summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2010-04-06 09:23:03 +0200
committerGeorg Brandl <georg@python.org>2010-04-06 09:23:03 +0200
commit5a1b937afaa5b8a4d93bc15f90d69d0e917d9056 (patch)
treed4b3d1b1f1fed3c1dd37029cf7fb4a485c765c5f
parent7f269d3edc077c5e3c3448049eccd393d79a8bdf (diff)
parented65cb87d83af26789f8646c700deec981315579 (diff)
downloadsphinx-5a1b937afaa5b8a4d93bc15f90d69d0e917d9056.tar.gz
merge with trunk
-rw-r--r--.hgignore19
-rw-r--r--CHANGES32
-rw-r--r--EXAMPLES1
-rw-r--r--Makefile2
-rw-r--r--doc/Makefile10
-rw-r--r--doc/_templates/index.html71
-rw-r--r--doc/_templates/layout.html3
-rw-r--r--doc/builders.rst34
-rw-r--r--doc/conf.py24
-rw-r--r--doc/config.rst132
-rw-r--r--doc/contents.rst4
-rw-r--r--doc/domains.rst548
-rw-r--r--doc/ext/appapi.rst110
-rw-r--r--doc/ext/autodoc.rst13
-rw-r--r--doc/ext/builderapi.rst1
-rw-r--r--doc/ext/tutorial.rst10
-rw-r--r--doc/ext/viewcode.rst19
-rw-r--r--doc/extensions.rst1
-rw-r--r--doc/faq.rst12
-rw-r--r--doc/glossary.rst54
-rw-r--r--doc/intro.rst125
-rw-r--r--doc/invocation.rst178
-rw-r--r--doc/man/sphinx-build.rst102
-rw-r--r--doc/man/sphinx-quickstart.rst33
-rw-r--r--doc/markup/desc.rst357
-rw-r--r--doc/markup/index.rst6
-rw-r--r--doc/markup/inline.rst243
-rw-r--r--doc/markup/misc.rst34
-rw-r--r--doc/markup/para.rst68
-rw-r--r--doc/markup/toctree.rst (renamed from doc/concepts.rst)32
-rw-r--r--doc/more.pngbin0 -> 1502 bytes
-rw-r--r--doc/rest.rst231
-rw-r--r--doc/sphinx-build.1105
-rw-r--r--doc/sphinx-quickstart.117
-rw-r--r--doc/templating.rst16
-rw-r--r--doc/theming.rst4
-rw-r--r--doc/tutorial.rst262
-rw-r--r--setup.cfg1
-rw-r--r--setup.py17
-rw-r--r--sphinx/__init__.py2
-rw-r--r--sphinx/addnodes.py5
-rw-r--r--sphinx/application.py179
-rw-r--r--sphinx/builders/__init__.py79
-rw-r--r--sphinx/builders/changes.py1
-rw-r--r--sphinx/builders/devhelp.py13
-rw-r--r--sphinx/builders/html.py163
-rw-r--r--sphinx/builders/htmlhelp.py7
-rw-r--r--sphinx/builders/latex.py1
-rw-r--r--sphinx/builders/manpage.py92
-rw-r--r--sphinx/builders/qthelp.py9
-rw-r--r--sphinx/cmdline.py13
-rw-r--r--sphinx/config.py15
-rw-r--r--sphinx/directives/__init__.py175
-rw-r--r--sphinx/directives/code.py13
-rw-r--r--sphinx/directives/desc.py771
-rw-r--r--sphinx/directives/other.py274
-rw-r--r--sphinx/domains/__init__.py250
-rw-r--r--sphinx/domains/c.py213
-rw-r--r--sphinx/domains/cpp.py1097
-rw-r--r--sphinx/domains/python.py621
-rw-r--r--sphinx/domains/std.py386
-rw-r--r--sphinx/environment.py516
-rw-r--r--sphinx/errors.py8
-rw-r--r--sphinx/ext/autodoc.py46
-rw-r--r--sphinx/ext/autosummary/__init__.py19
-rw-r--r--sphinx/ext/coverage.py14
-rw-r--r--sphinx/ext/inheritance_diagram.py14
-rw-r--r--sphinx/ext/intersphinx.py133
-rw-r--r--sphinx/ext/mathbase.py17
-rw-r--r--sphinx/ext/refcounting.py2
-rw-r--r--sphinx/ext/todo.py8
-rw-r--r--sphinx/ext/viewcode.py169
-rw-r--r--sphinx/jinja2glue.py7
-rw-r--r--sphinx/locale/__init__.py191
-rw-r--r--sphinx/locale/ca/LC_MESSAGES/sphinx.js1
-rw-r--r--sphinx/locale/ca/LC_MESSAGES/sphinx.mobin0 -> 8114 bytes
-rw-r--r--sphinx/locale/ca/LC_MESSAGES/sphinx.po606
-rw-r--r--sphinx/locale/sphinx.pot306
-rw-r--r--sphinx/pycode/__init__.py67
-rw-r--r--sphinx/pycode/pgen2/driver.py2
-rw-r--r--sphinx/pycode/pgen2/grammar.py2
-rw-r--r--sphinx/pycode/pgen2/pgen.py8
-rw-r--r--sphinx/quickstart.py82
-rw-r--r--sphinx/roles.py295
-rw-r--r--sphinx/search.py66
-rw-r--r--sphinx/texinputs/Makefile2
-rw-r--r--sphinx/texinputs/sphinx.sty313
-rw-r--r--sphinx/themes/agogo/static/agogo.css_t22
-rw-r--r--sphinx/themes/basic/domainindex.html57
-rw-r--r--sphinx/themes/basic/layout.html2
-rw-r--r--sphinx/themes/basic/modindex.html52
-rw-r--r--sphinx/themes/basic/static/basic.css16
-rw-r--r--sphinx/themes/basic/static/doctools.js23
-rw-r--r--sphinx/themes/basic/static/jquery.js177
-rw-r--r--sphinx/themes/basic/static/searchtools.js54
-rw-r--r--sphinx/themes/default/static/default.css_t10
-rw-r--r--sphinx/themes/epub/static/epub.css2
-rw-r--r--sphinx/themes/haiku/static/haiku.css_t12
-rw-r--r--sphinx/themes/nature/static/nature.css_t10
-rw-r--r--sphinx/themes/scrolls/static/scrolls.css_t17
-rw-r--r--sphinx/themes/sphinxdoc/static/sphinxdoc.css11
-rw-r--r--sphinx/themes/traditional/static/traditional.css17
-rw-r--r--sphinx/util/__init__.py33
-rw-r--r--sphinx/util/compat.py69
-rw-r--r--sphinx/util/docfields.py267
-rw-r--r--sphinx/util/nodes.py29
-rw-r--r--sphinx/util/texescape.py2
-rw-r--r--sphinx/writers/html.py30
-rw-r--r--sphinx/writers/latex.py370
-rw-r--r--sphinx/writers/manpage.py323
-rw-r--r--sphinx/writers/text.py13
-rw-r--r--tests/root/_templates/layout.html7
-rw-r--r--tests/root/conf.py26
-rw-r--r--tests/root/contents.txt3
-rw-r--r--tests/root/desc.txt71
-rw-r--r--tests/root/extapi.txt10
-rw-r--r--tests/root/markup.txt113
-rw-r--r--tests/root/objects.txt110
-rw-r--r--tests/test_autodoc.py73
-rw-r--r--tests/test_build.py98
-rw-r--r--tests/test_build_html.py90
-rw-r--r--tests/test_build_latex.py94
-rw-r--r--tests/test_config.py2
-rw-r--r--tests/test_coverage.py2
-rw-r--r--tests/test_cpp_domain.py55
-rw-r--r--tests/test_env.py20
-rw-r--r--tests/test_intersphinx.py112
-rw-r--r--tests/test_markup.py25
-rw-r--r--tests/test_metadata.py5
-rw-r--r--tests/test_quickstart.py6
-rw-r--r--tests/test_search.py4
-rw-r--r--tests/util.py5
-rwxr-xr-xutils/check_sources.py3
-rw-r--r--utils/pylintrc2
134 files changed, 8745 insertions, 4013 deletions
diff --git a/.hgignore b/.hgignore
index 7bd2ee92..95e208aa 100644
--- a/.hgignore
+++ b/.hgignore
@@ -1,13 +1,14 @@
.*\.pyc
.*\.egg
.*\.so
-build/
-dist/
-tests/.coverage
-sphinx/pycode/Grammar.*pickle
-Sphinx.egg-info/
-doc/_build/
-TAGS
-\.ropeproject/
-^env/
+.dir-locals.el
\.DS_Store$
+^build/
+^dist/
+^tests/.coverage
+^sphinx/pycode/Grammar.*pickle
+^Sphinx.egg-info/
+^doc/_build/
+^TAGS
+^\.ropeproject/
+^env/
diff --git a/CHANGES b/CHANGES
index 6f63ccc2..71c2a950 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,33 @@
Release 1.0 (in development)
============================
+* Support for domains has been added. A domain is a collection of
+ directives and roles that all describe objects belonging together,
+ e.g. elements of a programming language. Builtin domains are
+ provided for Python and C objects.
+
+* Support for docutils 0.4 has been removed.
+
+* Added a manual page builder.
+
+* Added support for source ordering of members in autodoc, with
+ ``autodoc_member_order = 'bysource'``.
+
+* In HTML output, inline roles now get a CSS class with their name,
+ allowing styles to customize their appearance. Domain-specific
+ roles get two classes, ``domain`` and ``domain-rolename``.
+
+* New more compact doc field syntax is now recognized:
+ ``:param type name: description``.
+
+* Added a "nitpicky" mode that emits warnings for all missing
+ references. It is activated by the ``-n`` command-line switch
+ or the ``nitpicky`` config value.
+
+* Added the ``viewcode`` extension.
+
+* Added ``html-collect-pages`` event.
+
* Sphinx now requires Jinja2 version 2.2 or greater.
* Added ``needs_sphinx`` config value and ``Sphinx.require_sphinx``
@@ -50,6 +77,11 @@ Release 1.0 (in development)
* Added new HTML theme ``scrolls``, created by Armin Ronacher.
+* The ``toctree()`` callable in templates now has a ``maxdepth``
+ keyword argument to control the depth of the generated tree.
+
+* Added Catalan translation, thanks to Pau Fernández.
+
* Added ``html_output_encoding`` config value.
* #200: Added ``Sphinx.add_stylesheet()``.
diff --git a/EXAMPLES b/EXAMPLES
index 4f800f48..0be237a5 100644
--- a/EXAMPLES
+++ b/EXAMPLES
@@ -113,6 +113,7 @@ Documentation using another builtin theme
Documentation using a custom theme/integrated in a site
-------------------------------------------------------
+* Blinker: http://discorporate.us/projects/Blinker/docs/
* Django: http://docs.djangoproject.com/
* GeoServer: http://docs.geoserver.org/
* Glashammer: http://glashammer.org/
diff --git a/Makefile b/Makefile
index b7716b59..90f7c3d4 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ all: clean-pyc check test
check:
@$(PYTHON) utils/check_sources.py -i build -i dist -i sphinx/style/jquery.js \
-i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py -i .ropeproject \
- -i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py .
+ -i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py -i env .
clean: clean-pyc clean-patchfiles
diff --git a/doc/Makefile b/doc/Makefile
index bfd5ca83..48a66ed1 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -9,9 +9,9 @@ PAPER =
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) \
- $(SPHINXOPTS) .
+ $(SPHINXOPTS) $(O) .
-.PHONY: help clean html dirhtml pickle htmlhelp qthelp latex changes linkcheck doctest
+.PHONY: help clean html dirhtml pickle htmlhelp qthelp latex changes linkcheck doctest man
help:
@echo "Please use \`make <target>' where <target> is one of"
@@ -21,6 +21,7 @@ help:
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " epub to make an epub file"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " man to make manual pages"
@echo " changes to make an overview over all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@@ -47,6 +48,11 @@ text:
@echo
@echo "Build finished."
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) _build/man
+ @echo
+ @echo "Build finished."
+
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
diff --git a/doc/_templates/index.html b/doc/_templates/index.html
index a68a6251..082a1f87 100644
--- a/doc/_templates/index.html
+++ b/doc/_templates/index.html
@@ -4,7 +4,7 @@
<h1>Welcome</h1>
<div class="quotebar">
- <p>What users say:</p>
+ <p><em>What users say:</em></p>
<p>&ldquo;Cheers for a great tool that actually makes programmers <b>want</b>
to write documentation!&rdquo;</p>
</div>
@@ -12,28 +12,30 @@
<p>
Sphinx is a tool that makes it easy to create intelligent and beautiful
documentation, written by Georg Brandl and licensed under the BSD license.</p>
- <p>It was originally created to translate <a href="http://docs.python.org/dev/">the
- new Python documentation</a>, and it has excellent support for the documentation
- of Python projects, but other documents can be written with it too. Of course,
- this site is also created from reStructuredText sources using Sphinx!
+ <p>It was originally created for <a href="http://docs.python.org/dev/">the
+ new Python documentation</a>, and it has excellent facilities for the
+ documentation of Python projects, but C/C++ is already supported as well,
+ and it is planned to add special support for other languages as well. Of
+ course, this site is also created from reStructuredText sources using
+ Sphinx!
</p>
<p>
- It is still under constant development, and the following features are
- already present, work fine and can be seen &#8220;in action&#8221; in the
- Python docs:
+ Sphinx is under constant development. The following features are present,
+ work fine and can be seen &#8220;in action&#8221; in the Python docs:
</p>
<ul>
- <li><b>Output formats:</b> HTML (including Windows HTML Help) and LaTeX, for
- printable PDF versions</li>
+ <li><b>Output formats:</b> HTML (including Windows HTML Help), LaTeX (for
+ printable PDF versions), manual pages, plain text</li>
<li><b>Extensive cross-references:</b> semantic markup and automatic links
- for functions, classes, glossary terms and similar pieces of information</li>
+ for functions, classes, citations, glossary terms and similar pieces of
+ information</li>
<li><b>Hierarchical structure:</b> easy definition of a document tree, with
- automatic links to siblings, parents and children</li>
+ automatic links to siblings, parents and children</li>
<li><b>Automatic indices:</b> general index as well as a module index</li>
<li><b>Code handling:</b> automatic highlighting using the <a
- href="http://pygments.org">Pygments</a> highlighter</li>
+ href="http://pygments.org">Pygments</a> highlighter</li>
<li><b>Extensions:</b> automatic testing of code snippets, inclusion of
- docstrings from Python modules, and more</li>
+ docstrings from Python modules (API docs), and more</li>
</ul>
<p>
Sphinx uses <a href="http://docutils.sf.net/rst.html">reStructuredText</a>
@@ -42,39 +44,40 @@
suite, the <a href="http://docutils.sf.net/">Docutils</a>.
</p>
- <h2>Examples</h2>
- <p>
- The <a href="http://docs.python.org/dev/">Python documentation</a> and
- this page are different examples of Sphinx in use.
- You can also download PDF versions of the Sphinx documentation:
- a <a href="http://sphinx.pocoo.org/sphinx.pdf">version</a> generated from
- the LaTeX Sphinx produces, and a
- <a href="http://sphinx.pocoo.org/sphinx-rst2pdf.pdf">version</a> generated by rst2pdf.
- </p>
- <p>
- For examples of how Sphinx source files look, use the &#8220;Show source&#8221;
- links on all pages of the documentation apart from this welcome page.
- </p>
- <p>Links to more documentation generated with Sphinx can be found on the
- <a href="{{ pathto("examples") }}">Projects using Sphinx</a> page.
- </p>
-
<h2>Documentation</h2>
<table class="contentstable" align="center" style="margin-left: 30px"><tr>
<td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("tutorial") }}">First steps with Sphinx</a><br/>
+ <span class="linkdescr">overview of basic tasks</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/>
<span class="linkdescr">for a complete overview</span></p>
+ </td><td width="50%">
<p class="biglink"><a class="biglink" href="{{ pathto("search") }}">Search page</a><br/>
<span class="linkdescr">search the documentation</span></p>
- </td><td width="50%">
<p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">General Index</a><br/>
<span class="linkdescr">all functions, classes, terms</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("modindex") }}">Module Index</a><br/>
- <span class="linkdescr">quick access to all documented modules</span></p>
</td></tr>
</table>
+ <p>
+ You can also download PDF versions of the Sphinx documentation:
+ a <a href="http://sphinx.pocoo.org/sphinx.pdf">version</a> generated from
+ the LaTeX Sphinx produces, and
+ a <a href="http://sphinx.pocoo.org/sphinx-rst2pdf.pdf">version</a> generated
+ by rst2pdf.
+ </p>
+
+ <h2>Examples</h2>
+ <p>Links to documentation generated with Sphinx can be found on the
+ <a href="{{ pathto("examples") }}">Projects using Sphinx</a> page.
+ </p>
+ <p>
+ For examples of how Sphinx source files look, use the &#8220;Show
+ source&#8221; links on all pages of the documentation apart from this
+ welcome page.
+ </p>
+
<p>You may also be interested in the very nice
<a href="http://matplotlib.sourceforge.net/sampledoc/">tutorial</a> on how to
create a customized documentation using Sphinx written by the matplotlib
diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html
index 60d217df..6e609e1a 100644
--- a/doc/_templates/layout.html
+++ b/doc/_templates/layout.html
@@ -12,7 +12,8 @@
{% block rootrellink %}
<li><a href="{{ pathto('index') }}">Sphinx home</a>&nbsp;|&nbsp;</li>
- <li><a href="{{ pathto('contents') }}">Documentation</a>&raquo;</li>
+ <li><a href="{{ pathto('contents') }}">Documentation</a>
+ &raquo;</li>
{% endblock %}
{% block header %}
diff --git a/doc/builders.rst b/doc/builders.rst
index 1fcc9da1..0eeb584c 100644
--- a/doc/builders.rst
+++ b/doc/builders.rst
@@ -59,11 +59,13 @@ The builder's "name" must be given to the **-b** command-line option of
.. class:: QtHelpBuilder
This builder produces the same output as the standalone HTML builder, but
- also generates Qt help collection support files that allow
+ also generates `Qt help`_ collection support files that allow
the Qt collection generator to compile them.
Its name is ``qthelp``.
+ .. _Qt help: http://doc.trolltech.com/4.6/qthelp-framework.html
+
.. module:: sphinx.builders.devhelp
.. class:: DevhelpBuilder
@@ -126,6 +128,22 @@ Note that a direct PDF builder using ReportLab is available in `rst2pdf
.. versionadded:: 0.4
+.. module:: sphinx.builders.manpage
+.. class:: ManualPageBuilder
+
+ This builder produces manual pages in the groff format. You have to specify
+ which documents are to be included in which manual pages via the
+ :confval:`man_pages` configuration value.
+
+ Its name is ``man``.
+
+ .. note::
+
+ This builder requires the docutils manual page writer, which is only
+ available as of docutils 0.6.
+
+ .. versionadded:: 1.0
+
.. currentmodule:: sphinx.builders.html
.. class:: SerializingHTMLBuilder
@@ -133,7 +151,7 @@ Note that a direct PDF builder using ReportLab is available in `rst2pdf
(`pickle`, `simplejson`, `phpserialize`, and others) to dump the generated
HTML documentation. The pickle builder is a subclass of it.
- A concreate subclass of this builder serializing to the `PHP serialization`_
+ A concrete subclass of this builder serializing to the `PHP serialization`_
format could look like this::
import phpserialize
@@ -278,8 +296,8 @@ The special files are located in the root output directory. They are:
``project``, ``copyright``, ``release``, ``version``
The same values as given in the configuration file.
- ``style``, ``use_modindex``
- :confval:`html_style` and :confval:`html_use_modindex`, respectively.
+ ``style``
+ :confval:`html_style`.
``last_updated``
Date of last build.
@@ -304,7 +322,9 @@ The special files are located in the root output directory. They are:
``environment.pickle``
The build environment. This is always a pickle file, independent of the
builder and a copy of the environment that was used when the builder was
- started. (XXX: document common members)
+ started.
+
+ .. todo:: Document common members.
- Unlike the other pickle files this pickle file requires that the sphinx
- module is available on unpickling.
+ Unlike the other pickle files this pickle file requires that the ``sphinx``
+ package is available on unpickling.
diff --git a/doc/conf.py b/doc/conf.py
index cff9af6e..98dc6565 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -6,7 +6,7 @@ import re
import sphinx
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
- 'sphinx.ext.autosummary']
+ 'sphinx.ext.autosummary', 'sphinx.ext.extlinks']
master_doc = 'contents'
templates_path = ['_templates']
@@ -16,7 +16,6 @@ project = 'Sphinx'
copyright = '2007-2010, Georg Brandl'
version = sphinx.__released__
release = version
-
show_authors = True
html_theme = 'sphinxdoc'
@@ -47,14 +46,30 @@ latex_elements = {
'fontpkg': '\\usepackage{palatino}',
}
+autodoc_member_order = 'groupwise'
todo_include_todos = True
+extlinks = {'rstref': ('http://docutils.sourceforge.net/docs/ref/rst/'
+ 'restructuredtext.html#%s', ''),
+ 'rstrole': ('http://docutils.sourceforge.net/docs/ref/rst/'
+ 'roles.html#%s', ''),
+ 'rstdir': ('http://docutils.sourceforge.net/docs/ref/rst/'
+ 'directives.html#%s', '')}
+
+man_pages = [
+ ('contents', 'sphinx-all', 'Sphinx documentation generator system manual',
+ 'Georg Brandl', 1),
+ ('man/sphinx-build', 'sphinx-build', 'Sphinx documentation generator tool',
+ '', 1),
+ ('man/sphinx-quickstart', 'sphinx-quickstart', 'Sphinx documentation '
+ 'template generator', '', 1),
+]
# -- Extension interface -------------------------------------------------------
from sphinx import addnodes
-dir_sig_re = re.compile(r'\.\. ([^:]+)::(.*)$')
+dir_sig_re = re.compile(r'\.\. (.+?)::(.*)$')
def parse_directive(env, sig, signode):
if not sig.startswith('.'):
@@ -101,5 +116,6 @@ def setup(app):
parse_directive)
app.add_description_unit('role', 'role', 'pair: %s; role', parse_role)
app.add_description_unit('confval', 'confval',
- 'pair: %s; configuration value')
+ objname='configuration value',
+ indextemplate='pair: %s; configuration value')
app.add_description_unit('event', 'event', 'pair: %s; event', parse_event)
diff --git a/doc/config.rst b/doc/config.rst
index 6d0563e0..611b7476 100644
--- a/doc/config.rst
+++ b/doc/config.rst
@@ -1,5 +1,7 @@
.. highlightlang:: python
+.. _build-config:
+
The build configuration file
============================
@@ -147,9 +149,9 @@ General configuration
Directories in which to search for additional Sphinx message catalogs (see
:confval:`language`), relative to the source directory. The directories on
- this path are searched by the standard :mod:`gettext` module for a domain of
- ``sphinx``; so if you add the directory :file:`./locale` to this settting,
- the message catalogs must be in
+ this path are searched by the standard :mod:`gettext` module for a text
+ domain of ``sphinx``; so if you add the directory :file:`./locale` to this
+ settting, the message catalogs must be in
:file:`./locale/{language}/LC_MESSAGES/sphinx.mo`.
The default is ``[]``.
@@ -182,14 +184,23 @@ General configuration
.. versionadded:: 0.6
+.. confval:: default_domain
+
+ .. index:: default; domain
+
+ The name of the default :ref:`domain <domains>`. Can also be ``None`` to
+ disable a default domain. The default is ``'py'``.
+
+ .. versionadded:: 1.0
+
.. confval:: default_role
.. index:: default; role
The name of a reST role (builtin or Sphinx extension) to use as the default
role, that is, for text marked up ```like this```. This can be set to
- ``'obj'`` to make ```filter``` a cross-reference to the function "filter".
- The default is ``None``, which doesn't reassign the default role.
+ ``'py:obj'`` to make ```filter``` a cross-reference to the Python function
+ "filter". The default is ``None``, which doesn't reassign the default role.
The default role can always be set within individual documents using the
standard reST :dir:`default-role` directive.
@@ -206,28 +217,19 @@ General configuration
.. versionadded:: 0.5
-.. confval:: modindex_common_prefix
-
- A list of prefixes that are ignored for sorting the module index (e.g.,
- if this is set to ``['foo.']``, then ``foo.bar`` is shown under ``B``, not
- ``F``). This can be handy if you document a project that consists of a single
- package. Works only for the HTML builder currently. Default is ``[]``.
-
- .. versionadded:: 0.6
-
-.. confval:: trim_doctest_flags
+.. confval:: needs_sphinx
- If true, doctest flags (comments looking like ``# doctest: FLAG, ...``) at
- the ends of lines are removed for all code blocks showing interactive Python
- sessions (i.e. doctests). Default is true. See the extension
- :mod:`~sphinx.ext.doctest` for more possibilities of including doctests.
+ If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will
+ compare it with its version and refuse to build if it is too old. Default is
+ no requirement.
.. versionadded:: 1.0
-.. confval:: needs_sphinx
+.. confval:: nitpicky
- If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will
- compare it with its version and refuse to build if it is too old.
+ If true, Sphinx will warn about *all* references where the target cannot be
+ found. Default is ``False``. You can activate this mode temporarily using
+ the :option:`-n` command-line switch.
.. versionadded:: 1.0
@@ -268,6 +270,7 @@ Project information
Currently supported languages are:
+ * ``ca`` -- Catalan
* ``cs`` -- Czech
* ``de`` -- German
* ``en`` -- English
@@ -324,14 +327,24 @@ Project information
.. confval:: add_module_names
A boolean that decides whether module names are prepended to all
- :term:`description unit` titles, e.g. for :dir:`function` directives.
- Default is ``True``.
+ :term:`object` names (for object types where a "module" of some kind is
+ defined), e.g. for :dir:`function` directives. Default is ``True``.
.. confval:: show_authors
A boolean that decides whether :dir:`moduleauthor` and :dir:`sectionauthor`
directives produce any output in the built files.
+.. confval:: modindex_common_prefix
+
+ A list of prefixes that are ignored for sorting the Python module index
+ (e.g., if this is set to ``['foo.']``, then ``foo.bar`` is shown under ``B``,
+ not ``F``). This can be handy if you document a project that consists of a
+ single package. Works only for the HTML builder currently. Default is
+ ``[]``.
+
+ .. versionadded:: 0.6
+
.. confval:: trim_footnote_reference_space
Trim spaces before footnote references that are necessary for the reST parser
@@ -339,6 +352,15 @@ Project information
.. versionadded:: 0.6
+.. confval:: trim_doctest_flags
+
+ If true, doctest flags (comments looking like ``# doctest: FLAG, ...``) at
+ the ends of lines are removed for all code blocks showing interactive Python
+ sessions (i.e. doctests). Default is true. See the extension
+ :mod:`~sphinx.ext.doctest` for more possibilities of including doctests.
+
+ .. versionadded:: 1.0
+
.. _html-options:
@@ -526,10 +548,25 @@ that use Sphinx' HTMLWriter class.
... old template content ...
{% endblock %}
+.. confval:: html_domain_indices
+
+ If true, generate domain-specific indices in addition to the general index.
+ For e.g. the Python domain, this is the global module index. Default is
+ ``True``.
+
+ This value can be a bool or a list of index names that should be generated.
+ To find out the index name for a specific index, look at the HTML file name.
+ For example, the Python module index has the name ``'py-modindex'``.
+
+ .. versionadded:: 1.0
+
.. confval:: html_use_modindex
If true, add a module index to the HTML documents. Default is ``True``.
+ .. deprecated:: 1.0
+ Use :confval:`html_domain_indices`.
+
.. confval:: html_use_index
If true, add an index to the HTML documents. Default is ``True``.
@@ -767,10 +804,24 @@ These options influence LaTeX output.
A list of document names to append as an appendix to all manuals.
+.. confval:: latex_domain_indices
+
+ If true, generate domain-specific indices in addition to the general index.
+ For e.g. the Python domain, this is the global module index. Default is
+ ``True``.
+
+ This value can be a bool or a list of index names that should be generated,
+ like for :confval:`html_domain_indices`.
+
+ .. versionadded:: 1.0
+
.. confval:: latex_use_modindex
If true, add a module index to LaTeX documents. Default is ``True``.
+ .. deprecated:: 1.0
+ Use :confval:`latex_domain_indices`.
+
.. confval:: latex_elements
.. versionadded:: 0.5
@@ -837,9 +888,7 @@ These options influence LaTeX output.
``'logo'``
``'releasename'``
``'makeindex'``
- ``'makemodindex'``
``'shorthandoff'``
- ``'printmodindex'``
.. confval:: latex_docclass
@@ -884,6 +933,37 @@ These options influence LaTeX output.
Use the ``'pointsize'`` key in the :confval:`latex_elements` value.
+.. _man-options:
+
+Options for manual page output
+------------------------------
+
+These options influence manual page output.
+
+.. confval:: man_pages
+
+ This value determines how to group the document tree into manual pages. It
+ must be a list of tuples ``(startdocname, name, description, authors,
+ section)``, where the items are:
+
+ * *startdocname*: document name that is the "root" of the manual page. All
+ documents referenced by it in TOC trees will be included in the manual file
+ too. (If you want one master manual page, use your :confval:`master_doc`
+ here.)
+ * *name*: name of the manual page. This should be a short string without
+ spaces or special characters. It is used to determine the file name as
+ well as the name of the manual page (in the NAME section).
+ * *description*: description of the manual page. This is used in the NAME
+ section.
+ * *authors*: A list of strings with authors, or a single string. Can be
+ an empty string or list if you do not want to automatically generate
+ an AUTHORS section in the manual page.
+ * *section*: The manual page section. Used for the output file name as well
+ as in the manual page header.
+
+ .. versionadded:: 1.0
+
+
.. rubric:: Footnotes
.. [1] A note on available globbing syntax: you can use the standard shell
diff --git a/doc/contents.rst b/doc/contents.rst
index 1f3860ea..079f93f2 100644
--- a/doc/contents.rst
+++ b/doc/contents.rst
@@ -7,9 +7,11 @@ Sphinx documentation contents
:maxdepth: 2
intro
- concepts
+ tutorial
+ invocation
rest
markup/index
+ domains
builders
config
theming
diff --git a/doc/domains.rst b/doc/domains.rst
new file mode 100644
index 00000000..b8922920
--- /dev/null
+++ b/doc/domains.rst
@@ -0,0 +1,548 @@
+.. highlight:: rst
+
+.. _domains:
+
+Sphinx Domains
+==============
+
+.. versionadded:: 1.0
+
+What is a Domain?
+-----------------
+
+Originally, Sphinx was conceived for a single project, the documentation of the
+Python language. Shortly afterwards, it was made available for everyone as a
+documentation tool, but the documentation of Python modules remained deeply
+built in -- the most fundamental directives, like ``function``, were designed
+for Python objects. Since Sphinx has become somewhat popular, interest
+developed in using it for many different purposes: C/C++ projects, JavaScript,
+or even reStructuredText markup (like in this documentation).
+
+While this was always possible, it is now much easier to easily support
+documentation of projects using different programming languages or even ones not
+supported by the main Sphinx distribution, by providing a **domain** for every
+such purpose.
+
+A domain is a collection of markup (reStructuredText :term:`directive`\ s and
+:term:`role`\ s) to describe and link to :term:`object`\ s belonging together,
+e.g. elements of a programming language. Directive and role names in a domain
+have names like ``domain:name``, e.g. ``py:function``. Domains can also provide
+custom indices (like the Python Module Index).
+
+Having domains means that there are no naming problems when one set of
+documentation wants to refer to e.g. C++ and Python classes. It also means that
+extensions that support the documentation of whole new languages are much easier
+to write.
+
+This section describes what the domains that come with Sphinx provide. The
+domain API is documented as well, in the section :ref:`domain-api`.
+
+
+.. _basic-domain-markup:
+
+Basic Markup
+------------
+
+Most domains provide a number of :dfn:`object description directives`, used to
+describe specific objects provided by modules. Each directive requires one or
+more signatures to provide basic information about what is being described, and
+the content should be the description. The basic version makes entries in the
+general index; if no index entry is desired, you can give the directive option
+flag ``:noindex:``. An example using a Python domain directive::
+
+ .. py:function:: spam(eggs)
+ ham(eggs)
+ :noindex:
+
+ Spam or ham the foo.
+
+The domains also provide roles that link back to these object descriptions. For
+example, to link to one of the functions described in the example above, you
+could say ::
+
+ The function :py:func:`spam` does a similar thing.
+
+As you can see, both directive and role names contain the domain name and the
+directive name.
+
+.. rubric:: Default Domain
+
+To avoid having to writing the domain name all the time when you e.g. only
+describe Python objects, a default domain can be selected with either the config
+value :confval:`default_domain` or this directive:
+
+.. directive:: .. default-domain:: name
+
+ Select a new default domain. While the :confval:`default_domain` selects a
+ global default, this only has an effect within the same file.
+
+If no other default is selected, the Python domain (named ``py``) is the default
+one, mostly for compatibility with documentation written for older versions of
+Sphinx.
+
+Directives and roles that belong to the default domain can be mentioned without
+giving the domain name, i.e. ::
+
+ .. function:: pyfunc()
+
+ Describes a Python function.
+
+ Reference to :func:`pyfunc`.
+
+
+Cross-referencing syntax
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+For cross-reference roles provided by domains, the same facilities exist as for
+general cross-references. See :ref:`xref-syntax`.
+
+In short:
+
+* You may supply an explicit title and reference target: ``:role:`title
+ <target>``` will refer to *target*, but the link text will be *title*.
+
+* If you prefix the content with ``!``, no reference/hyperlink will be created.
+
+* If you prefix the content with ``~``, the link text will only be the last
+ component of the target. For example, ``:py:meth:`~Queue.Queue.get``` will
+ refer to ``Queue.Queue.get`` but only display ``get`` as the link text.
+
+
+The Python Domain
+-----------------
+
+The Python domain (name **py**) provides the following directives for module
+declarations:
+
+.. directive:: .. py:module:: name
+
+ This directive marks the beginning of the description of a module (or package
+ submodule, in which case the name should be fully qualified, including the
+ package name). It does not create content (like e.g. :dir:`py:class` does).
+
+ This directive will also cause an entry in the global module index.
+
+ The ``platform`` option, if present, is a comma-separated list of the
+ platforms on which the module is available (if it is available on all
+ platforms, the option should be omitted). The keys are short identifiers;
+ examples that are in use include "IRIX", "Mac", "Windows", and "Unix". It is
+ important to use a key which has already been used when applicable.
+
+ The ``synopsis`` option should consist of one sentence describing the
+ module's purpose -- it is currently only used in the Global Module Index.
+
+ The ``deprecated`` option can be given (with no value) to mark a module as
+ deprecated; it will be designated as such in various locations then.
+
+
+.. directive:: .. py:currentmodule:: name
+
+ This directive tells Sphinx that the classes, functions etc. documented from
+ here are in the given module (like :dir:`py:module`), but it will not create
+ index entries, an entry in the Global Module Index, or a link target for
+ :role:`mod`. This is helpful in situations where documentation for things in
+ a module is spread over multiple files or sections -- one location has the
+ :dir:`py:module` directive, the others only :dir:`py:currentmodule`.
+
+
+The following directives are provided for module and class contents:
+
+.. directive:: .. py:data:: name
+
+ Describes global data in a module, including both variables and values used
+ as "defined constants." Class and object attributes are not documented
+ using this environment.
+
+.. directive:: .. py:exception:: name
+
+ Describes an exception class. The signature can, but need not include
+ parentheses with constructor arguments.
+
+.. directive:: .. py:function:: name(signature)
+
+ Describes a module-level function. The signature should include the
+ parameters, enclosing optional parameters in brackets. Default values can be
+ given if it enhances clarity; see :ref:`signatures`. For example::
+
+ .. py:function:: Timer.repeat([repeat=3[, number=1000000]])
+
+ Object methods are not documented using this directive. Bound object methods
+ placed in the module namespace as part of the public interface of the module
+ are documented using this, as they are equivalent to normal functions for
+ most purposes.
+
+ The description should include information about the parameters required and
+ how they are used (especially whether mutable objects passed as parameters
+ are modified), side effects, and possible exceptions. A small example may be
+ provided.
+
+.. directive:: .. py:class:: name[(signature)]
+
+ Describes a class. The signature can include parentheses with parameters
+ which will be shown as the constructor arguments. See also
+ :ref:`signatures`.
+
+ Methods and attributes belonging to the class should be placed in this
+ directive's body. If they are placed outside, the supplied name should
+ contain the class name so that cross-references still work. Example::
+
+ .. py:class:: Foo
+ .. py:method:: quux()
+
+ -- or --
+
+ .. py:class:: Bar
+
+ .. py:method:: Bar.quux()
+
+ The first way is the preferred one.
+
+.. directive:: .. py:attribute:: name
+
+ Describes an object data attribute. The description should include
+ information about the type of the data to be expected and whether it may be
+ changed directly.
+
+.. directive:: .. py:method:: name(signature)
+
+ Describes an object method. The parameters should not include the ``self``
+ parameter. The description should include similar information to that
+ described for ``function``. See also :ref:`signatures`.
+
+.. directive:: .. py:staticmethod:: name(signature)
+
+ Like :dir:`py:method`, but indicates that the method is a static method.
+
+ .. versionadded:: 0.4
+
+.. directive:: .. py:classmethod:: name(signature)
+
+ Like :dir:`py:method`, but indicates that the method is a class method.
+
+ .. versionadded:: 0.6
+
+
+.. _signatures:
+
+Python Signatures
+~~~~~~~~~~~~~~~~~
+
+Signatures of functions, methods and class constructors can be given like they
+would be written in Python, with the exception that optional parameters can be
+indicated by brackets::
+
+ .. py:function:: compile(source[, filename[, symbol]])
+
+It is customary to put the opening bracket before the comma. In addition to
+this "nested" bracket style, a "flat" style can also be used, due to the fact
+that most optional parameters can be given independently::
+
+ .. py:function:: compile(source[, filename, symbol])
+
+Default values for optional arguments can be given (but if they contain commas,
+they will confuse the signature parser). Python 3-style argument annotations
+can also be given as well as return type annotations::
+
+ .. py:function:: compile(source : string[, filename, symbol]) -> ast object
+
+
+Info field lists
+~~~~~~~~~~~~~~~~
+
+.. versionadded:: 0.4
+
+Inside Python object description directives, reST field lists with these fields
+are recognized and formatted nicely:
+
+* ``param``, ``parameter``, ``arg``, ``argument``, ``key``, ``keyword``:
+ Description of a parameter.
+* ``type``: Type of a parameter.
+* ``raises``, ``raise``, ``except``, ``exception``: That (and when) a specific
+ exception is raised.
+* ``var``, ``ivar``, ``cvar``: Description of a variable.
+* ``returns``, ``return``: Description of the return value.
+* ``rtype``: Return type.
+
+The field names must consist of one of these keywords and an argument (except
+for ``returns`` and ``rtype``, which do not need an argument). This is best
+explained by an example::
+
+ .. py:function:: format_exception(etype, value, tb[, limit=None])
+
+ Format the exception with a traceback.
+
+ :param etype: exception type
+ :param value: exception value
+ :param tb: traceback object
+ :param limit: maximum number of stack frames to show
+ :type limit: integer or None
+ :rtype: list of strings
+
+It is also possible to combine parameter type and description, if the type is a
+single word, like this::
+
+ :param integer limit: maximum number of stack frames to show
+
+This will render like this:
+
+ .. py:function:: format_exception(etype, value, tb[, limit=None])
+ :noindex:
+
+ Format the exception with a traceback.
+
+ :param etype: exception type
+ :param value: exception value
+ :param tb: traceback object
+ :param limit: maximum number of stack frames to show
+ :type limit: integer or None
+ :rtype: list of strings
+
+
+Cross-referencing Python objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following roles refer to objects in modules and are possibly hyperlinked if
+a matching identifier is found:
+
+.. role:: py:mod
+
+ Reference a module; a dotted name may be used. This should also be used for
+ package names.
+
+.. role:: py:func
+
+ Reference a Python function; dotted names may be used. The role text needs
+ not include trailing parentheses to enhance readability; they will be added
+ automatically by Sphinx if the :confval:`add_function_parentheses` config
+ value is true (the default).
+
+.. role:: py:data
+
+ Reference a module-level variable.
+
+.. role:: py:const
+
+ Reference a "defined" constant. This may be a C-language ``#define`` or a
+ Python variable that is not intended to be changed.
+
+.. role:: py:class
+
+ Reference a class; a dotted name may be used.
+
+.. role:: py:meth
+
+ Reference a method of an object. The role text can include the type name and
+ the method name; if it occurs within the description of a type, the type name
+ can be omitted. A dotted name may be used.
+
+.. role:: py:attr
+
+ Reference a data attribute of an object.
+
+.. role:: py:exc
+
+ Reference an exception. A dotted name may be used.
+
+.. role:: py:obj
+
+ Reference an object of unspecified type. Useful e.g. as the
+ :confval:`default_role`.
+
+ .. versionadded:: 0.4
+
+The name enclosed in this markup can include a module name and/or a class name.
+For example, ``:py:func:`filter``` could refer to a function named ``filter`` in
+the current module, or the built-in function of that name. In contrast,
+``:py:func:`foo.filter``` clearly refers to the ``filter`` function in the
+``foo`` module.
+
+Normally, names in these roles are searched first without any further
+qualification, then with the current module name prepended, then with the
+current module and class name (if any) prepended. If you prefix the name with a
+dot, this order is reversed. For example, in the documentation of Python's
+:mod:`codecs` module, ``:py:func:`open``` always refers to the built-in
+function, while ``:py:func:`.open``` refers to :func:`codecs.open`.
+
+A similar heuristic is used to determine whether the name is an attribute of the
+currently documented class.
+
+
+The C Domain
+------------
+
+The C domain (name **c**) is suited for documentation of C API.
+
+.. directive:: .. c:function:: type name(signature)
+
+ Describes a C function. The signature should be given as in C, e.g.::
+
+ .. c:function:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
+
+ This is also used to describe function-like preprocessor macros. The names
+ of the arguments should be given so they may be used in the description.
+
+ Note that you don't have to backslash-escape asterisks in the signature, as
+ it is not parsed by the reST inliner.
+
+.. directive:: .. c:member:: type name
+
+ Describes a C struct member. Example signature::
+
+ .. c:member:: PyObject* PyTypeObject.tp_bases
+
+ The text of the description should include the range of values allowed, how
+ the value should be interpreted, and whether the value can be changed.
+ References to structure members in text should use the ``member`` role.
+
+.. directive:: .. c:macro:: name
+
+ Describes a "simple" C macro. Simple macros are macros which are used for
+ code expansion, but which do not take arguments so cannot be described as
+ functions. This is not to be used for simple constant definitions. Examples
+ of its use in the Python documentation include :c:macro:`PyObject_HEAD` and
+ :c:macro:`Py_BEGIN_ALLOW_THREADS`.
+
+.. directive:: .. c:type:: name
+
+ Describes a C type (whether defined by a typedef or struct). The signature
+ should just be the type name.
+
+.. directive:: .. c:var:: type name
+
+ Describes a global C variable. The signature should include the type, such
+ as::
+
+ .. c:var:: PyObject* PyClass_Type
+
+
+Cross-referencing C constructs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following roles create cross-references to C-language constructs if they are
+defined in the documentation:
+
+.. role:: c:data
+
+ Reference a C-language variable.
+
+.. role:: c:func
+
+ Reference a C-language function. Should include trailing parentheses.
+
+.. role:: c:macro
+
+ Reference a "simple" C macro, as defined above.
+
+.. role:: c:type
+
+ Reference a C-language type.
+
+
+The C++ Domain
+--------------
+
+The C++ domain (name **cpp**) supports documenting C++ projects.
+
+The following directives are available:
+
+.. directive:: .. cpp:class:: signatures
+ .. cpp:function:: signatures
+ .. cpp:member:: signatures
+ .. cpp:type:: signatures
+
+ Describe a C++ object. Full signature specification is supported -- give the
+ signature as you would in the declaration. Example::
+
+ .. cpp:function:: const int IntArray::operator[]
+
+ Describes the indexing operator of IntArrays.
+
+.. directive:: .. cpp:namespace:: namespace
+
+ Select the current C++ namespace for the following objects.
+
+These roles link to the given object types:
+
+.. role:: cpp:class
+ cpp:func
+ cpp:member
+ cpp:type
+
+ Reference a C++ object. You can give the full signature (and need to, for
+ overloaded functions.)
+
+
+The Standard Domain
+-------------------
+
+The so-called "standard" domain collects all markup that doesn't warrant a
+domain of its own. Its directives and roles are not prefixed with a domain
+name.
+
+The standard domain is also where custom object descriptions, added using the
+:func:`~sphinx.application.Sphinx.add_object_type` API, are placed.
+
+There is a set of directives allowing documenting command-line programs:
+
+.. directive:: .. option:: name args, name args, ...
+
+ Describes a command line option or switch. Option argument names should be
+ enclosed in angle brackets. Example::
+
+ .. option:: -m <module>, --module <module>
+
+ Run a module as a script.
+
+ The directive will create a cross-reference target named after the *first*
+ option, referencable by :role:`option` (in the example case, you'd use
+ something like ``:option:`-m```).
+
+.. directive:: .. envvar:: name
+
+ Describes an environment variable that the documented code or program uses or
+ defines. Referencable by :role:`envvar`.
+
+.. directive:: .. program:: name
+
+ Like :dir:`py:currentmodule`, this directive produces no output. Instead, it
+ serves to notify Sphinx that all following :dir:`option` directives
+ document options for the program called *name*.
+
+ If you use :dir:`program`, you have to qualify the references in your
+ :role:`option` roles by the program name, so if you have the following
+ situation ::
+
+ .. program:: rm
+
+ .. option:: -r
+
+ Work recursively.
+
+ .. program:: svn
+
+ .. option:: -r revision
+
+ Specify the revision to work upon.
+
+ then ``:option:`rm -r``` would refer to the first option, while
+ ``:option:`svn -r``` would refer to the second one.
+
+ The program name may contain spaces (in case you want to document subcommands
+ like ``svn add`` and ``svn commit`` separately).
+
+ .. versionadded:: 0.5
+
+
+There is also a very generic object description directive, which is not tied to
+any domain:
+
+.. directive:: .. describe:: text
+ .. object:: text
+
+ This directive produces the same formatting as the specific ones provided by
+ domains, but does not create index entries or cross-referencing targets.
+ Example::
+
+ .. describe:: PAPER
+
+ You can set this variable to select a paper size.
diff --git a/doc/ext/appapi.rst b/doc/ext/appapi.rst
index 3a8cdb9d..cfdaaaa8 100644
--- a/doc/ext/appapi.rst
+++ b/doc/ext/appapi.rst
@@ -43,20 +43,42 @@ the following public API:
``'env'``) to a string. However, booleans are still accepted and
converted internally.
+.. method:: Sphinx.add_domain(domain)
+
+ Make the given *domain* (which must be a class; more precisely, a subclass of
+ :class:`~sphinx.domains.Domain`) known to Sphinx.
+
+ .. versionadded:: 1.0
+
+.. method:: Sphinx.override_domain(domain)
+
+ Make the given *domain* class known to Sphinx, assuming that there is already
+ a domain with its ``.name``. The new domain must be a subclass of the
+ existing one.
+
+ .. versionadded:: 1.0
+
+.. method:: Sphinx.add_index_to_domain(domain, index)
+
+ Add a custom *index* class to the domain named *domain*. *index* must be a
+ subclass of :class:`~sphinx.domains.Index`.
+
+ .. versionadded:: 1.0
+
.. method:: Sphinx.add_event(name)
- Register an event called *name*.
+ Register an event called *name*. This is needed to be able to emit it.
.. method:: Sphinx.add_node(node, **kwds)
Register a Docutils node class. This is necessary for Docutils internals.
It may also be used in the future to validate nodes in the parsed documents.
- Node visitor functions for the Sphinx HTML, LaTeX and text writers can be
- given as keyword arguments: the keyword must be one or more of ``'html'``,
- ``'latex'``, ``'text'``, the value a 2-tuple of ``(visit, depart)`` methods.
- ``depart`` can be ``None`` if the ``visit`` function raises
- :exc:`docutils.nodes.SkipNode`. Example:
+ Node visitor functions for the Sphinx HTML, LaTeX, text and manpage writers
+ can be given as keyword arguments: the keyword must be one or more of
+ ``'html'``, ``'latex'``, ``'text'``, ``'man'``, the value a 2-tuple of
+ ``(visit, depart)`` methods. ``depart`` can be ``None`` if the ``visit``
+ function raises :exc:`docutils.nodes.SkipNode`. Example:
.. code-block:: python
@@ -81,10 +103,10 @@ the following public API:
Register a Docutils directive. *name* must be the prospective directive
name. There are two possible ways to write a directive:
- * In the docutils 0.4 style, *func* is the directive function. *content*,
+ * In the docutils 0.4 style, *obj* is the directive function. *content*,
*arguments* and *options* are set as attributes on the function and
determine whether the directive has content, arguments and options,
- respectively.
+ respectively. **This style is deprecated.**
* In the docutils 0.5 style, *directiveclass* is the directive class. It
must already have attributes named *has_content*, *required_arguments*,
@@ -114,12 +136,26 @@ the following public API:
.. versionchanged:: 0.6
Docutils 0.5-style directive classes are now supported.
+.. method:: Sphinx.add_directive_to_domain(domain, name, func, content, arguments, **options)
+ Sphinx.add_directive_to_domain(domain, name, directiveclass)
+
+ Like :meth:`add_directive`, but the directive is added to the domain named
+ *domain*.
+
+ .. versionadded:: 1.0
+
.. method:: Sphinx.add_role(name, role)
Register a Docutils role. *name* must be the role name that occurs in the
source, *role* the role function (see the `Docutils documentation
<http://docutils.sourceforge.net/docs/howto/rst-roles.html>`_ on details).
+.. method:: Sphinx.add_role_to_domain(domain, name, role)
+
+ Like :meth:`add_role`, but the role is added to the domain named *domain*.
+
+ .. versionadded:: 1.0
+
.. method:: Sphinx.add_generic_role(name, nodeclass)
Register a Docutils role that does nothing but wrap its contents in the
@@ -127,26 +163,28 @@ the following public API:
.. versionadded:: 0.6
-.. method:: Sphinx.add_description_unit(directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None)
+.. method:: Sphinx.add_object_type(directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None, objname='')
- This method is a very convenient way to add a new type of information that
+ This method is a very convenient way to add a new :term:`object` type that
can be cross-referenced. It will do this:
- * Create a new directive (called *directivename*) for a :term:`description
- unit`. It will automatically add index entries if *indextemplate* is
- nonempty; if given, it must contain exactly one instance of ``%s``. See
- the example below for how the template will be interpreted.
+ * Create a new directive (called *directivename*) for documenting an object.
+ It will automatically add index entries if *indextemplate* is nonempty; if
+ given, it must contain exactly one instance of ``%s``. See the example
+ below for how the template will be interpreted.
* Create a new role (called *rolename*) to cross-reference to these
- description units.
+ object descriptions.
* If you provide *parse_node*, it must be a function that takes a string and
a docutils node, and it must populate the node with children parsed from
the string. It must then return the name of the item to be used in
cross-referencing and index entries. See the :file:`conf.py` file in the
source for this documentation for an example.
+ * The *objname* (if not given, will default to *directivename*) names the
+ type of object. It is used when listing objects, e.g. in search results.
For example, if you have this call in a custom Sphinx extension::
- app.add_description_unit('directive', 'dir', 'pair: %s; directive')
+ app.add_object_type('directive', 'dir', 'pair: %s; directive')
you can use this markup in your documents::
@@ -168,12 +206,15 @@ the following public API:
``docutils.nodes.emphasis`` or ``docutils.nodes.strong`` -- you can also use
``docutils.nodes.generated`` if you want no further text decoration).
- For the role content, you have the same options as for standard Sphinx roles
- (see :ref:`xref-syntax`).
+ For the role content, you have the same syntactical possibilities as for
+ standard Sphinx roles (see :ref:`xref-syntax`).
-.. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None)
+ This method is also available under the deprecated alias
+ :meth:`add_description_unit`.
- This method is very similar to :meth:`add_description_unit` except that the
+.. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None, objname='')
+
+ This method is very similar to :meth:`add_object_type` except that the
directive it generates must be empty, and will produce no output.
That means that you can add semantic targets to your sources, and refer to
@@ -264,8 +305,7 @@ the following public API:
.. method:: Sphinx.emit_firstresult(event, *arguments)
Emit *event* and pass *arguments* to the callback functions. Return the
- result of the first callback that doesn't return ``None`` (and don't call
- the rest of the callbacks).
+ result of the first callback that doesn't return ``None``.
.. versionadded:: 0.5
@@ -363,7 +403,15 @@ registered event handlers.
.. versionadded:: 0.5
-.. event:: page-context (app, pagename, templatename, context, doctree)
+.. event:: html-collect-pages (app)
+
+ Emitted when the HTML builder is starting to write non-document pages. You
+ can add pages to write by returning an iterable from this event consisting of
+ ``(pagename, context, templatename)``.
+
+ .. versionadded:: 1.0
+
+.. event:: html-page-context (app, pagename, templatename, context, doctree)
Emitted when the HTML builder has created a context dictionary to render a
template with -- this can be used to add custom elements to the context.
@@ -402,3 +450,19 @@ The template bridge
.. autoclass:: TemplateBridge
:members:
+
+
+.. _domain-api:
+
+Domain API
+----------
+
+.. module:: sphinx.domains
+
+.. autoclass:: Domain
+ :members:
+
+.. autoclass:: ObjType
+
+.. autoclass:: Index
+ :members:
diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst
index 4098d711..7e280b34 100644
--- a/doc/ext/autodoc.rst
+++ b/doc/ext/autodoc.rst
@@ -89,6 +89,9 @@ directive.
.. autoclass:: Noodle
:members: eat, slurp
+ * If you want to make the ``members`` option the default, see
+ :confval:`autodoc_default_flags`.
+
* Members without docstrings will be left out, unless you give the
``undoc-members`` flag option::
@@ -223,10 +226,16 @@ There are also new config values that you can set:
.. confval:: autodoc_member_order
This value selects if automatically documented members are sorted
- alphabetical (value ``'alphabetical'``) or by member type (value
- ``'groupwise'``). The default is alphabetical.
+ alphabetical (value ``'alphabetical'``), by member type (value
+ ``'groupwise'``) or by source order (value ``'bysource'``). The default is
+ alphabetical.
+
+ Note that for source order, the module must be a Python module with the
+ source code available.
.. versionadded:: 0.6
+ .. versionchanged:: 1.0
+ Support for ``'bysource'``.
.. confval:: autodoc_default_flags
diff --git a/doc/ext/builderapi.rst b/doc/ext/builderapi.rst
index bb11bfe2..3ace2687 100644
--- a/doc/ext/builderapi.rst
+++ b/doc/ext/builderapi.rst
@@ -13,7 +13,6 @@ Writing new builders
These methods are predefined and will be called from the application:
- .. automethod:: load_env
.. automethod:: get_relative_uri
.. automethod:: build_all
.. automethod:: build_specific
diff --git a/doc/ext/tutorial.rst b/doc/ext/tutorial.rst
index c44748d2..43d12ccb 100644
--- a/doc/ext/tutorial.rst
+++ b/doc/ext/tutorial.rst
@@ -201,8 +201,7 @@ The ``todo`` directive function looks like this::
def run(self):
env = self.state.document.settings.env
- targetid = "todo-%s" % env.index_num
- env.index_num += 1
+ targetid = "todo-%s" % env.new_serialno('todo')
targetnode = nodes.target('', '', ids=[targetid])
ad = make_admonition(todo, self.name, [_('Todo')], self.options,
@@ -225,9 +224,10 @@ to the build environment instance using ``self.state.document.settings.env``.
Then, to act as a link target (from the todolist), the todo directive needs to
return a target node in addition to the todo node. The target ID (in HTML, this
-will be the anchor name) is generated by using ``env.index_num`` which is
-persistent between directive calls and therefore leads to unique target names.
-The target node is instantiated without any text (the first two arguments).
+will be the anchor name) is generated by using ``env.new_serialno`` which is
+returns a new integer directive on each call and therefore leads to unique
+target names. The target node is instantiated without any text (the first two
+arguments).
An admonition is created using a standard docutils function (wrapped in Sphinx
for docutils cross-version compatibility). The first argument gives the node
diff --git a/doc/ext/viewcode.rst b/doc/ext/viewcode.rst
new file mode 100644
index 00000000..ba6c8f86
--- /dev/null
+++ b/doc/ext/viewcode.rst
@@ -0,0 +1,19 @@
+:mod:`sphinx.ext.viewcode` -- Add links to highlighted source code
+==================================================================
+
+.. module:: sphinx.ext.viewcode
+ :synopsis: Add links to a highlighted version of the source code.
+.. moduleauthor:: Georg Brandl
+
+.. versionadded:: 1.0
+
+
+This extension looks at your Python object descriptions (``.. class::``,
+``.. function::`` etc.) and tries to find the source files where the objects are
+contained. When found, a separate HTML page will be output for each module with
+a highlighted version of the source code, and a link will be added to all object
+descriptions that leads to the source code of the described object. A link back
+from the source to the description will also be inserted.
+
+There are currently no configuration values for this extension; you just need to
+add ``'sphinx.ext.viewcode'`` to your :confval:`extensions` value for it to work.
diff --git a/doc/extensions.rst b/doc/extensions.rst
index 29c40ccd..38927520 100644
--- a/doc/extensions.rst
+++ b/doc/extensions.rst
@@ -52,6 +52,7 @@ These extensions are built in and can be activated by respective entries in the
ext/coverage
ext/todo
ext/extlinks
+ ext/viewcode
Third-party extensions
diff --git a/doc/faq.rst b/doc/faq.rst
index ac7a454b..1a993204 100644
--- a/doc/faq.rst
+++ b/doc/faq.rst
@@ -24,6 +24,10 @@ How do I...
... add global substitutions or includes?
Add them in the :confval:`rst_epilog` config value.
+... display the whole TOC tree in the sidebar?
+ Use the :data:`toctree` callable in a custom layout template, probably in the
+ ``sidebartoc`` block.
+
... write my own extension?
See the :ref:`extension tutorial <exttut>`.
@@ -33,6 +37,8 @@ How do I...
come through cleanly.
+.. _usingwith:
+
Using Sphinx with...
--------------------
@@ -48,6 +54,12 @@ SCons
Glenn Hutchings has written a SCons build script to build Sphinx
documentation; it is hosted here: http://bitbucket.org/zondo/sphinx-scons
+PyPI
+ Jannis Leidel wrote a `setuptools command
+ <http://pypi.python.org/pypi/Sphinx-PyPI-upload>`_ that automatically uploads
+ Sphinx documentation to the PyPI package documentation area at
+ http://packages.python.org/.
+
github pages
You can use `Michael Jones' sphinx-to-github tool
<http://github.com/michaeljones/sphinx-to-github/tree/master>`_ to prepare
diff --git a/doc/glossary.rst b/doc/glossary.rst
index 7ec787ff..aa71b2b8 100644
--- a/doc/glossary.rst
+++ b/doc/glossary.rst
@@ -19,10 +19,43 @@ Glossary
the :term:`source directory`, but can be set differently with the **-c**
command-line option.
- description unit
- The basic building block of Sphinx documentation. Every "description
- directive" (e.g. :dir:`function` or :dir:`describe`) creates such a unit;
- and most units can be cross-referenced to.
+ directive
+ A reStructuredText markup element that allows marking a block of content
+ with special meaning. Directives are supplied not only by docutils, but
+ Sphinx and custom extensions can add their own. The basic directive
+ syntax looks like this::
+
+ .. directivename:: argument ...
+ :option: value
+
+ Content of the directive.
+
+ See :ref:`directives` for more information.
+
+ document name
+ Since reST source files can have different extensions (some people like
+ ``.txt``, some like ``.rst`` -- the extension can be configured with
+ :confval:`source_suffix`) and different OSes have different path separators,
+ Sphinx abstracts them: :dfn:`document names` are always relative to the
+ :term:`source directory`, the extension is stripped, and path separators
+ are converted to slashes. All values, parameters and such referring to
+ "documents" expect such document names.
+
+ Examples for document names are ``index``, ``library/zipfile``, or
+ ``reference/datamodel/types``. Note that there is no leading or trailing
+ slash.
+
+ domain
+ A domain is a collection of markup (reStructuredText :term:`directive`\ s
+ and :term:`role`\ s) to describe and link to :term:`object`\ s belonging
+ together, e.g. elements of a programming language. Directive and role
+ names in a domain have names like ``domain:name``, e.g. ``py:function``.
+
+ Having domains means that there are no naming problems when one set of
+ documentation wants to refer to e.g. C++ and Python classes. It also
+ means that extensions that support the documentation of whole new
+ languages are much easier to write. For more information about domains,
+ see the chapter :ref:`domains`.
environment
A structure where information about all documents under the root is saved,
@@ -30,6 +63,19 @@ Glossary
parsing stage, so that successive runs only need to read and parse new and
changed documents.
+ master document
+ The document that contains the root :dir:`toctree` directive.
+
+ object
+ The basic building block of Sphinx documentation. Every "object
+ directive" (e.g. :dir:`function` or :dir:`object`) creates such a block;
+ and most objects can be cross-referenced to.
+
+ role
+ A reStructuredText markup element that allows marking a piece of text.
+ Like directives, roles are extensible. The basic syntax looks like this:
+ ``:rolename:`content```. See :ref:`inlinemarkup` for details.
+
source directory
The directory which, including its subdirectories, contains all source
files for one Sphinx project.
diff --git a/doc/intro.rst b/doc/intro.rst
index 773bc74e..600493c9 100644
--- a/doc/intro.rst
+++ b/doc/intro.rst
@@ -11,9 +11,9 @@ browsing and navigation. But from the same source, it can also generate a
LaTeX file that you can compile into a PDF version of the documents.
The focus is on hand-written documentation, rather than auto-generated API docs.
-Though there is limited support for that kind of docs as well (which is intended
-to be freely mixed with hand-written content), if you need pure API docs have a
-look at `Epydoc <http://epydoc.sf.net/>`_, which also understands reST.
+Though there is support for that kind of docs as well (which is intended to be
+freely mixed with hand-written content), if you need pure API docs have a look
+at `Epydoc <http://epydoc.sf.net/>`_, which also understands reST.
Conversion from other systems
@@ -35,6 +35,12 @@ to reStructuredText/Sphinx from other documentation systems.
markup; it is at `Google Code <http://code.google.com/p/db2rst/>`_.
+Use with other systems
+----------------------
+
+See the :ref:`pertinent section in the FAQ list <usingwith>`.
+
+
Prerequisites
-------------
@@ -47,113 +53,8 @@ or some (not broken) SVN trunk snapshot.
.. _Pygments: http://pygments.org
-Setting up the documentation sources
-------------------------------------
-
-The root directory of a documentation collection is called the :dfn:`source
-directory`. Normally, this directory also contains the Sphinx configuration
-file :file:`conf.py`, but that file can also live in another directory, the
-:dfn:`configuration directory`.
-
-.. versionadded:: 0.3
- Support for a different configuration directory.
-
-Sphinx comes with a script called :program:`sphinx-quickstart` that sets up a
-source directory and creates a default :file:`conf.py` from a few questions it
-asks you. Just run ::
-
- $ sphinx-quickstart
-
-and answer the questions.
-
-
-Running a build
----------------
-
-A build is started with the :program:`sphinx-build` script. It is called
-like this::
-
- $ sphinx-build -b latex sourcedir builddir
-
-where *sourcedir* is the :term:`source directory`, and *builddir* is the
-directory in which you want to place the built documentation (it must be an
-existing directory). The :option:`-b` option selects a builder; in this example
-Sphinx will build LaTeX files.
-
-The :program:`sphinx-build` script has several more options:
-
-**-a**
- If given, always write all output files. The default is to only write output
- files for new and changed source files. (This may not apply to all
- builders.)
-
-**-E**
- Don't use a saved :term:`environment` (the structure caching all
- cross-references), but rebuild it completely. The default is to only read
- and parse source files that are new or have changed since the last run.
-
-**-t** *tag*
- Define the tag *tag*. This is relevant for :dir:`only` directives that only
- include their content if this tag is set.
-
- .. versionadded:: 0.6
-
-**-d** *path*
- Since Sphinx has to read and parse all source files before it can write an
- output file, the parsed source files are cached as "doctree pickles".
- Normally, these files are put in a directory called :file:`.doctrees` under
- the build directory; with this option you can select a different cache
- directory (the doctrees can be shared between all builders).
-
-**-c** *path*
- Don't look for the :file:`conf.py` in the source directory, but use the given
- configuration directory instead. Note that various other files and paths
- given by configuration values are expected to be relative to the
- configuration directory, so they will have to be present at this location
- too.
-
- .. versionadded:: 0.3
-
-**-C**
- Don't look for a configuration file; only take options via the ``-D`` option.
-
- .. versionadded:: 0.5
-
-**-D** *setting=value*
- Override a configuration value set in the :file:`conf.py` file. The value
- must be a string or dictionary value. For the latter, supply the setting
- name and key like this: ``-D latex_elements.docclass=scrartcl``.
-
- .. versionchanged:: 0.6
- The value can now be a dictionary value.
-
-**-A** *name=value*
- Make the *name* assigned to *value* in the HTML templates.
-
-**-N**
- Do not do colored output. (On Windows, colored output is disabled in any
- case.)
-
-**-q**
- Do not output anything on standard output, only write warnings and errors to
- standard error.
-
-**-Q**
- Do not output anything on standard output, also suppress warnings. Only
- errors are written to standard error.
-
-**-w** *file*
- Write warnings (and errors) to the given file, in addition to standard error.
-
-**-W**
- Turn warnings into errors. This means that the build stops at the first
- warning and ``sphinx-build`` exits with exit status 1.
-
-**-P**
- (Useful for debugging only.) Run the Python debugger, :mod:`pdb`, if an
- unhandled exception occurs while building.
-
+Usage
+-----
-You can also give one or more filenames on the command line after the source and
-build directories. Sphinx will then try to build only these output files (and
-their dependencies).
+See :doc:`tutorial` for an introduction. It also contains links to more
+advanced sections in this manual for the topics it discusses.
diff --git a/doc/invocation.rst b/doc/invocation.rst
new file mode 100644
index 00000000..94b5db2e
--- /dev/null
+++ b/doc/invocation.rst
@@ -0,0 +1,178 @@
+.. _invocation:
+
+Invocation of sphinx-build
+==========================
+
+The :program:`sphinx-build` script builds a Sphinx documentation set. It is
+called like this::
+
+ $ sphinx-build [options] sourcedir builddir [filenames]
+
+where *sourcedir* is the :term:`source directory`, and *builddir* is the
+directory in which you want to place the built documentation. Most of the time,
+you don't need to specify any *filenames*.
+
+The :program:`sphinx-build` script has several options:
+
+.. option:: -b buildername
+
+ The most important option: it selects a builder. The most common builders
+ are:
+
+ **html**
+ Build HTML pages. This is the default builder.
+
+ **dirhtml**
+ Build HTML pages, but with a single directory per document. Makes for
+ prettier URLs (no ``.html``) if served from a webserver.
+
+ **singlehtml**
+ Build a single HTML with the whole content.
+
+ **htmlhelp**, **qthelp**, **devhelp**, **epub**
+ Build HTML files with additional information for building a documentation
+ collection in one of these formats.
+
+ **latex**
+ Build LaTeX sources that can be compiled to a PDF document using
+ :program:`pdflatex`.
+
+ **man**
+ Build manual pages in groff format for UNIX systems.
+
+ **text**
+ Build plain text files.
+
+ **doctest**
+ Run all doctests in the documentation, if the :mod:`~sphinx.ext.doctest`
+ extension is enabled.
+
+ **linkcheck**
+ Check the integrity of all external links.
+
+ See :ref:`builders` for a list of all builders shipped with Sphinx.
+ Extensions can add their own builders.
+
+.. option:: -a
+
+ If given, always write all output files. The default is to only write output
+ files for new and changed source files. (This may not apply to all
+ builders.)
+
+.. option:: -E
+
+ Don't use a saved :term:`environment` (the structure caching all
+ cross-references), but rebuild it completely. The default is to only read
+ and parse source files that are new or have changed since the last run.
+
+.. option:: -t tag
+
+ Define the tag *tag*. This is relevant for :dir:`only` directives that only
+ include their content if this tag is set.
+
+ .. versionadded:: 0.6
+
+.. option:: -d path
+
+ Since Sphinx has to read and parse all source files before it can write an
+ output file, the parsed source files are cached as "doctree pickles".
+ Normally, these files are put in a directory called :file:`.doctrees` under
+ the build directory; with this option you can select a different cache
+ directory (the doctrees can be shared between all builders).
+
+.. option:: -c path
+
+ Don't look for the :file:`conf.py` in the source directory, but use the given
+ configuration directory instead. Note that various other files and paths
+ given by configuration values are expected to be relative to the
+ configuration directory, so they will have to be present at this location
+ too.
+
+ .. versionadded:: 0.3
+
+.. option:: -C
+
+ Don't look for a configuration file; only take options via the ``-D`` option.
+
+ .. versionadded:: 0.5
+
+.. option:: -D setting=value
+
+ Override a configuration value set in the :file:`conf.py` file. The value
+ must be a string or dictionary value. For the latter, supply the setting
+ name and key like this: ``-D latex_elements.docclass=scrartcl``. For boolean
+ values, use ``0`` or ``1`` as the value.
+
+ .. versionchanged:: 0.6
+ The value can now be a dictionary value.
+
+.. option:: -A name=value
+
+ Make the *name* assigned to *value* in the HTML templates.
+
+ .. versionadded:: 0.5
+
+.. option:: -n
+
+ Run in nit-picky mode. Currently, this generates warnings for all missing
+ references.
+
+.. option:: -N
+
+ Do not emit colored output. (On Windows, colored output is disabled in any
+ case.)
+
+.. option:: -q
+
+ Do not output anything on standard output, only write warnings and errors to
+ standard error.
+
+.. option:: -Q
+
+ Do not output anything on standard output, also suppress warnings. Only
+ errors are written to standard error.
+
+.. option:: -w file
+
+ Write warnings (and errors) to the given file, in addition to standard error.
+
+.. option:: -W
+
+ Turn warnings into errors. This means that the build stops at the first
+ warning and ``sphinx-build`` exits with exit status 1.
+
+.. option:: -P
+
+ (Useful for debugging only.) Run the Python debugger, :mod:`pdb`, if an
+ unhandled exception occurs while building.
+
+
+You can also give one or more filenames on the command line after the source and
+build directories. Sphinx will then try to build only these output files (and
+their dependencies).
+
+
+Makefile options
+----------------
+
+The :file:`Makefile` and :file:`make.bat` files created by
+:program:`sphinx-quickstart` usually run :program:`sphinx-build` only with the
+:option:`-b` and :option:`-d` options. However, they support the following
+variables to customize behavior:
+
+.. describe:: PAPER
+
+ The value for :confval:`latex_paper_size`.
+
+.. describe:: SPHINXBUILD
+
+ The command to use instead of ``sphinx-build``.
+
+.. describe:: BUILDDIR
+
+ The build directory to use instead of the one chosen in
+ :program:`sphinx-quickstart`.
+
+.. describe:: SPHINXOPTS
+
+ Additional options for :program:`sphinx-build`.
diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst
new file mode 100644
index 00000000..30f824e8
--- /dev/null
+++ b/doc/man/sphinx-build.rst
@@ -0,0 +1,102 @@
+:orphan:
+
+sphinx-build manual page
+========================
+
+Synopsis
+--------
+
+**sphinx-build** [*options*] <*sourcedir*> <*outdir*> [*filenames* ...]
+
+
+Description
+-----------
+
+:program:`sphinx-build` generates documentation from the files in
+``<sourcedir>`` and places it in the ``<outdir>``.
+
+:program:`sphinx-build` looks for ``<sourcedir>/conf.py`` for the configuration
+settings. :manpage:`sphinx-quickstart(1)` may be used to generate template
+files, including ``conf.py``.
+
+:program:`sphinx-build` can create documentation in different formats. A format
+is selected by specifying the builder name on the command line; it defaults to
+HTML. Builders can also perform other tasks related to documentation
+processing.
+
+By default, everything that is outdated is built. Output only for selected
+files can be built by specifying individual filenames.
+
+List of available builders:
+
+html
+ HTML file generation. This is the default builder.
+
+htmlhelp
+ Generates files for CHM (compiled help files) generation.
+
+qthelp
+ Generates files for Qt help collection generation.
+
+devhelp
+ Generates files for the GNOME Devhelp help viewer.
+
+latex
+ Generates LaTeX output that can be compiled to a PDF document.
+
+man
+ Generates manual pages.
+
+text
+ Generates a plain-text version of the documentation.
+
+changes
+ Generates HTML files listing changed/added/deprecated items for
+ the current version of the documented project.
+
+linkcheck
+ Checks the integrity of all external links in the source.
+
+pickle / json
+ Generates serialized HTML files for use in web applications.
+
+
+Options
+-------
+
+-b <builder> Builder to use; defaults to html. See the full list
+ of builders above.
+-a Generate output for all files; without this option only
+ output for new and changed files is generated.
+-E Ignore cached files, forces to re-read all source files
+ from disk.
+-c <path> Locate the conf.py file in the specified path instead of
+ <sourcedir>.
+-C Specify that no conf.py file at all is to be used.
+ Configuration can only be set with the -D option.
+-D <setting=value> Override a setting from the configuration file.
+-d <path> Path to cached files; defaults to <outdir>/.doctrees.
+-A <name=value> Pass a value into the HTML templates (only for HTML builders).
+-n Run in nit-picky mode, warn about all missing references.
+-N Prevent colored output.
+-q Quiet operation, just print warnings and errors on stderr.
+-Q Very quiet operation, don't print anything except for errors.
+-w <file> Write warnings and errors into the given file, in addition
+ to stderr.
+-W Turn warnings into errors.
+-P Run Pdb on exception.
+
+
+See also
+--------
+
+:manpage:`sphinx-quickstart(1)`
+
+Author
+------
+
+Georg Brandl <georg@python.org>, Armin Ronacher <armin.ronacher@active-4.com> et
+al.
+
+This manual page was initially written by Mikhail Gusarov
+<dottedmag@dottedmag.net>, for the Debian project.
diff --git a/doc/man/sphinx-quickstart.rst b/doc/man/sphinx-quickstart.rst
new file mode 100644
index 00000000..17277261
--- /dev/null
+++ b/doc/man/sphinx-quickstart.rst
@@ -0,0 +1,33 @@
+:orphan:
+
+sphinx-quickstart manual page
+=============================
+
+Synopsis
+--------
+
+**sphinx-quickstart**
+
+
+Description
+-----------
+
+:program:`sphinx-quickstart` is an interactive tool that asks some questions
+about your project and then generates a complete documentation directory and
+sample Makefile to be used with :manpage:`sphinx-build(1)`.
+
+
+See also
+--------
+
+:manpage:`sphinx-build(1)`
+
+
+Author
+------
+
+Georg Brandl <georg@python.org>, Armin Ronacher <armin.ronacher@active-4.com> et
+al.
+
+This manual page was initially written by Mikhail Gusarov
+<dottedmag@dottedmag.net>, for the Debian project.
diff --git a/doc/markup/desc.rst b/doc/markup/desc.rst
deleted file mode 100644
index ec8ede37..00000000
--- a/doc/markup/desc.rst
+++ /dev/null
@@ -1,357 +0,0 @@
-.. highlight:: rest
-
-Module-specific markup
-----------------------
-
-The markup described in this section is used to provide information about a
-module being documented. Normally this markup appears after a title heading; a
-typical module section might start like this::
-
- :mod:`parrot` -- Dead parrot access
- ===================================
-
- .. module:: parrot
- :platform: Unix, Windows
- :synopsis: Analyze and reanimate dead parrots.
- .. moduleauthor:: Eric Cleese <eric@python.invalid>
- .. moduleauthor:: John Idle <john@python.invalid>
-
-
-The directives you can use for module declarations are:
-
-.. directive:: .. module:: name
-
- This directive marks the beginning of the description of a module (or package
- submodule, in which case the name should be fully qualified, including the
- package name). It does not create content (like e.g. :dir:`class` does).
-
- This directive will also cause an entry in the global module index.
-
- The ``platform`` option, if present, is a comma-separated list of the
- platforms on which the module is available (if it is available on all
- platforms, the option should be omitted). The keys are short identifiers;
- examples that are in use include "IRIX", "Mac", "Windows", and "Unix". It is
- important to use a key which has already been used when applicable.
-
- The ``synopsis`` option should consist of one sentence describing the
- module's purpose -- it is currently only used in the Global Module Index.
-
- The ``deprecated`` option can be given (with no value) to mark a module as
- deprecated; it will be designated as such in various locations then.
-
-
-.. directive:: .. currentmodule:: name
-
- This directive tells Sphinx that the classes, functions etc. documented from
- here are in the given module (like :dir:`module`), but it will not create
- index entries, an entry in the Global Module Index, or a link target for
- :role:`mod`. This is helpful in situations where documentation for things in
- a module is spread over multiple files or sections -- one location has the
- :dir:`module` directive, the others only :dir:`currentmodule`.
-
-
-.. directive:: .. moduleauthor:: name <email>
-
- The ``moduleauthor`` directive, which can appear multiple times, names the
- authors of the module code, just like ``sectionauthor`` names the author(s)
- of a piece of documentation. It too only produces output if the
- :confval:`show_authors` configuration value is True.
-
-
-.. note::
-
- It is important to make the section title of a module-describing file
- meaningful since that value will be inserted in the table-of-contents trees
- in overview files.
-
-
-.. _desc-units:
-
-Object description units
-------------------------
-
-There are a number of directives used to describe specific features provided by
-modules. Each directive requires one or more signatures to provide basic
-information about what is being described, and the content should be the
-description. The basic version makes entries in the general index; if no index
-entry is desired, you can give the directive option flag ``:noindex:``. The
-following example shows all of the features of this directive type::
-
- .. function:: spam(eggs)
- ham(eggs)
- :noindex:
-
- Spam or ham the foo.
-
-The signatures of object methods or data attributes should always include the
-type name (``.. method:: FileInput.input(...)``), even if it is obvious from the
-context which type they belong to; this is to enable consistent
-cross-references. If you describe methods belonging to an abstract protocol,
-such as "context managers", include a (pseudo-)type name too to make the
-index entries more informative.
-
-The directives are:
-
-.. directive:: .. cfunction:: type name(signature)
-
- Describes a C function. The signature should be given as in C, e.g.::
-
- .. cfunction:: PyObject* PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
-
- This is also used to describe function-like preprocessor macros. The names
- of the arguments should be given so they may be used in the description.
-
- Note that you don't have to backslash-escape asterisks in the signature,
- as it is not parsed by the reST inliner.
-
-.. directive:: .. cmember:: type name
-
- Describes a C struct member. Example signature::
-
- .. cmember:: PyObject* PyTypeObject.tp_bases
-
- The text of the description should include the range of values allowed, how
- the value should be interpreted, and whether the value can be changed.
- References to structure members in text should use the ``member`` role.
-
-.. directive:: .. cmacro:: name
-
- Describes a "simple" C macro. Simple macros are macros which are used
- for code expansion, but which do not take arguments so cannot be described as
- functions. This is not to be used for simple constant definitions. Examples
- of its use in the Python documentation include :cmacro:`PyObject_HEAD` and
- :cmacro:`Py_BEGIN_ALLOW_THREADS`.
-
-.. directive:: .. ctype:: name
-
- Describes a C type. The signature should just be the type name.
-
-.. directive:: .. cvar:: type name
-
- Describes a global C variable. The signature should include the type, such
- as::
-
- .. cvar:: PyObject* PyClass_Type
-
-.. directive:: .. data:: name
-
- Describes global data in a module, including both variables and values used
- as "defined constants." Class and object attributes are not documented
- using this environment.
-
-.. directive:: .. exception:: name
-
- Describes an exception class. The signature can, but need not include
- parentheses with constructor arguments.
-
-.. directive:: .. function:: name(signature)
-
- Describes a module-level function. The signature should include the
- parameters, enclosing optional parameters in brackets. Default values can be
- given if it enhances clarity; see :ref:`signatures`. For example::
-
- .. function:: Timer.repeat([repeat=3[, number=1000000]])
-
- Object methods are not documented using this directive. Bound object methods
- placed in the module namespace as part of the public interface of the module
- are documented using this, as they are equivalent to normal functions for
- most purposes.
-
- The description should include information about the parameters required and
- how they are used (especially whether mutable objects passed as parameters
- are modified), side effects, and possible exceptions. A small example may be
- provided.
-
-.. directive:: .. class:: name[(signature)]
-
- Describes a class. The signature can include parentheses with parameters
- which will be shown as the constructor arguments. See also
- :ref:`signatures`.
-
- Methods and attributes belonging to the class should be placed in this
- directive's body. If they are placed outside, the supplied name should
- contain the class name so that cross-references still work. Example::
-
- .. class:: Foo
- .. method:: quux()
-
- -- or --
-
- .. class:: Bar
-
- .. method:: Bar.quux()
-
- The first way is the preferred one.
-
- .. versionadded:: 0.4
- The standard reST directive ``class`` is now provided by Sphinx under
- the name ``cssclass``.
-
-.. directive:: .. attribute:: name
-
- Describes an object data attribute. The description should include
- information about the type of the data to be expected and whether it may be
- changed directly.
-
-.. directive:: .. method:: name(signature)
-
- Describes an object method. The parameters should not include the ``self``
- parameter. The description should include similar information to that
- described for ``function``. See also :ref:`signatures`.
-
-.. directive:: .. staticmethod:: name(signature)
-
- Like :dir:`method`, but indicates that the method is a static method.
-
- .. versionadded:: 0.4
-
-.. directive:: .. classmethod:: name(signature)
-
- Like :dir:`method`, but indicates that the method is a class method.
-
- .. versionadded:: 0.6
-
-
-.. _signatures:
-
-Signatures
-~~~~~~~~~~
-
-Signatures of functions, methods and class constructors can be given like they
-would be written in Python, with the exception that optional parameters can be
-indicated by brackets::
-
- .. function:: compile(source[, filename[, symbol]])
-
-It is customary to put the opening bracket before the comma. In addition to
-this "nested" bracket style, a "flat" style can also be used, due to the fact
-that most optional parameters can be given independently::
-
- .. function:: compile(source[, filename, symbol])
-
-Default values for optional arguments can be given (but if they contain commas,
-they will confuse the signature parser). Python 3-style argument annotations
-can also be given as well as return type annotations::
-
- .. function:: compile(source : string[, filename, symbol]) -> ast object
-
-
-Info field lists
-~~~~~~~~~~~~~~~~
-
-.. versionadded:: 0.4
-
-Inside description unit directives, reST field lists with these fields are
-recognized and formatted nicely:
-
-* ``param``, ``parameter``, ``arg``, ``argument``, ``key``, ``keyword``:
- Description of a parameter.
-* ``type``: Type of a parameter.
-* ``raises``, ``raise``, ``except``, ``exception``: That (and when) a specific
- exception is raised.
-* ``var``, ``ivar``, ``cvar``: Description of a variable.
-* ``returns``, ``return``: Description of the return value.
-* ``rtype``: Return type.
-
-The field names must consist of one of these keywords and an argument (except
-for ``returns`` and ``rtype``, which do not need an argument). This is best
-explained by an example::
-
- .. function:: format_exception(etype, value, tb[, limit=None])
-
- Format the exception with a traceback.
-
- :param etype: exception type
- :param value: exception value
- :param tb: traceback object
- :param limit: maximum number of stack frames to show
- :type limit: integer or None
- :rtype: list of strings
-
-This will render like this:
-
- .. function:: format_exception(etype, value, tb[, limit=None])
- :noindex:
-
- Format the exception with a traceback.
-
- :param etype: exception type
- :param value: exception value
- :param tb: traceback object
- :param limit: maximum number of stack frames to show
- :type limit: integer or None
- :rtype: list of strings
-
-
-Command-line program markup
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-There is a set of directives allowing documenting command-line programs:
-
-.. directive:: .. cmdoption:: name args, name args, ...
-
- Describes a command line option or switch. Option argument names should be
- enclosed in angle brackets. Example::
-
- .. cmdoption:: -m <module>, --module <module>
-
- Run a module as a script.
-
- The directive will create a cross-reference target named after the *first*
- option, referencable by :role:`option` (in the example case, you'd use
- something like ``:option:`-m```).
-
-.. directive:: .. envvar:: name
-
- Describes an environment variable that the documented code or program uses or
- defines.
-
-
-.. directive:: .. program:: name
-
- Like :dir:`currentmodule`, this directive produces no output. Instead, it
- serves to notify Sphinx that all following :dir:`cmdoption` directives
- document options for the program called *name*.
-
- If you use :dir:`program`, you have to qualify the references in your
- :role:`option` roles by the program name, so if you have the following
- situation ::
-
- .. program:: rm
-
- .. cmdoption:: -r
-
- Work recursively.
-
- .. program:: svn
-
- .. cmdoption:: -r revision
-
- Specify the revision to work upon.
-
- then ``:option:`rm -r``` would refer to the first option, while
- ``:option:`svn -r``` would refer to the second one.
-
- The program name may contain spaces (in case you want to document subcommands
- like ``svn add`` and ``svn commit`` separately).
-
- .. versionadded:: 0.5
-
-
-Custom description units
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-There is also a generic version of these directives:
-
-.. directive:: .. describe:: text
-
- This directive produces the same formatting as the specific ones explained
- above but does not create index entries or cross-referencing targets. It is
- used, for example, to describe the directives in this document. Example::
-
- .. describe:: opcode
-
- Describes a Python bytecode instruction.
-
-Extensions may add more directives like that, using the
-:func:`~sphinx.application.Sphinx.add_description_unit` method.
diff --git a/doc/markup/index.rst b/doc/markup/index.rst
index 1127fa73..9492456d 100644
--- a/doc/markup/index.rst
+++ b/doc/markup/index.rst
@@ -1,3 +1,5 @@
+.. _sphinxmarkup:
+
Sphinx Markup Constructs
========================
@@ -6,8 +8,10 @@ markup. This section contains the reference material for these facilities.
.. toctree::
- desc
+ toctree
para
code
inline
misc
+
+More markup is added by :ref:`domains`.
diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst
index 9b4b26e3..298c999c 100644
--- a/doc/markup/inline.rst
+++ b/doc/markup/inline.rst
@@ -1,5 +1,7 @@
.. highlight:: rest
+.. _inline-markup:
+
Inline markup
=============
@@ -12,11 +14,13 @@ They are written as ``:rolename:`content```.
free to use it for anything you like, e.g. variable names; use the
:confval:`default_role` config value to set it to a known role.
+See :ref:`domains` for roles added by domains.
+
.. _xref-syntax:
Cross-referencing syntax
-------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~
Cross-references are generated by many semantic interpreted text roles.
Basically, you only need to write ``:role:`target```, and a link will be created
@@ -32,195 +36,60 @@ more versatile:
* If you prefix the content with ``!``, no reference/hyperlink will be created.
-* For the Python object roles, if you prefix the content with ``~``, the link
- text will only be the last component of the target. For example,
- ``:meth:`~Queue.Queue.get``` will refer to ``Queue.Queue.get`` but only
- display ``get`` as the link text.
+* If you prefix the content with ``~``, the link text will only be the last
+ component of the target. For example, ``:py:meth:`~Queue.Queue.get``` will
+ refer to ``Queue.Queue.get`` but only display ``get`` as the link text.
In HTML output, the link's ``title`` attribute (that is e.g. shown as a
tool-tip on mouse-hover) will always be the full target name.
-Cross-referencing Python objects
---------------------------------
-
-The following roles refer to objects in modules and are possibly hyperlinked if
-a matching identifier is found:
-
-.. role:: mod
-
- The name of a module; a dotted name may be used. This should also be used for
- package names.
-
-.. role:: func
-
- The name of a Python function; dotted names may be used. The role text
- needs not include trailing parentheses to enhance readability; they will be
- added automatically by Sphinx if the :confval:`add_function_parentheses`
- config value is true (the default).
-
-.. role:: data
-
- The name of a module-level variable.
-
-.. role:: const
-
- The name of a "defined" constant. This may be a C-language ``#define``
- or a Python variable that is not intended to be changed.
-
-.. role:: class
-
- A class name; a dotted name may be used.
-
-.. role:: meth
-
- The name of a method of an object. The role text should include the type
- name and the method name; if it occurs within the description of a type,
- the type name can be omitted. A dotted name may be used.
-
-.. role:: attr
-
- The name of a data attribute of an object.
-
-.. role:: exc
-
- The name of an exception. A dotted name may be used.
-
-.. role:: obj
-
- The name of an object of unspecified type. Useful e.g. as the
- :confval:`default_role`.
-
- .. versionadded:: 0.4
-
-The name enclosed in this markup can include a module name and/or a class name.
-For example, ``:func:`filter``` could refer to a function named ``filter`` in
-the current module, or the built-in function of that name. In contrast,
-``:func:`foo.filter``` clearly refers to the ``filter`` function in the ``foo``
-module.
-
-Normally, names in these roles are searched first without any further
-qualification, then with the current module name prepended, then with the
-current module and class name (if any) prepended. If you prefix the name with a
-dot, this order is reversed. For example, in the documentation of Python's
-:mod:`codecs` module, ``:func:`open``` always refers to the built-in function,
-while ``:func:`.open``` refers to :func:`codecs.open`.
-
-A similar heuristic is used to determine whether the name is an attribute of
-the currently documented class.
-
-
-Cross-referencing C constructs
-------------------------------
-
-The following roles create cross-references to C-language constructs if they
-are defined in the documentation:
-
-.. role:: cdata
-
- The name of a C-language variable.
-
-.. role:: cfunc
-
- The name of a C-language function. Should include trailing parentheses.
-
-.. role:: cmacro
-
- The name of a "simple" C macro, as defined above.
-
-.. role:: ctype
-
- The name of a C-language type.
-
-
-Cross-referencing other items of interest
------------------------------------------
-
-The following roles do possibly create a cross-reference, but do not refer to
-objects:
-
-.. role:: envvar
-
- An environment variable. Index entries are generated. Also generates a link
- to the matching :dir:`envvar` directive, if it exists.
-
-.. role:: token
-
- The name of a grammar token (used to create links between
- :dir:`productionlist` directives).
-
-.. role:: keyword
-
- The name of a keyword in Python. This creates a link to a reference label
- with that name, if it exists.
-
-.. role:: option
-
- A command-line option to an executable program. The leading hyphen(s) must
- be included. This generates a link to a :dir:`cmdoption` directive, if it
- exists.
-
-
-The following role creates a cross-reference to the term in the glossary:
-
-.. role:: term
-
- Reference to a term in the glossary. The glossary is created using the
- ``glossary`` directive containing a definition list with terms and
- definitions. It does not have to be in the same file as the ``term`` markup,
- for example the Python docs have one global glossary in the ``glossary.rst``
- file.
-
- If you use a term that's not explained in a glossary, you'll get a warning
- during build.
-
-
.. _ref-role:
Cross-referencing arbitrary locations
-------------------------------------
-.. index:: pair: ref; role
+.. role:: ref
-To support cross-referencing to arbitrary locations in any document, the
-standard reST labels are used. For this to work label names must be unique
-throughout the entire documentation. There are two ways in which you can refer
-to labels:
+ To support cross-referencing to arbitrary locations in any document, the
+ standard reST labels are used. For this to work label names must be unique
+ throughout the entire documentation. There are two ways in which you can
+ refer to labels:
-* If you place a label directly before a section title, you can reference to it
- with ``:ref:`label-name```. Example::
+ * If you place a label directly before a section title, you can reference to
+ it with ``:ref:`label-name```. Example::
- .. _my-reference-label:
+ .. _my-reference-label:
- Section to cross-reference
- --------------------------
+ Section to cross-reference
+ --------------------------
- This is the text of the section.
+ This is the text of the section.
- It refers to the section itself, see :ref:`my-reference-label`.
+ It refers to the section itself, see :ref:`my-reference-label`.
- The ``:ref:`` role would then generate a link to the section, with the link
- title being "Section to cross-reference". This works just as well when
- section and reference are in different source files.
+ The ``:ref:`` role would then generate a link to the section, with the link
+ title being "Section to cross-reference". This works just as well when
+ section and reference are in different source files.
- Automatic labels also work with figures: given ::
+ Automatic labels also work with figures: given ::
- .. _my-figure:
+ .. _my-figure:
- .. figure:: whatever
+ .. figure:: whatever
- Figure caption
+ Figure caption
- a reference ``:ref:`my-figure``` would insert a reference to the figure with
- link text "Figure caption".
+ a reference ``:ref:`my-figure``` would insert a reference to the figure
+ with link text "Figure caption".
-* Labels that aren't placed before a section title can still be referenced to,
- but you must give the link an explicit title, using this syntax: ``:ref:`Link
- title <label-name>```.
+ * Labels that aren't placed before a section title can still be referenced
+ to, but you must give the link an explicit title, using this syntax:
+ ``:ref:`Link title <label-name>```.
-Using :role:`ref` is advised over standard reStructuredText links to sections
-(like ```Section title`_``) because it works across files, when section headings
-are changed, and for all builders that support cross-references.
+ Using :role:`ref` is advised over standard reStructuredText links to sections
+ (like ```Section title`_``) because it works across files, when section
+ headings are changed, and for all builders that support cross-references.
Cross-referencing documents
@@ -405,6 +274,48 @@ Note that there are no special roles for including hyperlinks as you can use
the standard reST markup for that purpose.
+Cross-referencing other items of interest
+-----------------------------------------
+
+The following roles do possibly create a cross-reference, but do not refer to
+objects:
+
+.. role:: envvar
+
+ An environment variable. Index entries are generated. Also generates a link
+ to the matching :dir:`envvar` directive, if it exists.
+
+.. role:: token
+
+ The name of a grammar token (used to create links between
+ :dir:`productionlist` directives).
+
+.. role:: keyword
+
+ The name of a keyword in Python. This creates a link to a reference label
+ with that name, if it exists.
+
+.. role:: option
+
+ A command-line option to an executable program. The leading hyphen(s) must
+ be included. This generates a link to a :dir:`option` directive, if it
+ exists.
+
+
+The following role creates a cross-reference to the term in the glossary:
+
+.. role:: term
+
+ Reference to a term in the glossary. The glossary is created using the
+ ``glossary`` directive containing a definition list with terms and
+ definitions. It does not have to be in the same file as the ``term`` markup,
+ for example the Python docs have one global glossary in the ``glossary.rst``
+ file.
+
+ If you use a term that's not explained in a glossary, you'll get a warning
+ during build.
+
+
.. _default-substitutions:
Substitutions
diff --git a/doc/markup/misc.rst b/doc/markup/misc.rst
index 01e5a3f1..ba045165 100644
--- a/doc/markup/misc.rst
+++ b/doc/markup/misc.rst
@@ -11,12 +11,12 @@ File-wide metadata
reST has the concept of "field lists"; these are a sequence of fields marked up
like this::
- :Field name: Field content
+ :fieldname: Field content
-A field list at the very top of a file is parsed as the "docinfo", which in
-normal documents can be used to record the author, date of publication and
-other metadata. In Sphinx, the docinfo is used as metadata, too, but not
-displayed in the output.
+A field list at the very top of a file is parsed by docutils as the "docinfo",
+which is normally used to record the author, date of publication and other
+metadata. *In Sphinx*, the docinfo is used as metadata, too, but not displayed
+in the output.
At the moment, these metadata fields are recognized:
@@ -29,11 +29,17 @@ At the moment, these metadata fields are recognized:
If set, the web application won't display a comment form for a page generated
from this source file.
+``orphan``
+ If set, warnings about this file not being included in any toctree will be
+ suppressed.
+
+ .. versionadded:: 1.0
+
Meta-information markup
-----------------------
-.. directive:: sectionauthor
+.. directive:: .. sectionauthor:: name <email>
Identifies the author of the current section. The argument should include
the author's name such that it can be used for presentation and email
@@ -48,6 +54,14 @@ Meta-information markup
output.
+.. directive:: .. codeauthor:: name <email>
+
+ The :dir:`codeauthor` directive, which can appear multiple times, names the
+ authors of the described code, just like :dir:`sectionauthor` names the
+ author(s) of a piece of documentation. It too only produces output if the
+ :confval:`show_authors` configuration value is True.
+
+
.. _tags:
Including content based on tags
@@ -73,10 +87,10 @@ Including content based on tags
Tables
------
-Use standard reStructuredText tables. They work fine in HTML output, however
-there are some gotchas when using tables in LaTeX: the column width is hard to
-determine correctly automatically. For this reason, the following directive
-exists:
+Use :ref:`standard reStructuredText tables <rst-tables>`. They work fine in
+HTML output, however there are some gotchas when using tables in LaTeX: the
+column width is hard to determine correctly automatically. For this reason, the
+following directive exists:
.. directive:: .. tabularcolumns:: column spec
diff --git a/doc/markup/para.rst b/doc/markup/para.rst
index 774b0f51..9abae1dc 100644
--- a/doc/markup/para.rst
+++ b/doc/markup/para.rst
@@ -9,7 +9,7 @@ Paragraph-level markup
These directives create short paragraphs and can be used inside information
units as well as normal text:
-.. directive:: note
+.. directive:: .. note::
An especially important bit of information about an API that a user should be
aware of when using whatever bit of API the note pertains to. The content of
@@ -22,13 +22,13 @@ units as well as normal text:
This function is not suitable for sending spam e-mails.
-.. directive:: warning
+.. directive:: .. warning::
An important bit of information about an API that a user should be very aware
of when using whatever bit of API the warning pertains to. The content of
the directive should be written in complete sentences and include all
- appropriate punctuation. This differs from ``note`` in that it is recommended
- over ``note`` for information regarding security.
+ appropriate punctuation. This differs from :dir:`note` in that it is
+ recommended over :dir:`note` for information regarding security.
.. directive:: .. versionadded:: version
@@ -49,7 +49,7 @@ units as well as normal text:
.. directive:: .. versionchanged:: version
- Similar to ``versionadded``, but describes when and what changed in the named
+ Similar to :dir:`versionadded`, but describes when and what changed in the named
feature in some way (new parameters, changed side effects, etc.).
--------------
@@ -57,26 +57,27 @@ units as well as normal text:
.. directive:: seealso
Many sections include a list of references to module documentation or
- external documents. These lists are created using the ``seealso`` directive.
+ external documents. These lists are created using the :dir:`seealso`
+ directive.
- The ``seealso`` directive is typically placed in a section just before any
+ The :dir:`seealso` directive is typically placed in a section just before any
sub-sections. For the HTML output, it is shown boxed off from the main flow
of the text.
- The content of the ``seealso`` directive should be a reST definition list.
+ The content of the :dir:`seealso` directive should be a reST definition list.
Example::
.. seealso::
- Module :mod:`zipfile`
- Documentation of the :mod:`zipfile` standard module.
+ Module :py:mod:`zipfile`
+ Documentation of the :py:mod:`zipfile` standard module.
`GNU tar manual, Basic Tar Format <http://link>`_
Documentation for tar archive files, including GNU tar extensions.
There's also a "short form" allowed that looks like this::
- .. seealso:: modules :mod:`zipfile`, :mod:`tarfile`
+ .. seealso:: modules :py:mod:`zipfile`, :py:mod:`tarfile`
.. versionadded:: 0.5
The short form.
@@ -96,7 +97,8 @@ units as well as normal text:
.. directive:: centered
- This directive creates a centered boldfaced line of text. Use it as follows::
+ This directive creates a centered boldfaced line of text. Use it as
+ follows::
.. centered:: LICENSE AGREEMENT
@@ -126,16 +128,17 @@ Table-of-contents markup
------------------------
The :dir:`toctree` directive, which generates tables of contents of
-subdocuments, is described in "Sphinx concepts".
+subdocuments, is described in :ref:`toctree-directive`.
-For local tables of contents, use the standard reST :dir:`contents` directive.
+For local tables of contents, use the standard reST :rstdir:`contents directive
+<contents>`.
Index-generating markup
-----------------------
-Sphinx automatically creates index entries from all information units (like
-functions, classes or attributes) like discussed before.
+Sphinx automatically creates index entries from all object descriptions (like
+functions, classes or attributes) like discussed in :ref:`domains`.
However, there is also an explicit directive available, to make the index more
comprehensive and enable index entries in documents where information is not
@@ -159,9 +162,9 @@ mainly contained in information units, such as the language reference.
...
- This directive contains five entries, which will be converted to entries in the
- generated index which link to the exact location of the index statement (or, in
- case of offline media, the corresponding page number).
+ This directive contains five entries, which will be converted to entries in
+ the generated index which link to the exact location of the index statement
+ (or, in case of offline media, the corresponding page number).
Since index directives generate cross-reference targets at their location in
the source, it makes sense to put them *before* the thing they refer to --
@@ -171,18 +174,19 @@ mainly contained in information units, such as the language reference.
single
Creates a single index entry. Can be made a subentry by separating the
- subentry text with a semicolon (this notation is also used below to describe
- what entries are created).
+ subentry text with a semicolon (this notation is also used below to
+ describe what entries are created).
pair
``pair: loop; statement`` is a shortcut that creates two index entries,
namely ``loop; statement`` and ``statement; loop``.
triple
- Likewise, ``triple: module; search; path`` is a shortcut that creates three
- index entries, which are ``module; search path``, ``search; path, module`` and
- ``path; module search``.
+ Likewise, ``triple: module; search; path`` is a shortcut that creates
+ three index entries, which are ``module; search path``, ``search; path,
+ module`` and ``path; module search``.
module, keyword, operator, object, exception, statement, builtin
- These all create two index entries. For example, ``module: hashlib`` creates
- the entries ``module; hashlib`` and ``hashlib; module``.
+ These all create two index entries. For example, ``module: hashlib``
+ creates the entries ``module; hashlib`` and ``hashlib; module``. (These
+ are Python-specific and therefore deprecated.)
For index directives containing only "single" entries, there is a shorthand
notation::
@@ -195,7 +199,7 @@ mainly contained in information units, such as the language reference.
Glossary
--------
-.. directive:: glossary
+.. directive:: .. glossary::
This directive must contain a reST definition list with terms and
definitions. The definitions will then be referencable with the :role:`term`
@@ -227,7 +231,7 @@ derived forms), but provides enough to allow context-free grammars to be
displayed in a way that causes uses of a symbol to be rendered as hyperlinks to
the definition of the symbol. There is this directive:
-.. directive:: productionlist
+.. directive:: .. productionlist:: [name]
This directive is used to enclose a group of productions. Each production is
given on a single line and consists of a name, separated by a colon from the
@@ -235,17 +239,19 @@ the definition of the symbol. There is this directive:
continuation line must begin with a colon placed at the same column as in the
first line.
+ The argument to :dir:`productionlist` serves to distinguish different sets of
+ production lists that belong to different grammars.
+
Blank lines are not allowed within ``productionlist`` directive arguments.
The definition can contain token names which are marked as interpreted text
(e.g. ``sum ::= `integer` "+" `integer```) -- this generates cross-references
- to the productions of these tokens.
+ to the productions of these tokens. Outside of the production list, you can
+ reference to token productions using :role:`token`.
Note that no further reST parsing is done in the production, so that you
don't have to escape ``*`` or ``|`` characters.
-.. XXX describe optional first parameter
-
The following is an example taken from the Python Reference Manual::
.. productionlist::
diff --git a/doc/concepts.rst b/doc/markup/toctree.rst
index 5aabdd3b..af2fc223 100644
--- a/doc/concepts.rst
+++ b/doc/markup/toctree.rst
@@ -1,27 +1,8 @@
-.. highlight:: rest
-
-.. _concepts:
-
-Sphinx concepts
-===============
-
-Document names
---------------
-
-Since the reST source files can have different extensions (some people like
-``.txt``, some like ``.rst`` -- the extension can be configured with
-:confval:`source_suffix`) and different OSes have different path separators,
-Sphinx abstracts them: all "document names" are relative to the :term:`source
-directory`, the extension is stripped, and path separators are converted to
-slashes. All values, parameters and suchlike referring to "documents" expect
-such a document name.
-
-Examples for document names are ``index``, ``library/zipfile``, or
-``reference/datamodel/types``. Note that there is no leading slash.
-
+.. highlight:: rst
+.. _toctree-directive:
The TOC tree
-------------
+============
.. index:: pair: table of; contents
@@ -162,11 +143,12 @@ The special document names (and pages generated for them) are:
* ``genindex``, ``modindex``, ``search``
- These are used for the general index, the module index, and the search page,
- respectively.
+ These are used for the general index, the Python module index, and the search
+ page, respectively.
The general index is populated with entries from modules, all index-generating
- :ref:`description units <desc-units>`, and from :dir:`index` directives.
+ :ref:`object descriptions <basic-domain-markup>`, and from :dir:`index`
+ directives.
The module index contains one entry per :dir:`module` directive.
diff --git a/doc/more.png b/doc/more.png
new file mode 100644
index 00000000..3eb7b05c
--- /dev/null
+++ b/doc/more.png
Binary files differ
diff --git a/doc/rest.rst b/doc/rest.rst
index e70fa105..856775e1 100644
--- a/doc/rest.rst
+++ b/doc/rest.rst
@@ -1,5 +1,7 @@
.. highlightlang:: rest
+.. _rst-primer:
+
reStructuredText Primer
=======================
@@ -10,18 +12,22 @@ language, this will not take too long.
.. seealso::
- The authoritative `reStructuredText User
- Documentation <http://docutils.sourceforge.net/rst.html>`_.
+ The authoritative `reStructuredText User Documentation
+ <http://docutils.sourceforge.net/rst.html>`_. The "ref" links in this
+ document link to the description of the individual constructs in the reST
+ reference.
Paragraphs
----------
-The paragraph is the most basic block in a reST document. Paragraphs are simply
-chunks of text separated by one or more blank lines. As in Python, indentation
-is significant in reST, so all lines of the same paragraph must be left-aligned
-to the same level of indentation.
+The paragraph (:rstref:`ref <paragraphs>`) is the most basic block in a reST
+document. Paragraphs are simply chunks of text separated by one or more blank
+lines. As in Python, indentation is significant in reST, so all lines of the
+same paragraph must be left-aligned to the same level of indentation.
+
+.. _inlinemarkup:
Inline markup
-------------
@@ -49,13 +55,25 @@ enclosed text should be interpreted in a specific way. Sphinx uses this to
provide semantic markup and cross-referencing of identifiers, as described in
the appropriate section. The general syntax is ``:rolename:`content```.
+Standard reST provides the following roles:
+
+* :rstrole:`emphasis` -- alternate spelling for ``*emphasis*``
+* :rstrole:`strong` -- alternate spelling for ``**strong**``
+* :rstrole:`literal` -- alternate spelling for ````literal````
+* :rstrole:`subscript` -- subscript text
+* :rstrole:`superscript` -- superscript text
+* :rstrole:`title-reference` -- for titles of books, periodicals, and other
+ materials
+
+See :ref:`inline-markup` for roles added by Sphinx.
+
-Lists and Quotes
-----------------
+Lists and Quote-like blocks
+---------------------------
-List markup is natural: just place an asterisk at the start of a paragraph and
-indent properly. The same goes for numbered lists; they can also be
-autonumbered using a ``#`` sign::
+List markup (:rstref:`ref <bullet-lists>`) is natural: just place an asterisk at
+the start of a paragraph and indent properly. The same goes for numbered lists;
+they can also be autonumbered using a ``#`` sign::
* This is a bulleted list.
* It has two items, the second
@@ -79,7 +97,7 @@ parent list items by blank lines::
* and here the parent list continues
-Definition lists are created as follows::
+Definition lists (:rstref:`ref <definition-lists>`) are created as follows::
term (up to a line of text)
Definition of the term, which must be indented
@@ -89,17 +107,31 @@ Definition lists are created as follows::
next term
Description.
+Note that the term cannot have more than one line of text.
-Paragraphs are quoted by just indenting them more than the surrounding
-paragraphs.
+Quoted paragraphs (:rstref:`ref <block-quotes>`) are created by just indenting
+them more than the surrounding paragraphs.
+
+Line blocks (:rstref:`ref <line-blocks>`) are a way of preserving line breaks::
+
+ | These lines are
+ | broken exactly like in
+ | the source file.
+
+There are also several more special blocks available:
+
+* field lists (:rstref:`ref <field-lists>`)
+* option lists (:rstref:`ref <option-lists>`)
+* quoted literal blocks (:rstref:`ref <quoted-literal-blocks>`)
+* doctest blocks (:rstref:`ref <doctest-blocks>`)
Source Code
-----------
-Literal code blocks are introduced by ending a paragraph with the special marker
-``::``. The literal block must be indented (and, like all paragraphs, separated
-from the surrounding ones by blank lines)::
+Literal code blocks (:rstref:`ref <literal-blocks>`) are introduced by ending a
+paragraph with the special marker ``::``. The literal block must be indented
+(and, like all paragraphs, separated from the surrounding ones by blank lines)::
This is a normal text paragraph. The next paragraph is a code sample::
@@ -122,28 +154,69 @@ That way, the second sentence in the above example's first paragraph would be
rendered as "The next paragraph is a code sample:".
+.. _rst-tables:
+
+Tables
+------
+
+Two forms of tables are supported. For *grid tables* (:rstref:`ref
+<grid-tables>`), you have to "paint" the cell grid yourself. They look like
+this::
+
+ +------------------------+------------+----------+----------+
+ | Header row, column 1 | Header 2 | Header 3 | Header 4 |
+ | (header rows optional) | | | |
+ +========================+============+==========+==========+
+ | body row 1, column 1 | column 2 | column 3 | column 4 |
+ +------------------------+------------+----------+----------+
+ | body row 2 | ... | ... | |
+ +------------------------+------------+----------+----------+
+
+*Simple tables* (:rstref:`ref <simple-tables>`) are easier to write, but
+limited: they must contain more than one row, and the first column cannot
+contain multiple lines. They look like this::
+
+ ===== ===== =======
+ A B A and B
+ ===== ===== =======
+ False False False
+ True False False
+ False True False
+ True True True
+ ===== ===== =======
+
+
Hyperlinks
----------
External links
^^^^^^^^^^^^^^
-Use ```Link text <http://target>`_`` for inline web links. If the link text
-should be the web address, you don't need special markup at all, the parser
+Use ```Link text <http://example.com/>`_`` for inline web links. If the link
+text should be the web address, you don't need special markup at all, the parser
finds links and mail addresses in ordinary text.
+You can also separate the link and the target definition (:rstref:`ref
+<hyperlink-targets>`), like this::
+
+ This is a paragraph that contains `a link`_.
+
+ .. _a link: http://example.com/
+
+
Internal links
^^^^^^^^^^^^^^
-Internal linking is done via a special reST role, see the section on specific
-markup, :ref:`ref-role`.
+Internal linking is done via a special reST role provided by Sphinx, see the
+section on specific markup, :ref:`ref-role`.
Sections
--------
-Section headers are created by underlining (and optionally overlining) the
-section title with a punctuation character, at least as long as the text::
+Section headers (:rstref:`ref <sections>`) are created by underlining (and
+optionally overlining) the section title with a punctuation character, at least
+as long as the text::
=================
This is a heading
@@ -168,9 +241,9 @@ target formats (HTML, LaTeX) have a limited supported nesting depth.
Explicit Markup
---------------
-"Explicit markup" is used in reST for most constructs that need special
-handling, such as footnotes, specially-highlighted paragraphs, comments, and
-generic directives.
+"Explicit markup" (:rstref:`ref <explicit-markup-blocks>`) is used in reST for
+most constructs that need special handling, such as footnotes,
+specially-highlighted paragraphs, comments, and generic directives.
An explicit markup block begins with a line starting with ``..`` followed by
whitespace and is terminated by the next paragraph at the same level of
@@ -179,11 +252,70 @@ paragraphs. This may all sound a bit complicated, but it is intuitive enough
when you write it.)
+.. _directives:
+
Directives
----------
-A directive is a generic block of explicit markup. Besides roles, it is one of
-the extension mechanisms of reST, and Sphinx makes heavy use of it.
+A directive (:rstref:`ref <directives>`) is a generic block of explicit markup.
+Besides roles, it is one of the extension mechanisms of reST, and Sphinx makes
+heavy use of it.
+
+Docutils supports the following directives:
+
+* Admonitions: :rstdir:`attention`, :rstdir:`caution`, :rstdir:`danger`,
+ :rstdir:`error`, :rstdir:`hint`, :rstdir:`important`, :rstdir:`note`,
+ :rstdir:`tip`, :rstdir:`warning` and the generic :rstdir:`admonition`.
+ (Most themes style only "note" and "warning" specially.)
+
+* Images:
+
+ - :rstdir:`image` (see also Images_ below)
+ - :rstdir:`figure` (an image with caption and optional legend)
+
+* Additional body elements:
+
+ - :rstdir:`contents` (a local, i.e. for the current file only, table of
+ contents)
+ - :rstdir:`container` (a container with a custom class, useful to generate an
+ outer ``<div>`` in HTML)
+ - :rstdir:`rubric` (a heading without relation to the document sectioning)
+ - :rstdir:`topic`, :rstdir:`sidebar` (special highlighted body elements)
+ - :rstdir:`parsed-literal` (literal block that supports inline markup)
+ - :rstdir:`epigraph` (a block quote with optional attribution line)
+ - :rstdir:`highlights`, :rstdir:`pull-quote` (block quotes with their own
+ class attribute)
+ - :rstdir:`compound` (a compound paragraph)
+
+* Special tables:
+
+ - :rstdir:`table` (a table with title)
+ - :rstdir:`csv-table` (a table generated from comma-separated values)
+ - :rstdir:`list-table` (a table generated from a list of lists)
+
+* Special directives:
+
+ - :rstdir:`raw` (include raw target-format markup)
+ - :rstdir:`include` (include reStructuredText from another file)
+ - :rstdir:`class` (assign a class attribute to the next element) [1]_
+
+* HTML specifics:
+
+ - :rstdir:`meta` (generation of HTML ``<meta>`` tags)
+ - :rstdir:`title` (override document title)
+
+* Influencing markup:
+
+ - :rstdir:`default-role` (set a new default role)
+ - :rstdir:`role` (create a new role)
+
+ Since these are only per-file, better use Sphinx' facilities for setting the
+ :confval:`default_role`.
+
+Do *not* use the directives :rstdir:`sectnum`, :rstdir:`header` and
+:rstdir:`footer`.
+
+Directives added by Sphinx are described in :ref:`sphinxmarkup`.
Basically, a directive consists of a name, arguments, options and content. (Keep
this terminology in mind, it is used in the next chapter describing custom
@@ -207,7 +339,7 @@ directive start.
Images
------
-reST supports an image directive, used like so::
+reST supports an image directive (:rstdir:`ref <image>`), used like so::
.. image:: gnu.png
(options)
@@ -247,9 +379,9 @@ the former, while the HTML builder would prefer the latter.
Footnotes
---------
-For footnotes, use ``[#name]_`` to mark the footnote location, and add the
-footnote body at the bottom of the document after a "Footnotes" rubric heading,
-like so::
+For footnotes (:rstref:`ref <footnotes>`), use ``[#name]_`` to mark the footnote
+location, and add the footnote body at the bottom of the document after a
+"Footnotes" rubric heading, like so::
Lorem ipsum [#f1]_ dolor sit amet ... [#f2]_
@@ -265,9 +397,9 @@ footnotes without names (``[#]_``).
Citations
---------
-Standard reST citations are supported, with the additional feature that they are
-"global", i.e. all citations can be referenced from all files. Use them like
-so::
+Standard reST citations (:rstref:`ref <citations>`) are supported, with the
+additional feature that they are "global", i.e. all citations can be referenced
+from all files. Use them like so::
Lorem ipsum [Ref]_ dolor sit amet.
@@ -280,14 +412,18 @@ numeric or begins with ``#``.
Substitutions
-------------
-reST supports "substitutions", which are pieces of text and/or markup referred
-to in the text by ``|name|``. They are defined like footnotes with explicit
-markup blocks, like this::
+reST supports "substitutions" (:rstref:`ref <substitution-definitions>`), which
+are pieces of text and/or markup referred to in the text by ``|name|``. They
+are defined like footnotes with explicit markup blocks, like this::
.. |name| replace:: replacement *text*
-See the `reST reference for substitutions
-<http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#substitution-definitions>`_
+or this::
+
+ .. |caution| image:: warning.png
+ :alt: Warning!
+
+See the :rstref:`reST reference for substitutions <substitution-definitions>`
for details.
If you want to use some substitutions for all documents, put them into a
@@ -303,7 +439,8 @@ Comments
--------
Every explicit markup block which isn't a valid markup construct (like the
-footnotes above) is regarded as a comment. For example::
+footnotes above) is regarded as a comment (:rstref:`ref <comments>`). For
+example::
.. This is a comment.
@@ -331,10 +468,16 @@ Gotchas
There are some problems one commonly runs into while authoring reST documents:
* **Separation of inline markup:** As said above, inline markup spans must be
- separated from the surrounding text by non-word characters, you have to use
- a backslash-escaped space to get around that.
+ separated from the surrounding text by non-word characters, you have to use a
+ backslash-escaped space to get around that. See `the reference
+ <http://docutils.sf.net/docs/ref/rst/restructuredtext.html#inline-markup>`_
+ for the details.
* **No nested inline markup:** Something like ``*see :func:`foo`*`` is not
possible.
-.. XXX more?
+
+.. rubric:: Footnotes
+
+.. [1] When the default domain contains a :dir:`class` directive, this directive
+ will be shadowed. Therefore, Sphinx re-exports it as :dir:`rst-class`.
diff --git a/doc/sphinx-build.1 b/doc/sphinx-build.1
deleted file mode 100644
index a3df16d0..00000000
--- a/doc/sphinx-build.1
+++ /dev/null
@@ -1,105 +0,0 @@
-.TH sphinx-build 1 "Jan 2009" "Sphinx 0.6" "User Commands"
-.SH NAME
-sphinx-build \- Sphinx documentation generator tool
-.SH SYNOPSIS
-.B sphinx-build
-[\fIoptions\fR] <\fIsourcedir\fR> <\fIoutdir\fR> [\fIfilenames\fR...]
-.SH DESCRIPTION
-sphinx-build generates documentation from the files in <sourcedir> and places it
-in the <outdir>.
-
-sphinx-build looks for <sourcedir>/conf.py for the configuration settings.
-.B sphinx-quickstart(1)
-may be used to generate template files, including conf.py.
-
-sphinx-build can create documentation in different formats. A format is
-selected by specifying the builder name on the command line; it defaults to
-HTML. Builders can also perform other tasks related to documentation
-processing.
-
-By default, everything that is outdated is built. Output only for selected
-files can be built by specifying individual filenames.
-
-List of available builders:
-.TP
-\fBhtml\fR
-HTML files generation. This is default builder.
-.TP
-\fBhtmlhelp\fR
-Generates files for CHM generation.
-.TP
-\fBqthelp\fR
-Generates files for Qt help collection generation.
-.TP
-\fBdevhelp\fR
-Generates files for GNOME Devhelp help viewer.
-.TP
-\fBlatex\fR
-Generates a LaTeX version of the documentation.
-.TP
-\fBtext\fR
-Generates a plain-text version of the documentation.
-.TP
-\fBchanges\fR
-Generates HTML files listing changed/added/deprecated items for the
-current version.
-.TP
-\fBlinkcheck\fR
-Checks the integrity of all external links in the documentation.
-.TP
-\fBpickle / json\fR
-Generates serialized HTML files in the selected format.
-
-.SH OPTIONS
-.TP
-\fB-b\fR <builder>
-Builder to use; defaults to html. See the full list of builders above.
-.TP
-\fB-a\fR
-Generates output for all files; without this option only output for
-new and changed files is generated.
-.TP
-\fB-E\fR
-Ignores cached files, forces to re-read all source files from disk.
-.TP
-\fB-c\fR <path>
-Locates the conf.py file in the specified path instead of <sourcedir>.
-.TP
-\fB-C\fR
-Specifies that no conf.py file at all is to be used. Configuration can
-only be set with the -D option.
-.TP
-\fB-D\fR <setting>=<value>
-Overrides a setting from the configuration file.
-.TP
-\fB-d\fR <path>
-Path to cached files; defaults to <outdir>/.doctrees.
-.TP
-\fB-A\fR <name>=<value>
-Passes a value into the HTML templates (only for html builders).
-.TP
-\fB-N\fR
-Prevents colored output.
-.TP
-\fB-q\fR
-Quiet operation, just prints warnings and errors on stderr.
-.TP
-\fB-Q\fR
-Very quiet operation, doesn't print anything except for errors.
-.TP
-\fB-w\fR <file>
-Write warnings and errors into the given file, in addition to stderr.
-.TP
-\fB-W\fR
-Turn warnings into errors.
-.TP
-\fB-P\fR
-Runs Pdb on exception.
-.SH "SEE ALSO"
-.BR sphinx-quickstart(1)
-.SH AUTHOR
-Georg Brandl <georg@python.org>, Armin Ronacher <armin.ronacher@active-4.com> et
-al.
-.PP
-This manual page was initially written by Mikhail Gusarov
-<dottedmag@dottedmag.net>, for the Debian project.
diff --git a/doc/sphinx-quickstart.1 b/doc/sphinx-quickstart.1
deleted file mode 100644
index 93b0a4a5..00000000
--- a/doc/sphinx-quickstart.1
+++ /dev/null
@@ -1,17 +0,0 @@
-.TH sphinx-quickstart 1 "Jan 2009" "Sphinx 0.6" "User Commands"
-.SH NAME
-sphinx-quickstart \- Sphinx documentation template generator
-.SH SYNOPSIS
-.B sphinx-quickstart
-.SH DESCRIPTION
-sphinx-quickstart is an interactive tool that asks some questions about your
-project and then generates a complete documentation directory and sample
-Makefile to be used with \fBsphinx-build(1)\fR.
-.SH "SEE ALSO"
-.BR sphinx-build(1)
-.SH AUTHOR
-Georg Brandl <georg@python.org>, Armin Ronacher <armin.ronacher@active-4.com> et
-al.
-.PP
-This manual page was initially written by Mikhail Gusarov
-<dottedmag@dottedmag.net> for the Debian project.
diff --git a/doc/templating.rst b/doc/templating.rst
index 948e611d..5bf09dbd 100644
--- a/doc/templating.rst
+++ b/doc/templating.rst
@@ -318,9 +318,9 @@ in the future.
.. data:: rellinks
A list of links to put at the left side of the relbar, next to "next" and
- "prev". This usually contains links to the index and the modindex. If you
- add something yourself, it must be a tuple ``(pagename, link title,
- accesskey, link text)``.
+ "prev". This usually contains links to the general index and other indices,
+ such as the Python module index. If you add something yourself, it must be a
+ tuple ``(pagename, link title, accesskey, link text)``.
.. data:: shorttitle
@@ -377,6 +377,10 @@ are in HTML form), these variables are also available:
.. data:: toctree
A callable yielding the global TOC tree containing the current page, rendered
- as HTML bullet lists. If the optional keyword argument ``collapse`` is true
- (the default), all TOC entries that are not ancestors of the current page are
- collapsed.
+ as HTML bullet lists. Optional keyword arguments:
+
+ * ``collapse`` (true by default): if true, all TOC entries that are not
+ ancestors of the current page are collapsed
+
+ * ``maxdepth`` (defaults to the max depth selected in the toctree directive):
+ the maximum depth of the tree; set it to ``-1`` to allow unlimited depth
diff --git a/doc/theming.rst b/doc/theming.rst
index e4a6b9a5..3a00150b 100644
--- a/doc/theming.rst
+++ b/doc/theming.rst
@@ -54,8 +54,8 @@ Builtin themes
.. cssclass:: right
-+-----------------------------------------+
-| **Theme overview** |
++--------------------+--------------------+
+| **Theme overview** | |
+--------------------+--------------------+
| |default| | |sphinxdoc| |
| | |
diff --git a/doc/tutorial.rst b/doc/tutorial.rst
new file mode 100644
index 00000000..bb4116ba
--- /dev/null
+++ b/doc/tutorial.rst
@@ -0,0 +1,262 @@
+.. highlight:: rst
+
+First Steps with Sphinx
+=======================
+
+This document is meant to give a tutorial-like overview of all common tasks
+while using Sphinx.
+
+The green arrows designate "more info" links leading to advanced sections about
+the described task.
+
+
+Setting up the documentation sources
+------------------------------------
+
+The root directory of a documentation collection is called the :term:`source
+directory`. This directory also contains the Sphinx configuration file
+:file:`conf.py`, where you can configure all aspects of how Sphinx reads your
+sources and builds your documentation. [#]_
+
+Sphinx comes with a script called :program:`sphinx-quickstart` that sets up a
+source directory and creates a default :file:`conf.py` with the most useful
+configuration values from a few questions it asks you. Just run ::
+
+ $ sphinx-quickstart
+
+and answer its questions. (Be sure to say yes to the "autodoc" extension.)
+
+
+Defining document structure
+---------------------------
+
+Let's assume you've run :program:`sphinx-quickstart`. It created a source
+directory with :file:`conf.py` and a master document, :file:`index.rst` (if you
+accepted the defaults). The main function of the :term:`master document` is to
+serve as a welcome page, and to contain the root of the "table of contents tree"
+(or *toctree*). This is one of the main things that Sphinx adds to
+reStructuredText, a way to connect multiple files to a single hierarchy of
+documents.
+
+.. sidebar:: reStructuredText directives
+
+ ``toctree`` is a reStructuredText :dfn:`directive`, a very versatile piece of
+ markup. Directives can have arguments, options and content.
+
+ *Arguments* are given directly after the double colon following the
+ directive's name. Each directive decides whether it can have arguments, and
+ how many.
+
+ *Options* are given after the arguments, in form of a "field list". The
+ ``maxdepth`` is such an option for the ``toctree`` directive.
+
+ *Content* follows the options or arguments after a blank line. Each
+ directive decides whether to allow content, and what to do with it.
+
+ A common gotcha with directives is that **the first line of the content must
+ be indented to the same level as the options are**.
+
+
+The toctree directive initially is empty, and looks like this::
+
+ .. toctree::
+ :maxdepth: 2
+
+You add documents listing them in the *content* of the directive::
+
+ .. toctree::
+ :maxdepth: 2
+
+ intro
+ tutorial
+ ...
+
+This is exactly how the toctree for this documentation looks. The documents to
+include are given as :term:`document name`\ s, which in short means that you
+leave off the file name extension and use slashes as directory separators.
+
+|more| Read more about :ref:`the toctree directive <toctree-directive>`.
+
+You can now create the files you listed in the toctree and add content, and
+their section titles will be inserted (up to the "maxdepth" level) at the place
+where the toctree directive is placed. Also, Sphinx now knows about the order
+and hierarchy of your documents. (They may contain ``toctree`` directives
+themselves, which means you can create deeply nested hierarchies if necessary.)
+
+
+Adding content
+--------------
+
+In Sphinx source files, you can use most features of standard reStructuredText.
+There are also several features added by Sphinx. For example, you can add
+cross-file references in a portable way (which works for all output types) using
+the :role:`ref` role.
+
+For an example, if you are viewing the HTML version you can look at the source
+for this document -- use the "Show Source" link in the sidebar.
+
+|more| See :ref:`rst-primer` for a more in-depth introduction to
+reStructuredText and :ref:`sphinxmarkup` for a full list of markup added by
+Sphinx.
+
+
+Running the build
+-----------------
+
+Now that you have added some files and content, let's make a first build of the
+docs. A build is started with the :program:`sphinx-build` program, called like
+this::
+
+ $ sphinx-build -b html sourcedir builddir
+
+where *sourcedir* is the :term:`source directory`, and *builddir* is the
+directory in which you want to place the built documentation. The :option:`-b`
+option selects a builder; in this example Sphinx will build HTML files.
+
+|more| See :ref:`invocation` for all options that :program:`sphinx-build`
+supports.
+
+However, :program:`sphinx-quickstart` script creates a :file:`Makefile` and a
+:file:`make.bat` which make life even easier for you: with them you only need
+to run ::
+
+ $ make html
+
+to build HTML docs in the build directory you chose. Execute ``make`` without
+an argument to see which targets are available.
+
+
+Documenting objects
+-------------------
+
+One of Sphinx' main objectives is easy documentation of :dfn:`objects` (in a
+very general sense) in any :dfn:`domain`. A domain is a collection of object
+types that belong together, complete with markup to create and reference
+descriptions of these objects.
+
+The most prominent domain is the Python domain. To e.g. document the Python
+built-in function ``enumerate()``, you would add this to one of your source
+files::
+
+ .. py:function:: enumerate(sequence[, start=0])
+
+ Return an iterator that yields tuples of an index and an item of the
+ *sequence*. (And so on.)
+
+This is rendered like this:
+
+.. py:function:: enumerate(sequence[, start=0])
+
+ Return an iterator that yields tuples of an index and an item of the
+ *sequence*. (And so on.)
+
+The argument of the directive is the :dfn:`signature` of the object you
+describe, the content is the documentation for it. Multiple signatures can be
+given, each in its own line.
+
+The Python domain also happens to be the default domain, so you don't need to
+prefix the markup with the domain name::
+
+ .. function:: enumerate(sequence[, start=0])
+
+ ...
+
+does the same job if you keep the default setting for the default domain.
+
+There are several more directives for documenting other types of Python objects,
+for example :dir:`py:class` or :dir:`py:method`. There is also a
+cross-referencing :dfn:`role` for each of these object types. This markup will
+create a link to the documentation of ``enumerate()``::
+
+ The :py:func:`enumerate` function can be used for ...
+
+And here is the proof: A link to :func:`enumerate`.
+
+Again, the ``py:`` can be left out if the Python domain is the default one. It
+doesn't matter which file contains the actual documentation for ``enumerate()``;
+Sphinx will find it and create a link to it.
+
+Each domain will have special rules for how the signatures can look like, and
+make the formatted output look pretty, or add specific features like links to
+parameter types, e.g. in the C/C++ domains.
+
+|more| See :ref:`domains` for all the available domains and their
+directives/roles.
+
+
+Basic configuration
+-------------------
+
+Earlier we mentioned that the :file:`conf.py` file controls how Sphinx processes
+your documents. In that file, which is executed as a Python source file, you
+assign configuration values. For advanced users: since it is executed by
+Sphinx, you can do non-trivial tasks in it, like extending :data:`sys.path` or
+importing a module to find out the version your are documenting.
+
+The config values that you probably want to change are already put into the
+:file:`conf.py` by :program:`sphinx-quickstart` and initially commented out
+(with standard Python syntax: a ``#`` comments the rest of the line). To change
+the default value, remove the hash sign and modify the value. To customize a
+config value that is not automatically added by :program:`sphinx-quickstart`,
+just add an additional assignment.
+
+Keep in mind that the file uses Python syntax for strings, numbers, lists and so
+on. The file is saved in UTF-8 by default, as indicated by the encoding
+declaration in the first line. If you use non-ASCII characters in any string
+value, you need to use Python Unicode strings (like ``project = u'Exposé'``).
+
+|more| See :ref:`build-config` for documentation of all available config values.
+
+
+Autodoc
+-------
+
+When documenting Python code, it is common to put a lot of documentation in the
+source files, in documentation strings. Sphinx supports the inclusion of
+docstrings from your modules with an :dfn:`extension` (an extension is a Python
+module that provides additional features for Sphinx projects) called "autodoc".
+
+In order to use autodoc, you need to activate it in :file:`conf.py` by putting
+the string ``'sphinx.ext.autodoc'`` into the list assigned to the
+:confval:`extensions` config value. Then, you have a few additional directives
+at your disposal.
+
+For example, to document the function ``io.open()``, reading its
+signature and docstring from the source file, you'd write this::
+
+ .. autofunction:: io.open
+
+You can also document whole classes or even modules automatically, using member
+options for the auto directives, like ::
+
+ .. automodule:: io
+ :members:
+
+autodoc needs to import your modules in order to extract the docstrings.
+Therefore, you must add the appropriate path to :py:data:`sys.path` in your
+:file:`conf.py`.
+
+|more| See :mod:`sphinx.ext.autodoc` for the complete description of the
+features of autodoc.
+
+
+More topics to be covered
+-------------------------
+
+- Other extensions (math, intersphinx, viewcode, doctest)
+- Static files
+- Selecting a theme
+- Templating
+- Using extensions
+- Writing extensions
+
+
+.. rubric:: Footnotes
+
+.. [#] This is the usual lay-out. However, :file:`conf.py` can also live in
+ another directory, the :term:`configuration directory`. See
+ :ref:`invocation`.
+
+.. |more| image:: more.png
+ :align: middle
+ :alt: more info
diff --git a/setup.cfg b/setup.cfg
index 23986bcf..525e24ea 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -8,6 +8,7 @@ release = egg_info -RDb ''
[extract_messages]
mapping_file = babel.cfg
output_file = sphinx/locale/sphinx.pot
+keywords = _ l_ lazy_gettext
[update_catalog]
input_file = sphinx/locale/sphinx.pot
diff --git a/setup.py b/setup.py
index 6a46e6d6..b2c96f48 100644
--- a/setup.py
+++ b/setup.py
@@ -11,20 +11,21 @@ import sphinx
long_desc = '''
Sphinx is a tool that makes it easy to create intelligent and beautiful
-documentation for Python projects (or other documents consisting of
-multiple reStructuredText sources), written by Georg Brandl.
-It was originally created to translate the new Python documentation,
-but has now been cleaned up in the hope that it will be useful to many
-other projects.
+documentation for Python projects (or other documents consisting of multiple
+reStructuredText sources), written by Georg Brandl. It was originally created
+for the new Python documentation, and has excellent facilities for Python
+project documentation, but C/C++ is supported as well, and more languages are
+planned.
Sphinx uses reStructuredText as its markup language, and many of its strengths
-come from the power and straightforwardness of reStructuredText and its
-parsing and translating suite, the Docutils.
+come from the power and straightforwardness of reStructuredText and its parsing
+and translating suite, the Docutils.
Among its features are the following:
* Output formats: HTML (including derivative formats such as HTML Help, Epub
- and Qt Help), plain text and LaTeX or direct PDF output using rst2pdf
+ and Qt Help), plain text, manual pages and LaTeX or direct PDF output
+ using rst2pdf
* Extensive cross-references: semantic markup and automatic links
for functions, classes, glossary terms and similar pieces of information
* Hierarchical structure: easy definition of a document tree, with automatic
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 31726e4b..6fd96bdc 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/addnodes.py b/sphinx/addnodes.py
index 83ba8a00..0a2f0f7f 100644
--- a/sphinx/addnodes.py
+++ b/sphinx/addnodes.py
@@ -14,7 +14,7 @@ from docutils import nodes
# index markup
class index(nodes.Invisible, nodes.Inline, nodes.TextElement): pass
-# description units (classdesc, funcdesc etc.)
+# domain-specific object descriptions (class, function etc.)
# parent node for signature and content
class desc(nodes.Admonition, nodes.Element): pass
@@ -90,9 +90,6 @@ class abbreviation(nodes.Inline, nodes.TextElement): pass
# glossary
class glossary(nodes.Element): pass
-# module declaration
-class module(nodes.Element): pass
-
# start of a file, used in the LaTeX builder only
class start_of_file(nodes.Element): pass
diff --git a/sphinx/application.py b/sphinx/application.py
index 636d436c..b5ba514c 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -14,22 +14,26 @@
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
+from docutils.parsers.rst import Directive, convert_directive_function, \
+ 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, \
VersionRequirementError
+from sphinx.domains import ObjType, BUILTIN_DOMAINS
+from sphinx.domains.std import GenericObject, Target, StandardDomain
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
+from sphinx.util.osutil import ENOENT
from sphinx.util.console import bold
@@ -45,23 +49,27 @@ events = {
'missing-reference': 'env, node, contnode',
'doctree-resolved': 'doctree, docname',
'env-updated': 'env',
+ 'html-collect-pages': 'builder',
'html-page-context': 'pagename, context, doctree or None',
'build-finished': 'exception',
}
CONFIG_FILENAME = 'conf.py'
+ENV_PICKLE_FILENAME = 'environment.pickle'
class Sphinx(object):
def __init__(self, srcdir, confdir, outdir, doctreedir, buildername,
- confoverrides, status, warning=sys.stderr, freshenv=False,
- warningiserror=False, tags=None):
+ confoverrides=None, status=sys.stdout, warning=sys.stderr,
+ freshenv=False, warningiserror=False, tags=None):
self.next_listener_id = 0
self._extensions = {}
self._listeners = {}
+ self.domains = BUILTIN_DOMAINS.copy()
self.builderclasses = BUILTIN_BUILDERS.copy()
self.builder = None
+ self.env = None
self.srcdir = srcdir
self.confdir = confdir
@@ -92,7 +100,8 @@ class Sphinx(object):
# read config
self.tags = Tags(tags)
- self.config = Config(confdir, CONFIG_FILENAME, confoverrides, self.tags)
+ self.config = Config(confdir, CONFIG_FILENAME,
+ confoverrides or {}, self.tags)
self.config.check_unicode(self.warn)
# set confdir to srcdir if -C given (!= no confdir); a few pieces
@@ -117,8 +126,62 @@ class Sphinx(object):
'This project needs at least Sphinx v%s and therefore cannot '
'be built with this version.' % self.config.needs_sphinx)
+ # 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 self.domains.keys():
+ self.env.domains[domain] = self.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 self.domains.keys():
+ # this can raise if the data version doesn't fit
+ self.env.domains[domain] = self.domains[domain](self.env)
+ self.info('done')
+ except Exception, err:
+ if type(err) is IOError and err.errno == ENOENT:
+ 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)
@@ -129,14 +192,12 @@ 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):
+ def build(self, force_all=False, filenames=None):
try:
- if all_files:
+ if force_all:
self.builder.build_all()
elif filenames:
self.builder.build_specific(filenames)
@@ -242,11 +303,11 @@ class Sphinx(object):
event.pop(listener_id, None)
def emit(self, event, *args):
- result = []
+ results = []
if event in self._listeners:
for _, callback in self._listeners[event].iteritems():
- result.append(callback(self, *args))
- return result
+ results.append(callback(self, *args))
+ return results
def emit_firstresult(self, event, *args):
for result in self.emit(event, *args):
@@ -296,6 +357,9 @@ class Sphinx(object):
from sphinx.writers.latex import LaTeXTranslator as translator
elif key == 'text':
from sphinx.writers.text import TextTranslator as translator
+ elif key == 'man':
+ from sphinx.writers.manpage import ManualPageTranslator \
+ as translator
else:
# ignore invalid keys for compatibility
continue
@@ -303,17 +367,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 obj
else:
obj.content = content
- obj.arguments = arguments
+ obj.arguments = arguments or (0, 0, False)
obj.options = options
- directives.register_directive(name, obj)
+ return convert_directive_function(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)
@@ -324,23 +392,62 @@ class Sphinx(object):
role = roles.GenericRole(name, nodeclass)
roles.register_local_role(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
+ def add_domain(self, domain):
+ if domain.name in self.domains:
+ raise ExtensionError('domain %s already registered' % domain.name)
+ self.domains[domain.name] = domain
+
+ def override_domain(self, domain):
+ if domain.name not in self.domains:
+ raise ExtensionError('domain %s not yet registered' % domain.name)
+ if not issubclass(domain, self.domains[domain.name]):
+ raise ExtensionError('new domain not a subclass of registered '
+ 'domain' % domain.name)
+ self.domains[domain.name] = domain
+
+ def add_directive_to_domain(self, domain, name, obj,
+ content=None, arguments=None, **options):
+ if domain not in self.domains:
+ raise ExtensionError('domain %s not yet registered' % domain)
+ self.domains[domain].directives[name] = \
+ self._directive_helper(obj, content, arguments, **options)
+
+ def add_role_to_domain(self, domain, name, role):
+ if domain not in self.domains:
+ raise ExtensionError('domain %s not yet registered' % domain)
+ self.domains[domain].roles[name] = role
+
+ def add_index_to_domain(self, domain, name, localname, shortname, func):
+ if domain not in self.domains:
+ raise ExtensionError('domain %s not yet registered' % domain)
+ self.domains[domain].indices.append((name, localname, shortname))
+ setattr(self.domains[domain], 'get_%s_index' % name, func)
+
+ def add_object_type(self, directivename, rolename, indextemplate='',
+ parse_node=None, ref_nodeclass=None, objname=''):
+ StandardDomain.object_types[directivename] = \
+ ObjType(objname or directivename, rolename)
+ # create a subclass of GenericObject as the new directive
+ new_directive = type(directivename, (GenericObject, object),
+ {'indextemplate': indextemplate,
+ 'parse_node': staticmethod(parse_node)})
+ StandardDomain.directives[directivename] = new_directive
+ # XXX support more options?
+ StandardDomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass)
+
+ # backwards compatible alias
+ add_description_unit = add_object_type
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
+ ref_nodeclass=None, objname=''):
+ StandardDomain.object_types[directivename] = \
+ ObjType(objname or directivename, rolename)
+ # create a subclass of Target as the new directive
+ new_directive = type(directivename, (Target, object),
+ {'indextemplate': indextemplate})
+ StandardDomain.directives[directivename] = new_directive
+ # XXX support more options?
+ StandardDomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass)
def add_transform(self, transform):
SphinxStandaloneReader.transforms.append(transform)
diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py
index 32236a66..e345d570 100644
--- a/sphinx/builders/__init__.py
+++ b/sphinx/builders/__init__.py
@@ -10,14 +10,11 @@
"""
import os
-import gettext
from os import path
from docutils import nodes
-from sphinx import package_dir, locale
-from sphinx.environment import BuildEnvironment
-from sphinx.util.osutil import SEP, ENOENT, relative_uri
+from sphinx.util.osutil import SEP, relative_uri
from sphinx.util.console import bold, purple, darkgreen, term_width_line
# side effect: registers roles and directives
@@ -25,9 +22,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 +32,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 +45,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 +156,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 == ENOENT:
- 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 +235,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')
@@ -392,6 +326,7 @@ BUILTIN_BUILDERS = {
'epub': ('epub', 'EpubBuilder'),
'latex': ('latex', 'LaTeXBuilder'),
'text': ('text', 'TextBuilder'),
+ 'man': ('manpage', 'ManualPageBuilder'),
'changes': ('changes', 'ChangesBuilder'),
'linkcheck': ('linkcheck', 'CheckExternalLinksBuilder'),
}
diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py
index 0571246a..980ed760 100644
--- a/sphinx/builders/changes.py
+++ b/sphinx/builders/changes.py
@@ -15,6 +15,7 @@ from cgi import escape
from sphinx import package_dir
from sphinx.util import copy_static_entry
+from sphinx.locale import _
from sphinx.theming import Theme
from sphinx.builders import Builder
from sphinx.util.osutil import ensuredir, os_path
diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py
index d7acf764..a5a0f280 100644
--- a/sphinx/builders/devhelp.py
+++ b/sphinx/builders/devhelp.py
@@ -11,9 +11,7 @@
:license: BSD, see LICENSE for details.
"""
-import os
-import cgi
-import sys
+import re
from os import path
from docutils import nodes
@@ -30,7 +28,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 +112,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 914d741f..b1084934 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -10,6 +10,7 @@
"""
import os
+import zlib
import codecs
import posixpath
import cPickle as pickle
@@ -35,9 +36,11 @@ from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.matching import patmatch, compile_matchers
from sphinx.util.pycompat import any
from sphinx.errors import SphinxError
+from sphinx.locale import _
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, darkgreen
from sphinx.writers.html import HTMLWriter, HTMLTranslator, \
@@ -229,6 +232,26 @@ class StandaloneHTMLBuilder(Builder):
defaults=self.env.settings,
components=(self.docwriter,)).get_default_values()
+ # determine the additional indices to include
+ self.domain_indices = []
+ # html_domain_indices can be False/True or a list of index names
+ indices_config = self.config.html_domain_indices
+ if indices_config:
+ for domain in self.env.domains.itervalues():
+ for indexcls in domain.indices:
+ indexname = '%s-%s' % (domain.name, indexcls.name)
+ if isinstance(indices_config, list):
+ if indexname not in indices_config:
+ continue
+ # deprecated config value
+ if indexname == 'py-modindex' and \
+ not self.config.html_use_modindex:
+ continue
+ content, collapse = indexcls(domain).generate()
+ if content:
+ self.domain_indices.append(
+ (indexname, indexcls, content, collapse))
+
# format the "last updated on" string, only once is enough since it
# typically doesn't include the time of day
lufmt = self.config.html_last_updated_fmt
@@ -253,9 +276,11 @@ 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:
- rellinks.append(('modindex', _('Global Module Index'),
- 'M', _('modules')))
+ for indexname, indexcls, content, collapse in self.domain_indices:
+ # if it has a short name
+ if indexcls.shortname:
+ rellinks.append((indexname, indexcls.localname,
+ '', indexcls.shortname))
if self.config.html_style is not None:
stylename = self.config.html_style
@@ -384,13 +409,17 @@ class StandaloneHTMLBuilder(Builder):
def finish(self):
self.info(bold('writing additional files...'), nonl=1)
+ # pages from extensions
+ for pagelist in self.app.emit('html-collect-pages'):
+ for pagename, context, template in pagelist:
+ self.handle_page(pagename, context, template)
+
# the global general index
if self.config.html_use_index:
self.write_genindex()
- # the global module index
- if self.config.html_use_modindex and self.env.modules:
- self.write_modindex()
+ # the global domain-specific indices
+ self.write_domain_indices()
# the search page
if self.name != 'htmlhelp':
@@ -446,95 +475,15 @@ class StandaloneHTMLBuilder(Builder):
else:
self.handle_page('genindex', genindexcontext, 'genindex.html')
- def write_modindex(self):
- # 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()),
- key=lambda x: x[0].lower())
- # collect all platforms
- platforms = set()
- # sort out collapsable modules
- modindexentries = []
- letters = []
- pmn = ''
- num_toplevels = 0
- num_collapsables = 0
- cg = 0 # collapse group
- fl = '' # first letter
- for mn, (fn, sy, pl, dep) in modules:
- pl = pl and pl.split(', ') or []
- platforms.update(pl)
-
- ignore = self.env.config['modindex_common_prefix']
- ignore = sorted(ignore, key=len, reverse=True)
- for i in ignore:
- if mn.startswith(i):
- mn = mn[len(i):]
- stripped = i
- break
- else:
- stripped = ''
-
- # we stripped the whole module name
- if not mn:
- continue
-
- if fl != mn[0].lower() and mn[0] != '_':
- # heading
- letter = mn[0].upper()
- if letter not in letters:
- modindexentries.append(['', False, 0, False,
- letter, '', [], False, ''])
- letters.append(letter)
- tn = mn.split('.')[0]
- if tn != mn:
- # submodule
- if pmn == tn:
- # first submodule - make parent collapsable
- modindexentries[-1][1] = True
- num_collapsables += 1
- elif not pmn.startswith(tn):
- # submodule without parent in list, add dummy entry
- cg += 1
- modindexentries.append([tn, True, cg, False, '', '',
- [], False, stripped])
- else:
- num_toplevels += 1
- cg += 1
- modindexentries.append([mn, False, cg, (tn != mn), fn, sy, pl,
- dep, stripped])
- pmn = mn
- fl = mn[0].lower()
- platforms = sorted(platforms)
-
- # apply heuristics when to collapse modindex at page load:
- # only collapse if number of toplevel modules is larger than
- # number of submodules
- collapse = len(modules) - num_toplevels < num_toplevels
-
- # As some parts of the module names may have been stripped, those
- # names have changed, thus it is necessary to sort the entries.
- if ignore:
- def sorthelper(entry):
- name = entry[0]
- if name == '':
- # heading
- name = entry[4]
- return name.lower()
-
- modindexentries.sort(key=sorthelper)
- letters.sort()
-
- modindexcontext = dict(
- modindexentries = modindexentries,
- platforms = platforms,
- letters = letters,
- collapse_modindex = collapse,
- )
- self.info(' modindex', nonl=1)
- self.handle_page('modindex', modindexcontext, 'modindex.html')
+ def write_domain_indices(self):
+ for indexname, indexcls, content, collapse in self.domain_indices:
+ indexcontext = dict(
+ indextitle = indexcls.localname,
+ content = content,
+ collapse_index = collapse,
+ )
+ self.info(' ' + indexname, nonl=1)
+ self.handle_page(indexname, indexcontext, 'domainindex.html')
def copy_image_files(self):
# copy image files
@@ -677,7 +626,7 @@ class StandaloneHTMLBuilder(Builder):
if self.indexer is not None and title:
self.indexer.feed(pagename, title, doctree)
- def _get_local_toctree(self, docname, collapse=True):
+ def _get_local_toctree(self, docname, collapse=True, maxdepth=0):
return self.render_partial(self.env.get_toctree_for(
docname, self, collapse))['fragment']
@@ -774,16 +723,22 @@ class StandaloneHTMLBuilder(Builder):
def dump_inventory(self):
self.info(bold('dumping object inventory... '), nonl=True)
- f = open(path.join(self.outdir, INVENTORY_FILENAME), 'w')
+ f = open(path.join(self.outdir, INVENTORY_FILENAME), 'wb')
try:
- f.write('# Sphinx inventory version 1\n')
+ f.write('# Sphinx inventory version 2\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)))
+ f.write('# The remainder of this file is compressed using zlib.\n')
+ compressor = zlib.compressobj(9)
+ for domainname, domain in self.env.domains.iteritems():
+ for name, type, docname, anchor, prio in domain.get_objects():
+ if anchor.endswith(name):
+ # this can shorten the inventory by as much as 25%
+ anchor = anchor[:-len(name)] + '$'
+ f.write(compressor.compress(
+ '%s %s:%s %s %s\n' % (name, domainname, type, prio,
+ self.get_target_uri(docname) + '#' + anchor)))
+ f.write(compressor.flush())
finally:
f.close()
self.info('done')
diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py
index 3ef98f34..9bbe0a5d 100644
--- a/sphinx/builders/htmlhelp.py
+++ b/sphinx/builders/htmlhelp.py
@@ -18,6 +18,7 @@ from os import path
from docutils import nodes
from sphinx import addnodes
+from sphinx.locale import _
from sphinx.builders.html import StandaloneHTMLBuilder
@@ -216,9 +217,9 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
# special books
f.write('<LI> ' + object_sitemap % (self.config.html_short_title,
'index.html'))
- if self.config.html_use_modindex:
- f.write('<LI> ' + object_sitemap % (_('Global Module Index'),
- 'modindex.html'))
+ for index in self.domain_indices:
+ f.write('<LI> ' + object_sitemap % (index[2],
+ '%s-%s.html' % index[0:2]))
# the TOC
tocdoc = self.env.get_and_resolve_doctree(
self.config.master_doc, self, prune_toctrees=False)
diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex.py
index 21771327..0481b308 100644
--- a/sphinx/builders/latex.py
+++ b/sphinx/builders/latex.py
@@ -19,6 +19,7 @@ from docutils.frontend import OptionParser
from sphinx import package_dir, addnodes
from sphinx.util import texescape
+from sphinx.locale import _
from sphinx.builders import Builder
from sphinx.environment import NoUri
from sphinx.util.nodes import inline_all_toctrees
diff --git a/sphinx/builders/manpage.py b/sphinx/builders/manpage.py
new file mode 100644
index 00000000..756e4732
--- /dev/null
+++ b/sphinx/builders/manpage.py
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.builders.manpage
+ ~~~~~~~~~~~~~~~~~~~~~~~
+
+ Manual pages builder.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from os import path
+
+from docutils.io import FileOutput
+from docutils.frontend import OptionParser
+
+from sphinx import addnodes
+from sphinx.errors import SphinxError
+from sphinx.builders import Builder
+from sphinx.environment import NoUri
+from sphinx.util.nodes import inline_all_toctrees
+from sphinx.util.console import bold, darkgreen
+from sphinx.writers.manpage import ManualPageWriter, has_manpage_writer
+
+
+class ManualPageBuilder(Builder):
+ """
+ Builds groff output in manual page format.
+ """
+ name = 'man'
+ format = 'man'
+ supported_image_types = []
+
+ def init(self):
+ if not has_manpage_writer:
+ raise SphinxError('The docutils manual page writer can\'t be '
+ 'found; it is only available as of docutils 0.6.')
+ if not self.config.man_pages:
+ self.warn('no "man_pages" config value found; no manual pages '
+ 'will be written')
+
+ def get_outdated_docs(self):
+ return 'all manpages' # for now
+
+ def get_target_uri(self, docname, typ=None):
+ if typ == 'token':
+ return ''
+ raise NoUri
+
+ def write(self, *ignored):
+ docwriter = ManualPageWriter(self)
+ docsettings = OptionParser(
+ defaults=self.env.settings,
+ components=(docwriter,)).get_default_values()
+
+ self.info(bold('writing... '), nonl=True)
+
+ for info in self.config.man_pages:
+ docname, name, description, authors, section = info
+ if isinstance(authors, basestring):
+ if authors:
+ authors = [authors]
+ else:
+ authors = []
+
+ targetname = '%s.%s' % (name, section)
+ self.info(darkgreen(targetname) + ' { ', nonl=True)
+ destination = FileOutput(
+ destination_path=path.join(self.outdir, targetname),
+ encoding='utf-8')
+
+ tree = self.env.get_doctree(docname)
+ docnames = set()
+ largetree = inline_all_toctrees(self, docnames, docname, tree,
+ darkgreen)
+ self.info('} ', nonl=True)
+ self.env.resolve_references(largetree, docname, self)
+ # remove pending_xref nodes
+ for pendingnode in largetree.traverse(addnodes.pending_xref):
+ pendingnode.replace_self(pendingnode.children)
+
+ largetree.settings = docsettings
+ largetree.settings.title = name
+ largetree.settings.subtitle = description
+ largetree.settings.authors = authors
+ largetree.settings.section = section
+
+ docwriter.write(largetree, destination)
+ self.info()
+
+ def finish(self):
+ pass
diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py
index 547bf2fd..72708803 100644
--- a/sphinx/builders/qthelp.py
+++ b/sphinx/builders/qthelp.py
@@ -18,6 +18,7 @@ from os import path
from docutils import nodes
from sphinx import addnodes
+from sphinx.locale import _
from sphinx.builders.html import StandaloneHTMLBuilder
_idpattern = re.compile(
@@ -129,9 +130,9 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
for node in tocdoc.traverse(istoctree):
sections.extend(self.write_toc(node))
- if self.config.html_use_modindex:
- item = section_template % {'title': _('Global Module Index'),
- 'ref': 'modindex.html'}
+ for index in self.domain_indices:
+ item = section_template % {'title': index[2],
+ 'ref': '%s-%s.html' % index[0:2]}
sections.append(' '*4*4 + item)
sections = '\n'.join(sections)
@@ -233,7 +234,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
shortname = shortname[:-2]
id = '%s.%s' % (id, shortname)
else:
- id = descr = None
+ id = None
if id:
item = ' '*12 + '<keyword name="%s" id="%s" ref="%s"/>' % (
diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py
index dc3269e2..e3e94465 100644
--- a/sphinx/cmdline.py
+++ b/sphinx/cmdline.py
@@ -43,6 +43,7 @@ new and changed files
-C -- use no config file at all, only -D options
-D <setting=value> -- override a setting in configuration
-A <name=value> -- pass a value into the templates, for HTML builder
+ -n -- nit-picky mode, warn about all missing references
-N -- do not do colored output
-q -- no output on stdout, just warnings on stderr
-Q -- no output at all, not even warnings
@@ -61,7 +62,7 @@ def main(argv):
nocolor()
try:
- opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:g:NEqQWw:P')
+ opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:ng:NEqQWw:P')
allopts = set(opt[0] for opt in opts)
srcdir = confdir = path.abspath(args[0])
if not path.isdir(srcdir):
@@ -89,8 +90,8 @@ def main(argv):
if err:
return 1
- buildername = all_files = None
- freshenv = warningiserror = use_pdb = False
+ buildername = None
+ force_all = freshenv = warningiserror = use_pdb = False
status = sys.stdout
warning = sys.stderr
error = sys.stderr
@@ -105,7 +106,7 @@ def main(argv):
if filenames:
usage(argv, 'Cannot combine -a option and filenames.')
return 1
- all_files = True
+ force_all = True
elif opt == '-t':
tags.append(val)
elif opt == '-d':
@@ -142,6 +143,8 @@ def main(argv):
except ValueError:
pass
confoverrides['html_context.%s' % key] = val
+ elif opt == '-n':
+ confoverrides['nitpicky'] = True
elif opt == '-N':
nocolor()
elif opt == '-E':
@@ -167,7 +170,7 @@ def main(argv):
app = Sphinx(srcdir, confdir, outdir, doctreedir, buildername,
confoverrides, status, warning, freshenv,
warningiserror, tags)
- app.build(all_files, filenames)
+ app.build(force_all, filenames)
return app.statuscode
except KeyboardInterrupt:
if use_pdb:
diff --git a/sphinx/config.py b/sphinx/config.py
index b81958df..24082b6c 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -60,7 +60,9 @@ class Config(object):
modindex_common_prefix = ([], 'html'),
rst_epilog = (None, 'env'),
trim_doctest_flags = (True, 'env'),
+ default_domain = ('py', 'env'),
needs_sphinx = (None, None),
+ nitpicky = (False, 'env'),
# HTML options
html_theme = ('default', 'html'),
@@ -80,7 +82,8 @@ class Config(object):
html_translator_class = (None, 'html'),
html_sidebars = ({}, 'html'),
html_additional_pages = ({}, 'html'),
- html_use_modindex = (True, 'html'),
+ html_use_modindex = (True, 'html'), # deprecated
+ html_domain_indices = (True, 'html'),
html_add_permalinks = (True, 'html'),
html_use_index = (True, 'html'),
html_split_index = (False, 'html'),
@@ -124,7 +127,8 @@ class Config(object):
latex_logo = (None, None),
latex_appendices = ([], None),
latex_use_parts = (False, None),
- latex_use_modindex = (True, None),
+ latex_use_modindex = (True, None), # deprecated
+ latex_domain_indices = (True, None),
# paper_size and font_size are still separate values
# so that you can give them easily on the command line
latex_paper_size = ('letter', None),
@@ -134,6 +138,13 @@ class Config(object):
latex_docclass = ({}, None),
# now deprecated - use latex_elements
latex_preamble = ('', None),
+
+ # text options
+ text_sectionchars = ('*=-~"+`', 'text'),
+ text_windows_newlines = (False, 'text'),
+
+ # manpage options
+ man_pages = ([], None),
)
def __init__(self, dirname, filename, overrides, tags):
diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py
index 00bb55ec..be603768 100644
--- a/sphinx/directives/__init__.py
+++ b/sphinx/directives/__init__.py
@@ -9,11 +9,15 @@
:license: BSD, see LICENSE for details.
"""
-from docutils.parsers.rst import directives
+import re
+
+from docutils.parsers.rst import Directive, directives
from docutils.parsers.rst.directives import images
+from sphinx import addnodes
+from sphinx.util.docfields import DocFieldTransformer
+
# import and register directives
-from sphinx.directives.desc import *
from sphinx.directives.code import *
from sphinx.directives.other import *
@@ -25,3 +29,170 @@ try:
except AttributeError:
images.figure.options['figwidth'] = \
directives.length_or_percentage_or_unitless
+
+
+# RE to strip backslash escapes
+strip_backslash_re = re.compile(r'\\(?=[^\\])')
+
+
+class ObjectDescription(Directive):
+ """
+ Directive to describe a class, function or similar object. Not used
+ directly, but subclassed (in domain-specific directives) to add custom
+ behavior.
+ """
+
+ has_content = True
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = True
+ option_spec = {
+ 'noindex': directives.flag,
+ }
+
+ # types of doc fields that this directive handles, see sphinx.util.docfields
+ doc_field_types = []
+
+ def get_signatures(self):
+ """
+ Retrieve the signatures to document from the directive arguments. By
+ default, signatures are given as arguments, one per line.
+ """
+ # remove backslashes to support (dummy) escapes; helps Vim highlighting
+ return [strip_backslash_re.sub('', sig.strip())
+ for sig in self.arguments[0].split('\n')]
+
+ def handle_signature(self, sig, signode):
+ """
+ Parse the signature *sig* into individual nodes and append them to
+ *signode*. If ValueError is raised, parsing is aborted and the whole
+ *sig* is put into a single desc_name node.
+
+ The return value should be a value that identifies the object. It is
+ passed to :meth:`add_target_and_index()` unchanged, and otherwise only
+ used to skip duplicates.
+ """
+ raise ValueError
+
+ def add_target_and_index(self, name, sig, signode):
+ """
+ Add cross-reference IDs and entries to self.indexnode, if applicable.
+
+ *name* is whatever :meth:`handle_signature()` returned.
+ """
+ return # do nothing by default
+
+ def before_content(self):
+ """
+ Called before parsing content. Used to set information about the current
+ directive context on the build environment.
+ """
+ pass
+
+ def after_content(self):
+ """
+ Called after parsing content. Used to reset information about the
+ current directive context on the build environment.
+ """
+ pass
+
+ def run(self):
+ """
+ Main directive entry function, called by docutils upon encountering the
+ directive.
+
+ This directive is meant to be quite easily subclassable, so it delegates
+ to several additional methods. What it does:
+
+ * find out if called as a domain-specific directive, set self.domain
+ * create a `desc` node to fit all description inside
+ * parse standard options, currently `noindex`
+ * create an index node if needed as self.indexnode
+ * parse all given signatures (as returned by self.get_signatures())
+ using self.handle_signature(), which should either return a name
+ or raise ValueError
+ * add index entries using self.add_target_and_index()
+ * parse the content and handle doc fields in it
+ """
+ if ':' in self.name:
+ self.domain, self.objtype = self.name.split(':', 1)
+ else:
+ self.domain, self.objtype = '', self.name
+ self.env = self.state.document.settings.env
+ self.indexnode = addnodes.index(entries=[])
+
+ node = addnodes.desc()
+ node.document = self.state.document
+ node['domain'] = self.domain
+ # 'desctype' is a backwards compatible attribute
+ node['objtype'] = node['desctype'] = self.objtype
+ node['noindex'] = noindex = ('noindex' in self.options)
+
+ self.names = []
+ signatures = self.get_signatures()
+ for i, sig in enumerate(signatures):
+ # add a signature node for each signature in the current unit
+ # and add a reference target for it
+ signode = addnodes.desc_signature(sig, '')
+ signode['first'] = False
+ node.append(signode)
+ try:
+ # name can also be a tuple, e.g. (classname, objname);
+ # this is strictly domain-specific (i.e. no assumptions may
+ # be made in this base class)
+ name = self.handle_signature(sig, signode)
+ except ValueError:
+ # signature parsing failed
+ signode.clear()
+ signode += addnodes.desc_name(sig, sig)
+ continue # we don't want an index entry here
+ if not noindex and name not in self.names:
+ # only add target and index entry if this is the first
+ # description of the object with this name in this desc block
+ self.names.append(name)
+ self.add_target_and_index(name, sig, signode)
+
+ contentnode = addnodes.desc_content()
+ node.append(contentnode)
+ if self.names:
+ # needed for association of version{added,changed} directives
+ self.env.temp_data['object'] = self.names[0]
+ self.before_content()
+ self.state.nested_parse(self.content, self.content_offset, contentnode)
+ #self.handle_doc_fields(contentnode)
+ DocFieldTransformer(self).transform_all(contentnode)
+ self.env.temp_data['object'] = None
+ self.after_content()
+ return [self.indexnode, node]
+
+# backwards compatible old name
+DescDirective = ObjectDescription
+
+
+class DefaultDomain(Directive):
+ """
+ Directive to (re-)set the default domain for this source file.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {}
+
+ def run(self):
+ env = self.state.document.settings.env
+ domain_name = self.arguments[0].lower()
+ # if domain_name not in env.domains:
+ # # try searching by label
+ # for domain in env.domains.itervalues():
+ # if domain.label.lower() == domain_name:
+ # domain_name = domain.name
+ # break
+ env.temp_data['default_domain'] = env.domains.get(domain_name)
+
+
+directives.register_directive('default-domain', DefaultDomain)
+directives.register_directive('describe', ObjectDescription)
+# new, more consistent, name
+directives.register_directive('object', ObjectDescription)
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index 5f2fd51e..5497a365 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -13,11 +13,10 @@ import codecs
from os import path
from docutils import nodes
-from docutils.parsers.rst import directives
+from docutils.parsers.rst import Directive, directives
from sphinx import addnodes
from sphinx.util import parselinenos
-from sphinx.util.compat import Directive, directive_dwim
class Highlight(Directive):
@@ -187,8 +186,8 @@ class LiteralInclude(Directive):
return [retnode]
-directives.register_directive('highlight', directive_dwim(Highlight))
-directives.register_directive('highlightlang', directive_dwim(Highlight)) # old
-directives.register_directive('code-block', directive_dwim(CodeBlock))
-directives.register_directive('sourcecode', directive_dwim(CodeBlock))
-directives.register_directive('literalinclude', directive_dwim(LiteralInclude))
+directives.register_directive('highlight', Highlight)
+directives.register_directive('highlightlang', Highlight) # old
+directives.register_directive('code-block', CodeBlock)
+directives.register_directive('sourcecode', CodeBlock)
+directives.register_directive('literalinclude', LiteralInclude)
diff --git a/sphinx/directives/desc.py b/sphinx/directives/desc.py
deleted file mode 100644
index 5a8ed791..00000000
--- a/sphinx/directives/desc.py
+++ /dev/null
@@ -1,771 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.directives.desc
- ~~~~~~~~~~~~~~~~~~~~~~
-
- :copyright: Copyright 2007-2010 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.util import ws_re
-from sphinx.util.compat import Directive, directive_dwim
-
-
-def _is_only_paragraph(node):
- """True if the node only contains one paragraph (and system messages)."""
- if len(node) == 0:
- return False
- elif len(node) > 1:
- for subnode in node[1:]:
- if not isinstance(subnode, nodes.system_message):
- return False
- if isinstance(node[0], nodes.paragraph):
- return True
- 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'\\(?=[^\\])')
-
-
-class DescDirective(Directive):
- """
- Directive to describe a class, function or similar object. Not used
- directly, but subclassed to add custom behavior.
- """
-
- has_content = True
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = True
- option_spec = {
- 'noindex': directives.flag,
- 'module': directives.unchanged,
- }
-
- _ = lambda x: x # make gettext extraction in constants possible
-
- doc_fields_with_arg = {
- 'param': '%param',
- 'parameter': '%param',
- 'arg': '%param',
- 'argument': '%param',
- 'keyword': '%param',
- 'kwarg': '%param',
- 'kwparam': '%param',
- 'type': '%type',
- 'raises': _('Raises'),
- 'raise': 'Raises',
- 'exception': 'Raises',
- 'except': 'Raises',
- 'var': _('Variable'),
- 'ivar': 'Variable',
- 'cvar': 'Variable',
- 'returns': _('Returns'),
- 'return': 'Returns',
- }
-
- doc_fields_with_linked_arg = ('raises', 'raise', 'exception', 'except')
-
- doc_fields_without_arg = {
- 'returns': 'Returns',
- 'return': 'Returns',
- 'rtype': _('Return type'),
- }
-
- def handle_doc_fields(self, node):
- """
- Convert field lists with known keys inside the description content into
- better-looking equivalents.
- """
- # don't traverse, only handle field lists that are immediate children
- for child in node.children:
- if not isinstance(child, nodes.field_list):
- continue
- params = []
- pfield = None
- param_nodes = {}
- param_types = {}
- new_list = nodes.field_list()
- for field in child:
- fname, fbody = field
- try:
- typ, obj = fname.astext().split(None, 1)
- typdesc = _(self.doc_fields_with_arg[typ])
- if _is_only_paragraph(fbody):
- children = fbody.children[0].children
- else:
- children = fbody.children
- if typdesc == '%param':
- if not params:
- # add the field that later gets all the parameters
- pfield = nodes.field()
- new_list += pfield
- dlitem = nodes.list_item()
- dlpar = nodes.paragraph()
- dlpar += nodes.emphasis(obj, obj)
- dlpar += nodes.Text(' -- ', ' -- ')
- dlpar += children
- param_nodes[obj] = dlpar
- dlitem += dlpar
- params.append(dlitem)
- elif typdesc == '%type':
- typenodes = fbody.children
- if _is_only_paragraph(fbody):
- typenodes = ([nodes.Text(' (')] +
- typenodes[0].children +
- [nodes.Text(')')])
- param_types[obj] = typenodes
- else:
- fieldname = typdesc + ' '
- nfield = nodes.field()
- nfieldname = nodes.field_name(fieldname, fieldname)
- nfield += nfieldname
- node = nfieldname
- if typ in self.doc_fields_with_linked_arg:
- node = addnodes.pending_xref(
- obj, reftype='obj', refcaption=False,
- reftarget=obj, modname=self.env.currmodule,
- classname=self.env.currclass)
- nfieldname += node
- node += nodes.Text(obj, obj)
- nfield += nodes.field_body()
- nfield[1] += fbody.children
- new_list += nfield
- except (KeyError, ValueError):
- fnametext = fname.astext()
- try:
- typ = _(self.doc_fields_without_arg[fnametext])
- except KeyError:
- # at least capitalize the field name
- typ = fnametext.capitalize()
- fname[0] = nodes.Text(typ)
- new_list += field
- if params:
- if len(params) == 1:
- pfield += nodes.field_name('', _('Parameter'))
- pfield += nodes.field_body()
- pfield[1] += params[0][0]
- else:
- pfield += nodes.field_name('', _('Parameters'))
- pfield += nodes.field_body()
- pfield[1] += nodes.bullet_list()
- pfield[1][0].extend(params)
-
- for param, type in param_types.iteritems():
- if param in param_nodes:
- param_nodes[param][1:1] = type
- child.replace_self(new_list)
-
- def get_signatures(self):
- """
- Retrieve the signatures to document from the directive arguments.
- """
- # remove backslashes to support (dummy) escapes; helps Vim highlighting
- return [strip_backslash_re.sub('', sig.strip())
- for sig in self.arguments[0].split('\n')]
-
- def parse_signature(self, sig, signode):
- """
- Parse the signature *sig* into individual nodes and append them to
- *signode*. If ValueError is raised, parsing is aborted and the whole
- *sig* is put into a single desc_name node.
- """
- raise ValueError
-
- def add_target_and_index(self, name, sig, signode):
- """
- Add cross-reference IDs and entries to self.indexnode, if applicable.
- """
- return # do nothing by default
-
- def before_content(self):
- """
- Called before parsing content. Used to set information about the current
- directive context on the build environment.
- """
- pass
-
- def after_content(self):
- """
- Called after parsing content. Used to reset information about the
- current directive context on the build environment.
- """
- pass
-
- def run(self):
- self.desctype = self.name
- self.env = self.state.document.settings.env
- self.indexnode = addnodes.index(entries=[])
-
- node = addnodes.desc()
- node.document = self.state.document
- node['desctype'] = self.desctype
- node['noindex'] = noindex = ('noindex' in self.options)
-
- self.names = []
- signatures = self.get_signatures()
- for i, sig in enumerate(signatures):
- # add a signature node for each signature in the current unit
- # and add a reference target for it
- signode = addnodes.desc_signature(sig, '')
- signode['first'] = False
- node.append(signode)
- try:
- # name can also be a tuple, e.g. (classname, objname)
- name = self.parse_signature(sig, signode)
- except ValueError, err:
- # signature parsing failed
- signode.clear()
- signode += addnodes.desc_name(sig, sig)
- continue # we don't want an index entry here
- if not noindex and name not in self.names:
- # only add target and index entry if this is the first
- # description of the object with this name in this desc block
- self.names.append(name)
- self.add_target_and_index(name, sig, signode)
-
- contentnode = addnodes.desc_content()
- node.append(contentnode)
- if self.names:
- # needed for association of version{added,changed} directives
- self.env.currdesc = self.names[0]
- self.before_content()
- self.state.nested_parse(self.content, self.content_offset, contentnode)
- self.handle_doc_fields(contentnode)
- self.env.currdesc = None
- self.after_content()
- 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).
- """
-
- def parse_signature(self, sig, signode):
- """Transform an option description into RST nodes."""
- count = 0
- firstname = ''
- for m in option_desc_re.finditer(sig):
- optname, args = m.groups()
- if count:
- signode += addnodes.desc_addname(', ', ', ')
- signode += addnodes.desc_name(optname, optname)
- signode += addnodes.desc_addname(args, args)
- if not count:
- firstname = optname
- count += 1
- if not firstname:
- raise ValueError
- return firstname
-
- def add_target_and_index(self, name, sig, signode):
- targetname = name.replace('/', '-')
- if self.env.currprogram:
- targetname = '-' + self.env.currprogram + targetname
- targetname = 'cmdoption' + targetname
- signode['ids'].append(targetname)
- self.state.document.note_explicit_target(signode)
- self.indexnode['entries'].append(
- ('pair', _('%scommand line option; %s') %
- ((self.env.currprogram and
- self.env.currprogram + ' ' or ''), sig),
- targetname, targetname))
- self.env.note_progoption(name, targetname)
-
-
-class GenericDesc(DescDirective):
- """
- A generic x-ref directive registered with Sphinx.add_description_unit().
- """
-
- def parse_signature(self, sig, signode):
- parse_node = additional_xref_types[self.desctype][2]
- if parse_node:
- name = parse_node(self.env, sig, signode)
- else:
- signode.clear()
- signode += addnodes.desc_name(sig, sig)
- # normalize whitespace like xfileref_role does
- name = ws_re.sub('', sig)
- return name
-
- def add_target_and_index(self, name, sig, signode):
- rolename, indextemplate = additional_xref_types[self.desctype][:2]
- targetname = '%s-%s' % (rolename, name)
- signode['ids'].append(targetname)
- self.state.document.note_explicit_target(signode)
- if indextemplate:
- indexentry = _(indextemplate) % (name,)
- indextype = 'single'
- colon = indexentry.find(':')
- if colon != -1:
- indextype = indexentry[:colon].strip()
- indexentry = indexentry[colon+1:].strip()
- self.indexnode['entries'].append((indextype, indexentry,
- targetname, targetname))
- self.env.note_reftarget(rolename, name, targetname)
-
-
-class Target(Directive):
- """
- Generic target for user-defined cross-reference types.
- """
-
- has_content = False
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = True
- option_spec = {}
-
- 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
- fullname = ws_re.sub('', self.arguments[0].strip())
- targetname = '%s-%s' % (rolename, fullname)
- node = nodes.target('', '', ids=[targetname])
- self.state.document.note_explicit_target(node)
- ret = [node]
- if indextemplate:
- indexentry = indextemplate % (fullname,)
- indextype = 'single'
- colon = indexentry.find(':')
- if colon != -1:
- indextype = indexentry[:colon].strip()
- indexentry = indexentry[colon+1:].strip()
- inode = addnodes.index(entries=[(indextype, indexentry,
- targetname, targetname)])
- ret.insert(0, inode)
- env.note_reftarget(rolename, fullname, targetname)
- return ret
-
-# 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),
-}
-
-del _
-
-
-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 4b82f4ab..138d10c8 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -7,16 +7,14 @@
:license: BSD, see LICENSE for details.
"""
-import re
-
from docutils import nodes
-from docutils.parsers.rst import directives
+from docutils.parsers.rst import Directive, directives
from sphinx import addnodes
-from sphinx.locale import pairindextypes
-from sphinx.util import ws_re, url_re, docname_join
+from sphinx.locale import pairindextypes, _
+from sphinx.util import url_re, docname_join
from sphinx.util.nodes import explicit_title_re
-from sphinx.util.compat import Directive, directive_dwim, make_admonition
+from sphinx.util.compat import make_admonition
from sphinx.util.matching import patfilter
@@ -48,7 +46,6 @@ class TocTree(Directive):
# and title may be None if the document's title is to be used
entries = []
includefiles = []
- includetitles = {}
all_docnames = env.found_docs.copy()
# don't add the currently visited file in catch-all patterns
all_docnames.remove(env.docname)
@@ -107,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
@@ -199,6 +127,8 @@ class Author(Directive):
text = _('Section author: ')
elif self.name == 'moduleauthor':
text = _('Module author: ')
+ elif self.name == 'codeauthor':
+ text = _('Code author: ')
else:
text = _('Author: ')
emph += nodes.Text(text, text)
@@ -208,27 +138,6 @@ class Author(Directive):
return [para] + messages
-class Program(Directive):
- """
- Directive to name the program for which options are documented.
- """
-
- has_content = False
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = True
- option_spec = {}
-
- def run(self):
- env = self.state.document.settings.env
- program = ws_re.sub('-', self.arguments[0].strip())
- if program == 'None':
- env.currprogram = None
- else:
- env.currprogram = program
- return []
-
-
class Index(Directive):
"""
Directive to add entries to the index.
@@ -247,8 +156,7 @@ class Index(Directive):
def run(self):
arguments = self.arguments[0].split('\n')
env = self.state.document.settings.env
- targetid = 'index-%s' % env.index_num
- env.index_num += 1
+ targetid = 'index-%s' % env.new_serialno('index')
targetnode = nodes.target('', '', ids=[targetid])
self.state.document.note_explicit_target(targetnode)
indexnode = addnodes.index()
@@ -305,7 +213,12 @@ class VersionChange(Directive):
else:
ret = [node]
env = self.state.document.settings.env
- env.note_versionchange(node['type'], node['version'], node, self.lineno)
+ env.versionchanges.setdefault(node['version'], []).append(
+ (node['type'], env.temp_data['docname'], self.lineno,
+ # XXX: python domain specific
+ env.temp_data.get('py:module'),
+ env.temp_data.get('object'),
+ node.astext()))
return ret
@@ -335,66 +248,6 @@ class SeeAlso(Directive):
return ret
-token_re = re.compile('`([a-z_]+)`')
-
-def token_xrefs(text, env):
- retnodes = []
- pos = 0
- for m in token_re.finditer(text):
- if m.start() > pos:
- txt = text[pos:m.start()]
- retnodes.append(nodes.Text(txt, txt))
- refnode = addnodes.pending_xref(m.group(1))
- refnode['reftype'] = 'token'
- refnode['reftarget'] = m.group(1)
- refnode['modname'] = env.currmodule
- refnode['classname'] = env.currclass
- refnode += nodes.literal(m.group(1), m.group(1), classes=['xref'])
- retnodes.append(refnode)
- pos = m.end()
- if pos < len(text):
- retnodes.append(nodes.Text(text[pos:], text[pos:]))
- return retnodes
-
-class ProductionList(Directive):
- """
- Directive to list grammar productions.
- """
-
- has_content = False
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = True
- option_spec = {}
-
- def run(self):
- env = self.state.document.settings.env
- node = addnodes.productionlist()
- messages = []
- i = 0
-
- for rule in self.arguments[0].split('\n'):
- if i == 0 and ':' not in rule:
- # production group
- continue
- i += 1
- try:
- name, tokens = rule.split(':', 1)
- except ValueError:
- break
- subnode = addnodes.production()
- subnode['tokenname'] = name.strip()
- if subnode['tokenname']:
- idname = 'grammar-token-%s' % subnode['tokenname']
- if idname not in self.state.document.ids:
- subnode['ids'].append(idname)
- self.state.document.note_implicit_target(subnode, subnode)
- env.note_reftarget('token', subnode['tokenname'], idname)
- subnode.extend(token_xrefs(tokens, env))
- node.append(subnode)
- return [node] + messages
-
-
class TabularColumns(Directive):
"""
Directive to give an explicit tabulary column definition to LaTeX.
@@ -412,57 +265,6 @@ class TabularColumns(Directive):
return [node]
-class Glossary(Directive):
- """
- Directive to create a glossary with cross-reference targets
- for :term: roles.
- """
-
- has_content = True
- required_arguments = 0
- optional_arguments = 0
- final_argument_whitespace = False
- option_spec = {
- 'sorted': directives.flag,
- }
-
- def run(self):
- env = self.state.document.settings.env
- node = addnodes.glossary()
- node.document = self.state.document
- self.state.nested_parse(self.content, self.content_offset, node)
-
- # the content should be definition lists
- dls = [child for child in node
- if isinstance(child, nodes.definition_list)]
- # now, extract definition terms to enable cross-reference creation
- new_dl = nodes.definition_list()
- new_dl['classes'].append('glossary')
- items = []
- for dl in dls:
- for li in dl.children:
- if not li.children or not isinstance(li[0], nodes.term):
- continue
- termtext = li.children[0].astext()
- new_id = 'term-' + nodes.make_id(termtext)
- if new_id in env.gloss_entries:
- new_id = 'term-' + str(len(env.gloss_entries))
- env.gloss_entries.add(new_id)
- li[0]['names'].append(new_id)
- li[0]['ids'].append(new_id)
- env.note_reftarget('term', termtext.lower(), new_id)
- # add an index entry too
- indexnode = addnodes.index()
- indexnode['entries'] = [('single', termtext, new_id, termtext)]
- li.insert(0, indexnode)
- items.append((termtext, li))
- if 'sorted' in self.options:
- items.sort(key=lambda x: x[0].lower())
- new_dl.extend(item[1] for item in items)
- node.children = [new_dl]
- return [node]
-
-
class Centered(Directive):
"""
Directive to create a centered line of bold text.
@@ -565,36 +367,24 @@ class Only(Directive):
return [node]
-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))
-directives.register_directive('index', directive_dwim(Index))
-directives.register_directive('deprecated', directive_dwim(VersionChange))
-directives.register_directive('versionadded', directive_dwim(VersionChange))
-directives.register_directive('versionchanged', directive_dwim(VersionChange))
-directives.register_directive('seealso', directive_dwim(SeeAlso))
-directives.register_directive('productionlist', directive_dwim(ProductionList))
-directives.register_directive('tabularcolumns', directive_dwim(TabularColumns))
-directives.register_directive('glossary', directive_dwim(Glossary))
-directives.register_directive('centered', directive_dwim(Centered))
-directives.register_directive('acks', directive_dwim(Acks))
-directives.register_directive('hlist', directive_dwim(HList))
-directives.register_directive('only', directive_dwim(Only))
+directives.register_directive('toctree', TocTree)
+directives.register_directive('sectionauthor', Author)
+directives.register_directive('moduleauthor', Author)
+directives.register_directive('codeauthor', Author)
+directives.register_directive('index', Index)
+directives.register_directive('deprecated', VersionChange)
+directives.register_directive('versionadded', VersionChange)
+directives.register_directive('versionchanged', VersionChange)
+directives.register_directive('seealso', SeeAlso)
+directives.register_directive('tabularcolumns', TabularColumns)
+directives.register_directive('centered', Centered)
+directives.register_directive('acks', Acks)
+directives.register_directive('hlist', HList)
+directives.register_directive('only', Only)
# register the standard rst class directive under a different name
-
-try:
- # docutils 0.4
- from docutils.parsers.rst.directives.misc import class_directive
- directives.register_directive('cssclass', class_directive)
-except ImportError:
- try:
- # docutils 0.5
- from docutils.parsers.rst.directives.misc import Class
- directives.register_directive('cssclass', Class)
- except ImportError:
- # whatever :)
- pass
+from docutils.parsers.rst.directives.misc import Class
+# only for backwards compatibility now
+directives.register_directive('cssclass', Class)
+# new standard name when default-domain with "class" is in effect
+directives.register_directive('rst-class', Class)
diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py
new file mode 100644
index 00000000..66e1f681
--- /dev/null
+++ b/sphinx/domains/__init__.py
@@ -0,0 +1,250 @@
+# -*- 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-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from sphinx.errors import SphinxError
+
+
+class ObjType(object):
+ """
+ An ObjType is the description for a type of object that a domain can
+ document. In the object_types attribute of Domain subclasses, object type
+ names are mapped to instances of this class.
+
+ Constructor arguments:
+
+ - *lname*: localized name of the type
+ - *roles*: all the roles that can refer to an object of this type
+ - *attrs*: object attributes -- currently only "searchprio" is known,
+ which defines the object's priority in the full-text search index,
+ see :meth:`Domain.get_objects()`.
+ """
+
+ known_attrs = {
+ 'searchprio': 1,
+ }
+
+ def __init__(self, lname, *roles, **attrs):
+ self.lname = lname
+ self.roles = roles
+ self.attrs = self.known_attrs.copy()
+ self.attrs.update(attrs)
+
+
+class Index(object):
+ """
+ An Index is the description for a domain-specific index. To add an index to
+ a domain, subclass Index, overriding the three name attributes:
+
+ * `name` is an identifier used for generating file names.
+ * `localname` is the section title for the index.
+ * `shortname` is a short name for the index, for use in the relation bar in
+ HTML output. Can be empty to disable entries in the relation bar.
+
+ and providing a :meth:`generate()` method. Then, add the index class to
+ your domain's `indices` list. Extensions can add indices to existing
+ domains using :meth:`~sphinx.application.Sphinx.add_index_to_domain()`.
+ """
+
+ name = None
+ localname = None
+ shortname = None
+
+ def __init__(self, domain):
+ if self.name is None or self.localname is None:
+ raise SphinxError('Index subclass %s has no valid name or localname'
+ % self.__class__.__name__)
+ self.domain = domain
+
+ def generate(self, docnames=None):
+ """
+ Return entries for the index given by *name*. If *docnames* is given,
+ restrict to entries referring to these docnames.
+
+ The return value is a tuple of ``(content, collapse)``, where *collapse*
+ is a boolean that determines if sub-entries should start collapsed (for
+ output formats that support collapsing sub-entries).
+
+ *content* is a sequence of ``(letter, entries)`` tuples, where *letter*
+ is the "heading" for the given *entries*, usually the starting letter.
+
+ *entries* is a sequence of single entries, where a single entry is a
+ sequence ``[name, subtype, docname, anchor, extra, qualifier, descr]``.
+ The items in this sequence have the following meaning:
+
+ - `name` -- the name of the index entry to be displayed
+ - `subtype` -- sub-entry related type:
+ 0 -- normal entry
+ 1 -- entry with sub-entries
+ 2 -- sub-entry
+ - `docname` -- docname where the entry is located
+ - `anchor` -- anchor for the entry within `docname`
+ - `extra` -- extra info for the entry
+ - `qualifier` -- qualifier for the description
+ - `descr` -- description for the entry
+
+ Qualifier and description are not rendered e.g. in LaTeX output.
+ """
+ return []
+
+
+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 `self.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'
+ :attr:`data_version` attribute. Otherwise, `IOError` is raised and the
+ pickled environment is discarded.
+ """
+
+ #: domain name: should be short, but unique
+ name = ''
+ #: domain label: longer, more descriptive (used in messages)
+ label = ''
+ #: type (usually directive) name -> ObjType instance
+ object_types = {}
+ #: directive name -> directive class
+ directives = {}
+ #: role name -> role callable
+ roles = {}
+ #: a list of Index subclasses
+ indices = []
+
+ #: data value for a fresh environment
+ initial_data = {}
+ #: data version, bump this when the format of `self.data` changes
+ 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 = {}
+ self._role2type = {}
+ for name, obj in self.object_types.iteritems():
+ for rolename in obj.roles:
+ self._role2type.setdefault(rolename, []).append(name)
+ self.objtypes_for_role = self._role2type.get
+
+ 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)
+ BaseDirective = self.directives[name]
+ class DirectiveAdapter(BaseDirective):
+ def run(self):
+ self.name = fullname
+ return BaseDirective.run(self)
+ self._directive_cache[name] = DirectiveAdapter
+ return DirectiveAdapter
+
+ # methods that should be overwritten
+
+ def clear_doc(self, docname):
+ """
+ Remove traces of a document in the domain-specific inventories.
+ """
+ pass
+
+ def resolve_xref(self, env, fromdocname, builder,
+ 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 :exc:`sphinx.environment.NoUri` to suppress
+ the 'missing-reference' event being emitted.
+ """
+ pass
+
+ def get_objects(self):
+ """
+ Return an iterable of "object descriptions", which are tuples with
+ five items:
+
+ * `name` -- fully qualified name
+ * `type` -- object type, a key in ``self.object_types``
+ * `docname` -- the document where it is to be found
+ * `anchor` -- the anchor name for the object
+ * `priority` -- how "important" the object is (determines placement
+ in search results)
+
+ - 1: default priority (placed before full-text matches)
+ - 0: object is important (placed before default-priority objects)
+ - 2: object is unimportant (placed after full-text matches)
+ - -1: object should not show up in search at all
+ """
+ return []
+
+
+from sphinx.domains.c import CDomain
+from sphinx.domains.cpp import CPPDomain
+from sphinx.domains.std import StandardDomain
+from sphinx.domains.python import PythonDomain
+
+BUILTIN_DOMAINS = {
+ 'std': StandardDomain,
+ 'py': PythonDomain,
+ 'c': CDomain,
+ 'cpp': CPPDomain
+}
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
new file mode 100644
index 00000000..1edec525
--- /dev/null
+++ b/sphinx/domains/c.py
@@ -0,0 +1,213 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.domains.c
+ ~~~~~~~~~~~~~~~~
+
+ The C language domain.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+import string
+
+from docutils import nodes
+
+from sphinx import addnodes
+from sphinx.roles import XRefRole
+from sphinx.locale import l_, _
+from sphinx.domains import Domain, ObjType
+from sphinx.directives import ObjectDescription
+from sphinx.util.nodes import make_refnode
+from sphinx.util.docfields import Field, TypedField
+
+
+# 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++)
+ (?: \((.*)\) )? # 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 CObject(ObjectDescription):
+ """
+ Description of a C language object.
+ """
+
+ doc_field_types = [
+ TypedField('parameter', label=l_('Parameters'),
+ names=('param', 'parameter', 'arg', 'argument'),
+ typerolename='type', typenames=('type',)),
+ Field('returnvalue', label=l_('Returns'), has_arg=False,
+ names=('returns', 'return')),
+ Field('returntype', label=l_('Return type'), has_arg=False,
+ names=('rtype',)),
+ ]
+
+ # 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 handle_signature(self, sig, signode):
+ """Transform a 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.objtype == 'function':
+ # 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.objtype == 'function':
+ return _('%s (C function)') % name
+ elif self.objtype == 'member':
+ return _('%s (C member)') % name
+ elif self.objtype == 'macro':
+ return _('%s (C macro)') % name
+ elif self.objtype == 'type':
+ return _('%s (C type)') % name
+ elif self.objtype == 'var':
+ 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.objtype)
+
+ 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'
+ object_types = {
+ 'function': ObjType(l_('C function'), 'func'),
+ 'member': ObjType(l_('C member'), 'member'),
+ 'macro': ObjType(l_('C macro'), 'macro'),
+ 'type': ObjType(l_('C type'), 'type'),
+ 'var': ObjType(l_('C variable'), 'data'),
+ }
+
+ directives = {
+ 'function': CObject,
+ 'member': CObject,
+ 'macro': CObject,
+ 'type': CObject,
+ 'var': CObject,
+ }
+ roles = {
+ 'func' : XRefRole(fix_parens=True),
+ 'member': XRefRole(),
+ 'macro': XRefRole(),
+ 'data': XRefRole(),
+ 'type': XRefRole(),
+ }
+ initial_data = {
+ 'objects': {}, # fullname -> docname, objtype
+ }
+
+ 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['objects']:
+ return None
+ obj = self.data['objects'][target]
+ return make_refnode(builder, fromdocname, obj[0], target,
+ contnode, target)
+
+ def get_objects(self):
+ for refname, (docname, type) in self.data['objects'].iteritems():
+ yield (refname, type, docname, refname, 1)
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
new file mode 100644
index 00000000..22b63953
--- /dev/null
+++ b/sphinx/domains/cpp.py
@@ -0,0 +1,1097 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.domains.cpp
+ ~~~~~~~~~~~~~~~~~~
+
+ The C++ language domain.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+import string
+from copy import deepcopy
+
+from docutils import nodes
+
+from sphinx import addnodes
+from sphinx.roles import XRefRole
+from sphinx.locale import l_, _
+from sphinx.domains import Domain, ObjType
+from sphinx.directives import ObjectDescription
+from sphinx.util.nodes import make_refnode
+from sphinx.util.compat import Directive
+from sphinx.util.docfields import Field, TypedField
+
+
+_identifier_re = re.compile(r'\b(~?[a-zA-Z_][a-zA-Z0-9_]*)\b')
+_whitespace_re = re.compile(r'\s+(?u)')
+_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
+ r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
+_visibility_re = re.compile(r'\b(public|private|protected)\b')
+_operator_re = re.compile(r'''(?x)
+ \[\s*\]
+ | \(\s*\)
+ | [!<>=/*%+|&^-]=?
+ | \+\+ | --
+ | (<<|>>)=? | ~ | && | \| | \|\|
+ | ->\*? | \,
+''')
+
+_id_shortwords = {
+ 'char': 'c',
+ 'signed char': 'c',
+ 'unsigned char': 'C',
+ 'int': 'i',
+ 'signed int': 'i',
+ 'unsigned int': 'U',
+ 'long': 'l',
+ 'signed long': 'l',
+ 'unsigned long': 'L',
+ 'bool': 'b',
+ 'size_t': 's',
+ 'std::string': 'ss',
+ 'std::ostream': 'os',
+ 'std::istream': 'is',
+ 'std::iostream': 'ios',
+ 'std::vector': 'v',
+ 'std::map': 'm',
+ 'operator[]': 'subscript-operator',
+ 'operator()': 'call-operator',
+ 'operator!': 'not-operator',
+ 'operator<': 'lt-operator',
+ 'operator<=': 'lte-operator',
+ 'operator>': 'gt-operator',
+ 'operator>=': 'gte-operator',
+ 'operator=': 'assign-operator',
+ 'operator/': 'div-operator',
+ 'operator*': 'mul-operator',
+ 'operator%': 'mod-operator',
+ 'operator+': 'add-operator',
+ 'operator-': 'sub-operator',
+ 'operator|': 'or-operator',
+ 'operator&': 'and-operator',
+ 'operator^': 'xor-operator',
+ 'operator&&': 'sand-operator',
+ 'operator||': 'sor-operator',
+ 'operator==': 'eq-operator',
+ 'operator!=': 'neq-operator',
+ 'operator<<': 'lshift-operator',
+ 'operator>>': 'rshift-operator',
+ 'operator-=': 'sub-assign-operator',
+ 'operator+=': 'add-assign-operator',
+ 'operator*-': 'mul-assign-operator',
+ 'operator/=': 'div-assign-operator',
+ 'operator%=': 'mod-assign-operator',
+ 'operator&=': 'and-assign-operator',
+ 'operator|=': 'or-assign-operator',
+ 'operator<<=': 'lshift-assign-operator',
+ 'operator>>=': 'rshift-assign-operator',
+ 'operator^=': 'xor-assign-operator',
+ 'operator,': 'comma-operator',
+ 'operator->': 'pointer-operator',
+ 'operator->*': 'pointer-by-pointer-operator',
+ 'operator~': 'inv-operator',
+ 'operator++': 'inc-operator',
+ 'operator--': 'dec-operator',
+ 'operator new': 'new-operator',
+ 'operator new[]': 'new-array-operator',
+ 'operator delete': 'delete-operator',
+ 'operator delete[]': 'delete-array-operator'
+}
+
+
+class DefinitionError(Exception):
+
+ def __init__(self, description):
+ self.description = description
+
+ def __unicode__(self):
+ return self.description
+
+ def __str__(self):
+ return unicode(self.encode('utf-8'))
+
+
+class DefExpr(object):
+
+ def __unicode__(self):
+ raise NotImplementedError()
+
+ def __eq__(self, other):
+ if type(self) is not type(other):
+ return False
+ try:
+ for key, value in self.__dict__.iteritems():
+ if value != getattr(other, value):
+ return False
+ except AttributeError:
+ return False
+ return True
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def clone(self):
+ """Close a definition expression node"""
+ return deepcopy(self)
+
+ def get_id(self):
+ """Returns the id for the node"""
+ return u''
+
+ def get_name(self):
+ """Returns the name. Returns either `None` or a node with
+ a name you might call :meth:`split_owner` on.
+ """
+ return None
+
+ def split_owner(self):
+ """Nodes returned by :meth:`get_name` can split off their
+ owning parent. This function returns the owner and the
+ name as a tuple of two items. If a node does not support
+ it, :exc:`NotImplementedError` is raised.
+ """
+ raise NotImplementedError()
+
+ def prefix(self, prefix):
+ """Prefixes a name node (a node returned by :meth:`get_name`)."""
+ raise NotImplementedError()
+
+ def __str__(self):
+ return unicode(self).encode('utf-8')
+
+ def __repr__(self):
+ return '<defexpr %s>' % self
+
+
+class PrimaryDefExpr(DefExpr):
+
+ def get_name(self):
+ return self
+
+ def split_owner(self):
+ return None, self
+
+ def prefix(self, prefix):
+ if isinstance(prefix, PathDefExpr):
+ prefix = prefix.clone()
+ prefix.path.append(self)
+ return prefix
+ return PathDefExpr([prefix, self])
+
+
+class NameDefExpr(PrimaryDefExpr):
+
+ def __init__(self, name):
+ self.name = name
+
+ def get_id(self):
+ name = _id_shortwords.get(self.name)
+ if name is not None:
+ return name
+ return self.name.replace(u' ', u'-')
+
+ def __unicode__(self):
+ return unicode(self.name)
+
+
+class PathDefExpr(PrimaryDefExpr):
+
+ def __init__(self, parts):
+ self.path = parts
+
+ def get_id(self):
+ rv = u'::'.join(x.get_id() for x in self.path)
+ return _id_shortwords.get(rv, rv)
+
+ def split_owner(self):
+ if len(self.path) > 1:
+ return PathDefExpr(self.path[:-1]), self.path[-1]
+ return None, self
+
+ def prefix(self, prefix):
+ if isinstance(prefix, PathDefExpr):
+ prefix = prefix.clone()
+ prefix.path.extend(self.path)
+ return prefix
+ return PathDefExpr([prefix] + self.path)
+
+ def __unicode__(self):
+ return u'::'.join(map(unicode, self.path))
+
+
+class TemplateDefExpr(PrimaryDefExpr):
+
+ def __init__(self, typename, args):
+ self.typename = typename
+ self.args = args
+
+ def split_owner(self):
+ owner, typename = self.typename.split_owner()
+ return owner, TemplateDefExpr(typename, self.args)
+
+ def get_id(self):
+ return u'%s:%s:' % (self.typename.get_id(),
+ u'.'.join(x.get_id() for x in self.args))
+
+ def __unicode__(self):
+ return u'%s<%s>' % (self.typename, u', '.join(map(unicode, self.args)))
+
+
+class WrappingDefExpr(DefExpr):
+
+ def __init__(self, typename):
+ self.typename = typename
+
+ def get_name(self):
+ return self.typename.get_name()
+
+
+class ModifierDefExpr(WrappingDefExpr):
+
+ def __init__(self, typename, modifiers):
+ WrappingDefExpr.__init__(self, typename)
+ self.modifiers = modifiers
+
+ def get_id(self):
+ pieces = [_id_shortwords.get(unicode(x), unicode(x))
+ for x in self.modifiers]
+ pieces.append(self.typename.get_id())
+ return u'-'.join(pieces)
+
+ def __unicode__(self):
+ return u' '.join(map(unicode, list(self.modifiers) + [self.typename]))
+
+
+class PtrDefExpr(WrappingDefExpr):
+
+ def get_id(self):
+ return self.typename.get_id() + u'P'
+
+ def __unicode__(self):
+ return u'%s*' % self.typename
+
+
+class RefDefExpr(WrappingDefExpr):
+
+ def get_id(self):
+ return self.typename.get_id() + u'R'
+
+ def __unicode__(self):
+ return u'%s&' % self.typename
+
+
+class ConstDefExpr(WrappingDefExpr):
+
+ def __init__(self, typename, prefix=False):
+ WrappingDefExpr.__init__(self, typename)
+ self.prefix = prefix
+
+ def get_id(self):
+ return self.typename.get_id() + u'C'
+
+ def __unicode__(self):
+ return (self.prefix and u'const %s' or u'%s const') % self.typename
+
+
+class CastOpDefExpr(PrimaryDefExpr):
+
+ def __init__(self, typename):
+ self.typename = typename
+
+ def get_id(self):
+ return u'castto-%s-operator' % self.typename.get_id()
+
+ def __unicode__(self):
+ return u'operator %s' % self.typename
+
+
+class ArgumentDefExpr(DefExpr):
+
+ def __init__(self, type, name, default=None):
+ self.name = name
+ self.type = type
+ self.default = default
+
+ def get_name(self):
+ return self.name.get_name()
+
+ def get_id(self):
+ return self.type.get_id()
+
+ def __unicode__(self):
+ return (self.type is not None and u'%s %s' % (self.type, self.name)
+ or unicode(self.name)) + (self.default is not None and
+ u'=%s' % self.default or u'')
+
+
+class NamedDefExpr(DefExpr):
+
+ def __init__(self, name, visibility, static):
+ self.name = name
+ self.visibility = visibility
+ self.static = static
+
+ def get_name(self):
+ return self.name.get_name()
+
+ def get_modifiers(self):
+ rv = []
+ if self.visibility != 'public':
+ rv.append(self.visibility)
+ if self.static:
+ rv.append(u'static')
+ return rv
+
+
+class TypeObjDefExpr(NamedDefExpr):
+
+ def __init__(self, name, visibility, static, typename):
+ NamedDefExpr.__init__(self, name, visibility, static)
+ self.typename = typename
+
+ def get_id(self):
+ if self.typename is None:
+ return self.name.get_id()
+ return u'%s__%s' % (self.name.get_id(), self.typename.get_id())
+
+ def __unicode__(self):
+ buf = self.get_modifiers()
+ if self.typename is None:
+ buf.append(unicode(self.name))
+ else:
+ buf.extend(map(unicode, (self.typename, self.name)))
+ return u' '.join(buf)
+
+
+class MemberObjDefExpr(NamedDefExpr):
+
+ def __init__(self, name, visibility, static, typename, value):
+ NamedDefExpr.__init__(self, name, visibility, static)
+ self.typename = typename
+ self.value = value
+
+ def get_id(self):
+ return u'%s__%s' % (self.name.get_id(), self.typename.get_id())
+
+ def __unicode__(self):
+ buf = self.get_modifiers()
+ buf.append(u'%s %s' % (self.typename, self.name))
+ if self.value is not None:
+ buf.append(u'= %s' % self.value)
+ return u' '.join(buf)
+
+
+class FuncDefExpr(NamedDefExpr):
+
+ def __init__(self, name, visibility, static, explicit, rv,
+ signature, const, pure_virtual):
+ NamedDefExpr.__init__(self, name, visibility, static)
+ self.rv = rv
+ self.signature = signature
+ self.explicit = explicit
+ self.const = const
+ self.pure_virtual = pure_virtual
+
+ def get_id(self):
+ return u'%s%s%s' % (
+ self.name.get_id(),
+ self.signature and u'__' +
+ u'.'.join(x.get_id() for x in self.signature) or u'',
+ self.const and u'C' or u''
+ )
+
+ def __unicode__(self):
+ buf = self.get_modifiers()
+ if self.explicit:
+ buf.append(u'explicit')
+ if self.rv is not None:
+ buf.append(unicode(self.rv))
+ buf.append(u'%s(%s)' % (self.name, u', '.join(
+ map(unicode, self.signature))))
+ if self.const:
+ buf.append(u'const')
+ if self.pure_virtual:
+ buf.append(u'= 0')
+ return u' '.join(buf)
+
+
+class ClassDefExpr(NamedDefExpr):
+
+ def __init__(self, name, visibility, static):
+ NamedDefExpr.__init__(self, name, visibility, static)
+
+ def get_id(self):
+ return self.name.get_id()
+
+ def __unicode__(self):
+ buf = self.get_modifiers()
+ buf.append(unicode(self.name))
+ return u' '.join(buf)
+
+
+class DefinitionParser(object):
+
+ # mapping of valid type modifiers. if the set is None it means
+ # the modifier can prefix all types, otherwise only the types
+ # (actually more keywords) in the set. Also check
+ # _guess_typename when changing this.
+ _modifiers = {
+ 'volatile': None,
+ 'register': None,
+ 'mutable': None,
+ 'const': None,
+ 'typename': None,
+ 'unsigned': set(('char', 'int', 'long')),
+ 'signed': set(('char', 'int', 'long')),
+ 'short': set(('int', 'short')),
+ 'long': set(('int', 'long', 'double'))
+ }
+
+ def __init__(self, definition):
+ self.definition = definition.strip()
+ self.pos = 0
+ self.end = len(self.definition)
+ self.last_match = None
+ self._previous_state = (0, None)
+
+ def fail(self, msg):
+ raise DefinitionError('Invalid definition: %s [error at %d]\n %s' %
+ (msg, self.pos, self.definition))
+
+ def match(self, regex):
+ match = regex.match(self.definition, self.pos)
+ if match is not None:
+ self._previous_state = (self.pos, self.last_match)
+ self.pos = match.end()
+ self.last_match = match
+ return True
+ return False
+
+ def backout(self):
+ self.pos, self.last_match = self._previous_state
+
+ def skip_string(self, string):
+ strlen = len(string)
+ if self.definition[self.pos:self.pos + strlen] == string:
+ self.pos += strlen
+ return True
+ return False
+
+ def skip_word(self, word):
+ return self.match(re.compile(r'\b%s\b' % re.escape(word)))
+
+ def skip_ws(self):
+ return self.match(_whitespace_re)
+
+ @property
+ def eof(self):
+ return self.pos >= self.end
+
+ @property
+ def current_char(self):
+ try:
+ return self.definition[self.pos]
+ except IndexError:
+ return 'EOF'
+
+ @property
+ def matched_text(self):
+ if self.last_match is not None:
+ return self.last_match.group()
+
+ def _parse_operator(self):
+ self.skip_ws()
+ # thank god, a regular operator definition
+ if self.match(_operator_re):
+ return NameDefExpr('operator' +
+ _whitespace_re.sub('', self.matched_text))
+
+ # new/delete operator?
+ for allocop in 'new', 'delete':
+ if not self.skip_word(allocop):
+ continue
+ self.skip_ws()
+ if self.skip_string('['):
+ self.skip_ws()
+ if not self.skip_string(']'):
+ self.fail('expected "]" for ' + allocop)
+ allocop += '[]'
+ return NameDefExpr('operator ' + allocop)
+
+ # oh well, looks like a cast operator definition.
+ # In that case, eat another type.
+ type = self._parse_type()
+ return CastOpDefExpr(type)
+
+ def _parse_name(self):
+ if not self.match(_identifier_re):
+ self.fail('expected name')
+ identifier = self.matched_text
+
+ # strictly speaking, operators are not regular identifiers
+ # but because operator is a keyword, it might not be used
+ # for variable names anyways, so we can safely parse the
+ # operator here as identifier
+ if identifier == 'operator':
+ return self._parse_operator()
+
+ return NameDefExpr(identifier)
+
+ def _guess_typename(self, path):
+ if not path:
+ return [], 'int'
+ # for the long type, we don't want the int in there
+ if 'long' in path:
+ path = [x for x in path if x != 'int']
+ # remove one long
+ path.remove('long')
+ return path, 'long'
+ if path[-1] in ('int', 'char'):
+ return path[:-1], path[-1]
+ return path, 'int'
+
+ def _attach_crefptr(self, expr, is_const=False):
+ if is_const:
+ expr = ConstDefExpr(expr, prefix=True)
+ while 1:
+ self.skip_ws()
+ if self.skip_word('const'):
+ expr = ConstDefExpr(expr)
+ elif self.skip_string('*'):
+ expr = PtrDefExpr(expr)
+ elif self.skip_string('&'):
+ expr = RefDefExpr(expr)
+ else:
+ return expr
+
+ def _peek_const(self, path):
+ try:
+ path.remove('const')
+ return True
+ except ValueError:
+ return False
+
+ def _parse_builtin(self, modifier):
+ path = [modifier]
+ following = self._modifiers[modifier]
+ while 1:
+ self.skip_ws()
+ if not self.match(_identifier_re):
+ break
+ identifier = self.matched_text
+ if identifier in following:
+ path.append(identifier)
+ following = self._modifiers[modifier]
+ assert following
+ else:
+ self.backout()
+ break
+
+ is_const = self._peek_const(path)
+ modifiers, typename = self._guess_typename(path)
+ rv = ModifierDefExpr(NameDefExpr(typename), modifiers)
+ return self._attach_crefptr(rv, is_const)
+
+ def _parse_type_expr(self):
+ typename = self._parse_name()
+ self.skip_ws()
+ if not self.skip_string('<'):
+ return typename
+
+ args = []
+ while 1:
+ self.skip_ws()
+ if self.skip_string('>'):
+ break
+ if args:
+ if not self.skip_string(','):
+ self.fail('"," or ">" in template expected')
+ self.skip_ws()
+ args.append(self._parse_type(True))
+ return TemplateDefExpr(typename, args)
+
+ def _parse_type(self, in_template=False):
+ self.skip_ws()
+ result = []
+ modifiers = []
+
+ # if there is a leading :: or not, we don't care because we
+ # treat them exactly the same. Buf *if* there is one, we
+ # don't have to check for type modifiers
+ if not self.skip_string('::'):
+ self.skip_ws()
+ while self.match(_identifier_re):
+ modifier = self.matched_text
+ if modifier in self._modifiers:
+ following = self._modifiers[modifier]
+ # if the set is not none, there is a limited set
+ # of types that might follow. It is technically
+ # impossible for a template to follow, so what
+ # we do is go to a different function that just
+ # eats types
+ if following is not None:
+ return self._parse_builtin(modifier)
+ modifiers.append(modifier)
+ else:
+ self.backout()
+ break
+
+ while 1:
+ self.skip_ws()
+ if (in_template and self.current_char in ',>') or \
+ (result and not self.skip_string('::')) or \
+ self.eof:
+ break
+ result.append(self._parse_type_expr())
+
+ if not result:
+ self.fail('expected type')
+ if len(result) == 1:
+ rv = result[0]
+ else:
+ rv = PathDefExpr(result)
+ is_const = self._peek_const(modifiers)
+ if modifiers:
+ rv = ModifierDefExpr(rv, modifiers)
+ return self._attach_crefptr(rv, is_const)
+
+ def _parse_default_expr(self):
+ self.skip_ws()
+ if self.match(_string_re):
+ return self.matched_text
+ idx1 = self.definition.find(',', self.pos)
+ idx2 = self.definition.find(')', self.pos)
+ if idx1 < 0:
+ idx = idx2
+ elif idx2 < 0:
+ idx = idx1
+ else:
+ idx = min(idx1, idx2)
+ if idx < 0:
+ self.fail('unexpected end in default expression')
+ rv = self.definition[self.pos:idx]
+ self.pos = idx
+ return rv
+
+ def _parse_signature(self):
+ self.skip_ws()
+ if not self.skip_string('('):
+ self.fail('expected parentheses for function')
+
+ args = []
+ while 1:
+ self.skip_ws()
+ if self.eof:
+ self.fail('missing closing parentheses')
+ if self.skip_string(')'):
+ break
+ if args:
+ if not self.skip_string(','):
+ self.fail('expected comma between arguments')
+ self.skip_ws()
+
+ argname = self._parse_type()
+ argtype = default = None
+ self.skip_ws()
+ if self.skip_string('='):
+ self.pos += 1
+ default = self._parse_default_expr()
+ elif self.current_char not in ',)':
+ argtype = argname
+ argname = self._parse_name()
+ self.skip_ws()
+ if self.skip_string('='):
+ default = self._parse_default_expr()
+
+ args.append(ArgumentDefExpr(argtype, argname, default))
+ self.skip_ws()
+ const = self.skip_word('const')
+ if const:
+ self.skip_ws()
+ if self.skip_string('='):
+ self.skip_ws()
+ if not (self.skip_string('0') or \
+ self.skip_word('NULL') or \
+ self.skip_word('nullptr')):
+ self.fail('pure virtual functions must be defined with '
+ 'either 0, NULL or nullptr, other macros are '
+ 'not allowed')
+ pure_virtual = True
+ else:
+ pure_virtual = False
+ return args, const, pure_virtual
+
+ def _parse_visibility_static(self):
+ visibility = 'public'
+ if self.match(_visibility_re):
+ visibility = self.matched_text
+ static = self.skip_word('static')
+ return visibility, static
+
+ def parse_type(self):
+ return self._parse_type()
+
+ def parse_type_object(self):
+ visibility, static = self._parse_visibility_static()
+ typename = self._parse_type()
+ self.skip_ws()
+ if not self.eof:
+ name = self._parse_type()
+ else:
+ name = typename
+ typename = None
+ return TypeObjDefExpr(name, visibility, static, typename)
+
+ def parse_member_object(self):
+ visibility, static = self._parse_visibility_static()
+ typename = self._parse_type()
+ name = self._parse_type()
+ self.skip_ws()
+ if self.skip_string('='):
+ value = self.read_rest().strip()
+ else:
+ value = None
+ return MemberObjDefExpr(name, visibility, static, typename, value)
+
+ def parse_function(self):
+ visibility, static = self._parse_visibility_static()
+ if self.skip_word('explicit'):
+ explicit = True
+ self.skip_ws()
+ else:
+ explicit = False
+ rv = self._parse_type()
+ self.skip_ws()
+ # some things just don't have return values
+ if self.current_char == '(':
+ name = rv
+ rv = None
+ else:
+ name = self._parse_type()
+ return FuncDefExpr(name, visibility, static, explicit, rv,
+ *self._parse_signature())
+
+ def parse_class(self):
+ visibility, static = self._parse_visibility_static()
+ return ClassDefExpr(self._parse_type(), visibility, static)
+
+ def read_rest(self):
+ rv = self.definition[self.pos:]
+ self.pos = self.end
+ return rv
+
+ def assert_end(self):
+ self.skip_ws()
+ if not self.eof:
+ self.fail('expected end of definition, got %r' %
+ self.definition[self.pos:])
+
+
+class CPPObject(ObjectDescription):
+ """Description of a C++ language object."""
+
+ def attach_name(self, node, name):
+ owner, name = name.split_owner()
+ varname = unicode(name)
+ if owner is not None:
+ owner = unicode(owner) + '::'
+ node += addnodes.desc_addname(owner, owner)
+ node += addnodes.desc_name(varname, varname)
+
+ def attach_type(self, node, type):
+ # XXX: link to c?
+ text = unicode(type)
+ pnode = addnodes.pending_xref(
+ '', refdomain='cpp', reftype='type',
+ reftarget=text, modname=None, classname=None)
+ pnode['cpp:parent'] = self.env.temp_data.get('cpp:parent')
+ pnode += nodes.Text(text)
+ node += pnode
+
+ def attach_modifiers(self, node, obj):
+ if obj.visibility != 'public':
+ node += addnodes.desc_annotation(obj.visibility,
+ obj.visibility)
+ node += nodes.Text(' ')
+ if obj.static:
+ node += addnodes.desc_annotation('static', 'static')
+ node += nodes.Text(' ')
+
+ def add_target_and_index(self, sigobj, sig, signode):
+ theid = sigobj.get_id()
+ name = unicode(sigobj.name)
+ signode['names'].append(theid)
+ signode['ids'].append(theid)
+ signode['first'] = (not self.names)
+ self.state.document.note_explicit_target(signode)
+ self.env.domaindata['cpp']['objects'][name] = \
+ (self.env.docname, self.objtype)
+
+ indextext = self.get_index_text(name)
+ if indextext:
+ self.indexnode['entries'].append(('single', indextext, name, name))
+
+ def before_content(self):
+ lastname = self.names and self.names[-1]
+ if lastname and not self.env.temp_data.get('cpp:parent'):
+ assert isinstance(lastname, NamedDefExpr)
+ self.env.temp_data['cpp:parent'] = lastname.name
+ self.parentname_set = True
+ else:
+ self.parentname_set = False
+
+ def after_content(self):
+ if self.parentname_set:
+ self.env.temp_data['cpp:parent'] = None
+
+ def parse_definition(self, parser):
+ raise NotImplementedError()
+
+ def describe_signature(self, signode, arg):
+ raise NotImplementedError()
+
+ def handle_signature(self, sig, signode):
+ parser = DefinitionParser(sig)
+ try:
+ rv = self.parse_definition(parser)
+ parser.assert_end()
+ except DefinitionError, e:
+ self.env.warn(self.env.docname,
+ e.description, self.lineno)
+ raise ValueError
+ self.describe_signature(signode, rv)
+
+ parent = self.env.temp_data.get('cpp:parent')
+ if parent is not None:
+ rv = rv.clone()
+ rv.name = rv.name.prefix(parent)
+ return rv
+
+
+class CPPClassObject(CPPObject):
+
+ def get_index_text(self, name):
+ return _('%s (C++ class)') % name
+
+ def parse_definition(self, parser):
+ return parser.parse_class()
+
+ def describe_signature(self, signode, cls):
+ self.attach_modifiers(signode, cls)
+ signode += addnodes.desc_annotation('class ', 'class ')
+ self.attach_name(signode, cls.name)
+
+
+class CPPTypeObject(CPPObject):
+
+ def get_index_text(self, name):
+ if self.objtype == 'type':
+ return _('%s (C++ type)') % name
+ return ''
+
+ def parse_definition(self, parser):
+ return parser.parse_type_object()
+
+ def describe_signature(self, signode, obj):
+ self.attach_modifiers(signode, obj)
+ signode += addnodes.desc_annotation('type ', 'type ')
+ if obj.typename is not None:
+ self.attach_type(signode, obj.typename)
+ signode += nodes.Text(' ')
+ self.attach_name(signode, obj.name)
+
+
+class CPPMemberObject(CPPObject):
+
+ def get_index_text(self, name):
+ if self.objtype == 'member':
+ return _('%s (C++ member)') % name
+ return ''
+
+ def parse_definition(self, parser):
+ return parser.parse_member_object()
+
+ def describe_signature(self, signode, obj):
+ self.attach_modifiers(signode, obj)
+ self.attach_type(signode, obj.typename)
+ signode += nodes.Text(' ')
+ self.attach_name(signode, obj.name)
+ if obj.value is not None:
+ signode += nodes.Text(u' = ' + obj.value)
+
+
+class CPPFunctionObject(CPPObject):
+
+ def attach_function(self, node, func):
+ owner, name = func.name.split_owner()
+ if owner is not None:
+ owner = unicode(owner) + '::'
+ node += addnodes.desc_addname(owner, owner)
+
+ # cast operator is special. in this case the return value
+ # is reversed.
+ if isinstance(name, CastOpDefExpr):
+ node += addnodes.desc_name('operator', 'operator')
+ node += nodes.Text(u' ')
+ self.attach_type(node, name.typename)
+ else:
+ funcname = unicode(name)
+ node += addnodes.desc_name(funcname, funcname)
+
+ paramlist = addnodes.desc_parameterlist()
+ for arg in func.signature:
+ param = addnodes.desc_parameter('', '', noemph=True)
+ if arg.type is not None:
+ self.attach_type(param, arg.type)
+ param += nodes.Text(u' ')
+ param += nodes.emphasis(unicode(arg.name), unicode(arg.name))
+ if arg.default is not None:
+ def_ = u'=' + unicode(arg.default)
+ param += nodes.emphasis(def_, def_)
+ paramlist += param
+
+ node += paramlist
+ if func.const:
+ node += addnodes.desc_addname(' const', ' const')
+ if func.pure_virtual:
+ node += addnodes.desc_addname(' = 0', ' = 0')
+
+ def get_index_text(self, name):
+ return _('%s (C++ function)') % name
+
+ def parse_definition(self, parser):
+ return parser.parse_function()
+
+ def describe_signature(self, signode, func):
+ self.attach_modifiers(signode, func)
+ if func.explicit:
+ signode += addnodes.desc_annotation('explicit', 'explicit')
+ signode += nodes.Text(' ')
+ # return value is None for things with a reverse return value
+ # such as casting operator definitions or constructors
+ # and destructors.
+ if func.rv is not None:
+ self.attach_type(signode, func.rv)
+ signode += nodes.Text(u' ')
+ self.attach_function(signode, func)
+
+
+class CPPCurrentNamespace(Directive):
+ """This directive is just to tell Sphinx that we're documenting
+ stuff in namespace foo.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = True
+ option_spec = {}
+
+ def run(self):
+ env = self.state.document.settings.env
+ if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
+ env.temp_data['cpp:prefix'] = None
+ else:
+ parser = DefinitionParser(self.arguments[0])
+ try:
+ prefix = parser.parse_type()
+ parser.assert_end()
+ except DefinitionError, e:
+ self.env.warn(self.env.docname,
+ e.description, self.lineno)
+ else:
+ env.temp_data['cpp:prefix'] = prefix
+ return []
+
+
+class CPPXRefRole(XRefRole):
+
+ def process_link(self, env, refnode, has_explicit_title, title, target):
+ refnode['cpp:parent'] = env.temp_data.get('cpp:parent')
+ if not has_explicit_title:
+ 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[:1] == '~':
+ title = title[1:]
+ dcolon = title.rfind('::')
+ if dcolon != -1:
+ title = title[dcolon + 2:]
+ return title, target
+
+
+class CPPDomain(Domain):
+ """C++ language domain."""
+ name = 'cpp'
+ label = 'C++'
+ object_types = {
+ 'class': ObjType(l_('C++ class'), 'class'),
+ 'function': ObjType(l_('C++ function'), 'func'),
+ 'member': ObjType(l_('C++ member'), 'member'),
+ 'type': ObjType(l_('C++ type'), 'type')
+ }
+
+ directives = {
+ 'class': CPPClassObject,
+ 'function': CPPFunctionObject,
+ 'member': CPPMemberObject,
+ 'type': CPPTypeObject,
+ 'namespace': CPPCurrentNamespace
+ }
+ roles = {
+ 'class': CPPXRefRole(),
+ 'func' : CPPXRefRole(fix_parens=True),
+ 'member': CPPXRefRole(),
+ 'type': CPPXRefRole()
+ }
+ initial_data = {
+ 'objects': {}, # fullname -> docname, objtype
+ }
+
+ 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):
+ def _create_refnode(expr):
+ name = unicode(expr)
+ if name not in self.data['objects']:
+ return None
+ obj = self.data['objects'][name]
+ if obj[1] != typ:
+ return None
+ return make_refnode(builder, fromdocname, obj[0], expr.get_id(),
+ contnode, name)
+
+ parser = DefinitionParser(target)
+ # XXX: warn?
+ try:
+ expr = parser.parse_type().get_name()
+ parser.skip_ws()
+ if not parser.eof or expr is None:
+ return None
+ except DefinitionError:
+ return None
+
+ parent = node['cpp:parent']
+
+ rv = _create_refnode(expr)
+ if rv is not None or parent is None:
+ return rv
+ parent = parent.get_name()
+
+ rv = _create_refnode(expr.prefix(parent))
+ if rv is not None:
+ return rv
+
+ parent, name = parent.split_owner()
+ return _create_refnode(expr.prefix(parent))
+
+ def get_objects(self):
+ for refname, (docname, type) in self.data['objects'].iteritems():
+ yield (refname, type, docname, refname, 1)
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
new file mode 100644
index 00000000..de1ab84c
--- /dev/null
+++ b/sphinx/domains/python.py
@@ -0,0 +1,621 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.domains.python
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ The Python domain.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+
+from sphinx import addnodes
+from sphinx.roles import XRefRole
+from sphinx.locale import l_, _
+from sphinx.domains import Domain, ObjType, Index
+from sphinx.directives import ObjectDescription
+from sphinx.util.nodes import make_refnode
+from sphinx.util.compat import Directive
+from sphinx.util.docfields import Field, GroupedField, TypedField
+
+
+# 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 PyObject(ObjectDescription):
+ """
+ Description of a general Python object.
+ """
+ option_spec = {
+ 'noindex': directives.flag,
+ 'module': directives.unchanged,
+ }
+
+ doc_field_types = [
+ TypedField('parameter', label=l_('Parameters'),
+ names=('param', 'parameter', 'arg', 'argument',
+ 'keyword', 'kwarg', 'kwparam'),
+ typerolename='obj', typenames=('paramtype', 'type')),
+ TypedField('variable', label=l_('Variables'), rolename='obj',
+ names=('var', 'ivar', 'cvar'),
+ typerolename='obj', typenames=('vartype',)),
+ GroupedField('exceptions', label=l_('Raises'), rolename='exc',
+ names=('raises', 'raise', 'exception', 'except'),
+ can_collapse=True),
+ Field('returnvalue', label=l_('Returns'), has_arg=False,
+ names=('returns', 'return')),
+ Field('returntype', label=l_('Return type'), has_arg=False,
+ names=('rtype',)),
+ ]
+
+ 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 handle_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
+ name_prefix, name, arglist, retann = m.groups()
+
+ # determine module and class name (if applicable), as well as full name
+ modname = self.options.get(
+ 'module', self.env.temp_data.get('py:module'))
+ classname = self.env.temp_data.get('py:class')
+ if classname:
+ add_module = False
+ if name_prefix and name_prefix.startswith(classname):
+ fullname = name_prefix + name
+ # class name is given again in the signature
+ name_prefix = name_prefix[len(classname):].lstrip('.')
+ elif name_prefix:
+ # class name is given in the signature, but different
+ # (shouldn't happen)
+ fullname = classname + '.' + name_prefix + name
+ else:
+ # class name is not given in the signature
+ fullname = classname + '.' + name
+ else:
+ add_module = True
+ if name_prefix:
+ classname = name_prefix.rstrip('.')
+ fullname = name_prefix + name
+ else:
+ classname = ''
+ fullname = name
+
+ signode['module'] = modname
+ signode['class'] = classname
+ signode['fullname'] = fullname
+
+ sig_prefix = self.get_signature_prefix(sig)
+ if sig_prefix:
+ signode += addnodes.desc_annotation(sig_prefix, sig_prefix)
+
+ if name_prefix:
+ signode += addnodes.desc_addname(name_prefix, name_prefix)
+ # 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.temp_data.get('py:module'))
+ 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, name_prefix
+ 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, name_prefix
+
+ 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.temp_data.get('py:module'))
+ 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.objtype)
+
+ 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.temp_data['py:class'] = None
+
+
+class PyModulelevel(PyObject):
+ """
+ Description of an object on module level (functions, data).
+ """
+
+ def needs_arglist(self):
+ return self.objtype == 'function'
+
+ def get_index_text(self, modname, name_cls):
+ if self.objtype == 'function':
+ if not modname:
+ return _('%s() (built-in function)') % name_cls[0]
+ return _('%s() (in module %s)') % (name_cls[0], modname)
+ elif self.objtype == 'data':
+ if not modname:
+ return _('%s (built-in variable)') % name_cls[0]
+ return _('%s (in module %s)') % (name_cls[0], modname)
+ else:
+ return ''
+
+
+class PyClasslike(PyObject):
+ """
+ Description of a class-like object (classes, interfaces, exceptions).
+ """
+
+ def get_signature_prefix(self, sig):
+ return self.objtype + ' '
+
+ def get_index_text(self, modname, name_cls):
+ if self.objtype == 'class':
+ if not modname:
+ return _('%s (built-in class)') % name_cls[0]
+ return _('%s (class in %s)') % (name_cls[0], modname)
+ elif self.objtype == 'exception':
+ return name_cls[0]
+ else:
+ return ''
+
+ def before_content(self):
+ PyObject.before_content(self)
+ if self.names:
+ self.env.temp_data['py:class'] = self.names[0][0]
+ self.clsname_set = True
+
+
+class PyClassmember(PyObject):
+ """
+ Description of a class member (methods, attributes).
+ """
+
+ def needs_arglist(self):
+ return self.objtype.endswith('method')
+
+ def get_signature_prefix(self, sig):
+ if self.objtype == 'staticmethod':
+ return 'static '
+ elif self.objtype == '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.objtype == '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.objtype == '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.objtype == '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.objtype == '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):
+ PyObject.before_content(self)
+ lastname = self.names and self.names[-1][1]
+ if lastname and not self.env.temp_data.get('py:class'):
+ self.env.temp_data['py:class'] = lastname.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.temp_data['py:module'] = modname
+ env.domaindata['py']['modules'][modname] = \
+ (env.docname, self.options.get('synopsis', ''),
+ self.options.get('platform', ''), 'deprecated' in self.options)
+ targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
+ self.state.document.note_explicit_target(targetnode)
+ ret = [targetnode]
+ # XXX this behavior of the module directive is a mess...
+ if 'platform' in self.options:
+ platform = self.options['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.append(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.temp_data['py:module'] = None
+ else:
+ env.temp_data['py:module'] = modname
+ return []
+
+
+class PyXRefRole(XRefRole):
+ def process_link(self, env, refnode, has_explicit_title, title, target):
+ refnode['py:module'] = env.temp_data.get('py:module')
+ refnode['py:class'] = env.temp_data.get('py:class')
+ 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:]
+ refnode['refspecific'] = True
+ return title, target
+
+
+class PythonModuleIndex(Index):
+ """
+ Index subclass to provide the Python module index.
+ """
+
+ name = 'modindex'
+ localname = l_('Python Module Index')
+ shortname = l_('modules')
+
+ def generate(self, docnames=None):
+ content = {}
+ # list of prefixes to ignore
+ ignores = self.domain.env.config['modindex_common_prefix']
+ ignores = sorted(ignores, key=len, reverse=True)
+ # list of all modules, sorted by module name
+ modules = sorted(self.domain.data['modules'].iteritems(),
+ key=lambda x: x[0].lower())
+ # sort out collapsable modules
+ prev_modname = ''
+ num_toplevels = 0
+ for modname, (docname, synopsis, platforms, deprecated) in modules:
+ if docnames and docname not in docnames:
+ continue
+
+ for ignore in ignores:
+ if modname.startswith(ignore):
+ modname = modname[len(ignore):]
+ stripped = ignore
+ break
+ else:
+ stripped = ''
+
+ # we stripped the whole module name?
+ if not modname:
+ modname, stripped = stripped, ''
+
+ entries = content.setdefault(modname[0].lower(), [])
+
+ package = modname.split('.')[0]
+ if package != modname:
+ # it's a submodule
+ if prev_modname == package:
+ # first submodule - make parent a group head
+ entries[-1][1] = 1
+ elif not prev_modname.startswith(package):
+ # submodule without parent in list, add dummy entry
+ entries.append([stripped + package, 1, '', '', '', '', ''])
+ subtype = 2
+ else:
+ num_toplevels += 1
+ subtype = 0
+
+ qualifier = deprecated and _('Deprecated') or ''
+ entries.append([stripped + modname, subtype, docname,
+ 'module-' + stripped + modname, platforms,
+ qualifier, synopsis])
+ prev_modname = modname
+
+ # apply heuristics when to collapse modindex at page load:
+ # only collapse if number of toplevel modules is larger than
+ # number of submodules
+ collapse = len(modules) - num_toplevels < num_toplevels
+
+ # sort by first letter
+ content = sorted(content.iteritems())
+
+ return content, collapse
+
+
+class PythonDomain(Domain):
+ """Python language domain."""
+ name = 'py'
+ label = 'Python'
+ object_types = {
+ 'function': ObjType(l_('function'), 'func', 'obj'),
+ 'data': ObjType(l_('data'), 'data', 'obj'),
+ 'class': ObjType(l_('class'), 'class', 'obj'),
+ 'exception': ObjType(l_('exception'), 'exc', 'obj'),
+ 'method': ObjType(l_('method'), 'meth', 'obj'),
+ 'classmethod': ObjType(l_('class method'), 'meth', 'obj'),
+ 'staticmethod': ObjType(l_('static method'), 'meth', 'obj'),
+ 'attribute': ObjType(l_('attribute'), 'attr', 'obj'),
+ 'module': ObjType(l_('module'), 'mod', 'obj'),
+ }
+
+ directives = {
+ 'function': PyModulelevel,
+ 'data': PyModulelevel,
+ 'class': PyClasslike,
+ 'exception': PyClasslike,
+ 'method': PyClassmember,
+ 'classmethod': PyClassmember,
+ 'staticmethod': PyClassmember,
+ 'attribute': PyClassmember,
+ '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, objtype
+ 'modules': {}, # modname -> docname, synopsis, platform, deprecated
+ }
+ indices = [
+ PythonModuleIndex,
+ ]
+
+ 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_obj(self, env, modname, classname, name, type, searchorder=0):
+ """
+ Find a Python object 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 classname and classname + '.' + name in objects:
+ newname = classname + '.' + 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
+ 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.get('py:module')
+ clsname = node.get('py:class')
+ searchorder = node.hasattr('refspecific') and 1 or 0
+ name, obj = self.find_obj(env, modname, clsname,
+ target, typ, searchorder)
+ if not obj:
+ return None
+ else:
+ return make_refnode(builder, fromdocname, obj[0], name,
+ contnode, name)
+
+ def get_objects(self):
+ for modname, info in self.data['modules'].iteritems():
+ yield (modname, 'module', info[0], 'module-' + modname, 0)
+ for refname, (docname, type) in self.data['objects'].iteritems():
+ yield (refname, type, docname, refname, 1)
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
new file mode 100644
index 00000000..8b254e15
--- /dev/null
+++ b/sphinx/domains/std.py
@@ -0,0 +1,386 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.domains.std
+ ~~~~~~~~~~~~~~~~~~
+
+ The standard domain.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+
+from sphinx import addnodes
+from sphinx.roles import XRefRole
+from sphinx.locale import l_, _
+from sphinx.domains import Domain, ObjType
+from sphinx.directives import ObjectDescription
+from sphinx.util import ws_re
+from sphinx.util.nodes import make_refnode
+from sphinx.util.compat import Directive
+
+
+# RE for option descriptions
+option_desc_re = re.compile(
+ r'((?:/|-|--)[-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
+
+
+class GenericObject(ObjectDescription):
+ """
+ A generic x-ref directive registered with Sphinx.add_object_type().
+ """
+ indextemplate = ''
+ parse_node = None
+
+ def handle_signature(self, sig, signode):
+ if self.parse_node:
+ name = self.parse_node(self.env, sig, signode)
+ else:
+ signode.clear()
+ signode += addnodes.desc_name(sig, sig)
+ # normalize whitespace like XRefRole does
+ name = ws_re.sub('', sig)
+ return name
+
+ def add_target_and_index(self, name, sig, signode):
+ targetname = '%s-%s' % (self.objtype, name)
+ signode['ids'].append(targetname)
+ self.state.document.note_explicit_target(signode)
+ if self.indextemplate:
+ colon = self.indextemplate.find(':')
+ if colon != -1:
+ indextype = self.indextemplate[:colon].strip()
+ indexentry = self.indextemplate[colon+1:].strip() % (name,)
+ else:
+ indextype = 'single'
+ indexentry = self.indextemplate % (name,)
+ self.indexnode['entries'].append((indextype, indexentry,
+ targetname, targetname))
+ self.env.domaindata['std']['objects'][self.objtype, name] = \
+ self.env.docname, targetname
+
+
+class EnvVar(GenericObject):
+ indextemplate = l_('environment variable; %s')
+
+
+class EnvVarXRefRole(XRefRole):
+ """
+ Cross-referencing role for environment variables (adds an index entry).
+ """
+
+ def result_nodes(self, document, env, node, is_ref):
+ if not is_ref:
+ return [node], []
+ varname = node['reftarget']
+ tgtid = 'index-%s' % env.new_serialno('index')
+ indexnode = addnodes.index()
+ indexnode['entries'] = [
+ ('single', varname, tgtid, varname),
+ ('single', _('environment variable; %s') % varname, tgtid, varname)
+ ]
+ targetnode = nodes.target('', '', ids=[tgtid])
+ document.note_explicit_target(targetnode)
+ return [indexnode, targetnode, node], []
+
+
+class Target(Directive):
+ """
+ Generic target for user-defined cross-reference types.
+ """
+ indextemplate = ''
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = True
+ option_spec = {}
+
+ def run(self):
+ env = self.state.document.settings.env
+ # normalize whitespace in fullname like XRefRole does
+ fullname = ws_re.sub('', self.arguments[0].strip())
+ targetname = '%s-%s' % (self.name, fullname)
+ node = nodes.target('', '', ids=[targetname])
+ self.state.document.note_explicit_target(node)
+ ret = [node]
+ if self.indextemplate:
+ indexentry = self.indextemplate % (fullname,)
+ indextype = 'single'
+ colon = indexentry.find(':')
+ if colon != -1:
+ indextype = indexentry[:colon].strip()
+ indexentry = indexentry[colon+1:].strip()
+ inode = addnodes.index(entries=[(indextype, indexentry,
+ targetname, targetname)])
+ ret.insert(0, inode)
+ env.domaindata['std']['objects'][self.name, fullname] = \
+ env.docname, targetname
+ return ret
+
+
+class Cmdoption(ObjectDescription):
+ """
+ Description of a command-line option (.. cmdoption).
+ """
+
+ def handle_signature(self, sig, signode):
+ """Transform an option description into RST nodes."""
+ count = 0
+ firstname = ''
+ for m in option_desc_re.finditer(sig):
+ optname, args = m.groups()
+ if count:
+ signode += addnodes.desc_addname(', ', ', ')
+ signode += addnodes.desc_name(optname, optname)
+ signode += addnodes.desc_addname(args, args)
+ if not count:
+ firstname = optname
+ count += 1
+ if not firstname:
+ raise ValueError
+ return firstname
+
+ def add_target_and_index(self, name, sig, signode):
+ targetname = name.replace('/', '-')
+ currprogram = self.env.temp_data.get('std:program')
+ if currprogram:
+ targetname = '-' + currprogram + targetname
+ targetname = 'cmdoption' + targetname
+ signode['ids'].append(targetname)
+ self.state.document.note_explicit_target(signode)
+ self.indexnode['entries'].append(
+ ('pair', _('%scommand line option; %s') %
+ ((currprogram and currprogram + ' ' or ''), sig),
+ targetname, targetname))
+ self.env.domaindata['std']['progoptions'][currprogram, name] = \
+ self.env.docname, targetname
+
+
+class Program(Directive):
+ """
+ Directive to name the program for which options are documented.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = True
+ option_spec = {}
+
+ def run(self):
+ env = self.state.document.settings.env
+ program = ws_re.sub('-', self.arguments[0].strip())
+ if program == 'None':
+ env.temp_data['std:program'] = None
+ else:
+ env.temp_data['std:program'] = program
+ return []
+
+
+class OptionXRefRole(XRefRole):
+ innernodeclass = addnodes.literal_emphasis
+
+ def process_link(self, env, refnode, has_explicit_title, title, target):
+ program = env.temp_data.get('std:program')
+ 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)
+ refnode['refprogram'] = program
+ return title, target
+
+
+class Glossary(Directive):
+ """
+ Directive to create a glossary with cross-reference targets
+ for :term: roles.
+ """
+
+ has_content = True
+ required_arguments = 0
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {
+ 'sorted': directives.flag,
+ }
+
+ def run(self):
+ env = self.state.document.settings.env
+ objects = env.domaindata['std']['objects']
+ gloss_entries = env.temp_data.setdefault('gloss_entries', set())
+ node = addnodes.glossary()
+ node.document = self.state.document
+ self.state.nested_parse(self.content, self.content_offset, node)
+
+ # the content should be definition lists
+ dls = [child for child in node
+ if isinstance(child, nodes.definition_list)]
+ # now, extract definition terms to enable cross-reference creation
+ new_dl = nodes.definition_list()
+ new_dl['classes'].append('glossary')
+ items = []
+ for dl in dls:
+ for li in dl.children:
+ if not li.children or not isinstance(li[0], nodes.term):
+ continue
+ termtext = li.children[0].astext()
+ new_id = 'term-' + nodes.make_id(termtext)
+ if new_id in gloss_entries:
+ new_id = 'term-' + str(len(gloss_entries))
+ gloss_entries.add(new_id)
+ li[0]['names'].append(new_id)
+ li[0]['ids'].append(new_id)
+ objects['term', termtext.lower()] = env.docname, new_id
+ # add an index entry too
+ indexnode = addnodes.index()
+ indexnode['entries'] = [('single', termtext, new_id, termtext)]
+ li.insert(0, indexnode)
+ items.append((termtext, li))
+ if 'sorted' in self.options:
+ items.sort(key=lambda x: x[0].lower())
+ new_dl.extend(item[1] for item in items)
+ node.children = [new_dl]
+ return [node]
+
+
+token_re = re.compile('`([a-z_][a-z0-9_]*)`')
+
+def token_xrefs(text):
+ retnodes = []
+ pos = 0
+ for m in token_re.finditer(text):
+ if m.start() > pos:
+ txt = text[pos:m.start()]
+ retnodes.append(nodes.Text(txt, txt))
+ refnode = addnodes.pending_xref(
+ m.group(1), reftype='token', refdomain='std', reftarget=m.group(1))
+ refnode += nodes.literal(m.group(1), m.group(1), classes=['xref'])
+ retnodes.append(refnode)
+ pos = m.end()
+ if pos < len(text):
+ retnodes.append(nodes.Text(text[pos:], text[pos:]))
+ return retnodes
+
+
+class ProductionList(Directive):
+ """
+ Directive to list grammar productions.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = True
+ option_spec = {}
+
+ def run(self):
+ env = self.state.document.settings.env
+ objects = env.domaindata['std']['objects']
+ node = addnodes.productionlist()
+ messages = []
+ i = 0
+
+ for rule in self.arguments[0].split('\n'):
+ if i == 0 and ':' not in rule:
+ # production group
+ continue
+ i += 1
+ try:
+ name, tokens = rule.split(':', 1)
+ except ValueError:
+ break
+ subnode = addnodes.production()
+ subnode['tokenname'] = name.strip()
+ if subnode['tokenname']:
+ idname = 'grammar-token-%s' % subnode['tokenname']
+ if idname not in self.state.document.ids:
+ subnode['ids'].append(idname)
+ self.state.document.note_implicit_target(subnode, subnode)
+ objects['token', subnode['tokenname']] = env.docname, idname
+ subnode.extend(token_xrefs(tokens))
+ node.append(subnode)
+ return [node] + messages
+
+
+class StandardDomain(Domain):
+ """
+ Domain for all objects that don't fit into another domain or are added
+ via the application interface.
+ """
+
+ name = 'std'
+ label = 'Default'
+
+ object_types = {
+ 'term': ObjType(l_('glossary term'), 'term', searchprio=-1),
+ 'token': ObjType(l_('grammar token'), 'token', searchprio=-1),
+ 'envvar': ObjType(l_('environment variable'), 'envvar'),
+ 'cmdoption': ObjType(l_('program option'), 'option'),
+ }
+
+ directives = {
+ 'program': Program,
+ 'cmdoption': Cmdoption, # old name for backwards compatibility
+ 'option': Cmdoption,
+ 'envvar': EnvVar,
+ 'glossary': Glossary,
+ 'productionlist': ProductionList,
+ }
+ roles = {
+ 'option': OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
+ 'envvar': EnvVarXRefRole(),
+ 'token': XRefRole(),
+ 'term': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
+ }
+
+ initial_data = {
+ 'progoptions': {}, # (program, name) -> docname, labelid
+ 'objects': {}, # (type, name) -> docname, labelid
+ }
+
+ def clear_doc(self, docname):
+ for key, (fn, _) in self.data['progoptions'].items():
+ if fn == docname:
+ del self.data['progoptions'][key]
+ for key, (fn, _) in self.data['objects'].items():
+ if fn == docname:
+ del self.data['objects'][key]
+
+ def resolve_xref(self, env, fromdocname, builder,
+ typ, target, node, contnode):
+ if typ == 'option':
+ progname = node['refprogram']
+ docname, labelid = self.data['progoptions'].get((progname, target),
+ ('', ''))
+ if not docname:
+ return None
+ else:
+ return make_refnode(builder, fromdocname, docname,
+ labelid, contnode)
+ else:
+ docname, labelid = self.data['objects'].get((typ, target), ('', ''))
+ if not docname:
+ if typ == 'term':
+ env.warn(node.get('refdoc', fromdocname),
+ 'term not in glossary: %s' % target, node.line)
+ return None
+ else:
+ return make_refnode(builder, fromdocname, docname,
+ labelid, contnode)
+
+ def get_objects(self):
+ for (prog, option), info in self.data['progoptions'].iteritems():
+ yield (option, 'option', info[0], info[1], 1)
+ for (type, name), info in self.data['objects'].iteritems():
+ yield (name, type, info[0], info[1],
+ self.object_types[type].attrs['searchprio'])
diff --git a/sphinx/environment.py b/sphinx/environment.py
index 86585ded..a39c28bd 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -26,7 +26,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
@@ -36,11 +36,18 @@ from docutils.transforms.parts import ContentsFilter
from sphinx import addnodes
from sphinx.util import url_re, get_matching_docs, docname_join, \
FilenameUniqDict
-from sphinx.util.nodes import clean_astext
+from sphinx.util.nodes import clean_astext, make_refnode
from sphinx.util.osutil import movefile, SEP, ustrftime
from sphinx.util.matching import compile_matchers
-from sphinx.errors import SphinxError
-from sphinx.directives import additional_xref_types
+from sphinx.errors import SphinxError, ExtensionError
+from sphinx.locale import _
+
+
+orig_role_function = roles.role
+orig_directive_function = directives.directive
+
+class ElementLookupError(Exception): pass
+
default_settings = {
'embed_stylesheet': False,
@@ -54,7 +61,7 @@ default_settings = {
# This is increased every time an environment attribute is added
# or changed to properly invalidate pickle files.
-ENV_VERSION = 31
+ENV_VERSION = 35
default_substitutions = set([
@@ -102,7 +109,10 @@ class DefaultSubstitutions(Transform):
class MoveModuleTargets(Transform):
"""
- Move module targets to their nearest enclosing section title.
+ Move module targets that are the first thing in a section to the section
+ title.
+
+ XXX Python specific
"""
default_priority = 210
@@ -110,10 +120,11 @@ class MoveModuleTargets(Transform):
for node in self.document.traverse(nodes.target):
if not node['ids']:
continue
- if node['ids'][0].startswith('module-') and \
- node.parent.__class__ is nodes.section and \
- node.has_key('ismod'):
- node.parent['ids'] = node['ids']
+ if (node.has_key('ismod') and
+ node.parent.__class__ is nodes.section and
+ # index 0 is the section title node
+ node.parent.index(node) == 1):
+ node.parent['ids'][0:0] = node['ids']
node.parent.remove(node)
@@ -144,7 +155,8 @@ class SortIds(Transform):
class CitationReferences(Transform):
"""
- Handle citation references before the default docutils transform does.
+ Replace citation references by pending_xref nodes before the default
+ docutils transform tries to resolve them.
"""
default_priority = 619
@@ -205,9 +217,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):
@@ -216,6 +228,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')
@@ -232,6 +246,7 @@ class BuildEnvironment:
picklefile.close()
movefile(filename + '.tmp', filename)
# reset attributes
+ self.domains = domains
self.config.values = values
self.set_warnfunc(warnfunc)
@@ -245,6 +260,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
@@ -283,16 +301,13 @@ 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 dict
+
# 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
- self.reftargets = {} # (type, name) -> docname, labelid
- # type: term, token, envvar, citation
+ self.citations = {} # citation name -> docname, labelid
# Other inventories
self.indexentries = {} # docname -> list of
@@ -304,21 +319,17 @@ class BuildEnvironment:
self.images = FilenameUniqDict()
self.dlfiles = FilenameUniqDict()
- # These are set while parsing a file
- self.docname = None # current document name
- self.currmodule = None # current module name
- self.currclass = None # current class name
- self.currdesc = None # current descref name
- self.currprogram = None # current program name
- self.index_num = 0 # autonumber for index targets
- self.gloss_entries = set() # existing definition labels
+ # temporary data storage while reading a document
+ self.temp_data = {}
# Some magically present labels
- def add_magic_label(name, description):
- self.labels[name] = (name, '', description)
- self.anonlabels[name] = (name, '')
+ def add_magic_label(name, description, target=None):
+ self.labels[name] = (target or name, '', description)
+ self.anonlabels[name] = (target or name, '')
add_magic_label('genindex', _('Index'))
- add_magic_label('modindex', _('Module Index'))
+ # XXX add per domain?
+ # compatibility alias
+ add_magic_label('modindex', _('Module Index'), 'py-modindex')
add_magic_label('search', _('Search Page'))
def set_warnfunc(self, func):
@@ -345,7 +356,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)
@@ -356,25 +366,19 @@ 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]
- for key, (fn, _) in self.reftargets.items():
- if fn == docname:
- del self.reftargets[key]
- for key, (fn, _) in self.progoptions.items():
+ for key, (fn, _) in self.citations.items():
if fn == docname:
- del self.progoptions[key]
+ del self.citations[key]
for version, changes in self.versionchanges.items():
new = [change for change in changes if change[1] != docname]
changes[:] = new
+ 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.
@@ -533,9 +537,7 @@ class BuildEnvironment:
# --------- SINGLE FILE READING --------------------------------------------
def warn_and_replace(self, error):
- """
- Custom decoding error handler that warns and replaces.
- """
+ """Custom decoding error handler that warns and replaces."""
linestart = error.object.rfind('\n', 0, error.start)
lineend = error.object.find('\n', error.start)
if lineend == -1: lineend = len(error.object)
@@ -547,6 +549,51 @@ class BuildEnvironment:
error.object[error.end:lineend]), lineno)
return (u'?', error.end)
+ def lookup_domain_element(self, type, name):
+ """Lookup a markup element (directive or role), given its name which can
+ be a full name (with domain).
+ """
+ name = name.lower()
+ # explicit domain given?
+ if ':' in name:
+ domain_name, name = name.split(':', 1)
+ if domain_name in self.domains:
+ domain = self.domains[domain_name]
+ element = getattr(domain, type)(name)
+ if element is not None:
+ return element, []
+ # else look in the default domain
+ else:
+ def_domain = self.temp_data.get('default_domain')
+ if def_domain is not None:
+ element = getattr(def_domain, type)(name)
+ if element is not None:
+ return element, []
+ # always look in the std domain
+ element = getattr(self.domains['std'], type)(name)
+ if element is not None:
+ return element, []
+ raise ElementLookupError
+
+ def patch_lookup_functions(self):
+ """Monkey-patch directive and role dispatch, so that domain-specific
+ markup takes precedence.
+ """
+ def directive(name, lang_module, document):
+ try:
+ return self.lookup_domain_element('directive', name)
+ except ElementLookupError:
+ return orig_directive_function(name, lang_module, document)
+
+ def role(name, lang_module, lineno, reporter):
+ try:
+ return self.lookup_domain_element('role', name)
+ except ElementLookupError:
+ return orig_role_function(name, lang_module, lineno, reporter)
+
+ directives.directive = directive
+ roles.role = role
+
def read_doc(self, docname, src_path=None, save_parsed=True, app=None):
"""
Parse a file and add/update inventory entries for the doctree.
@@ -555,11 +602,23 @@ 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:
src_path = self.doc2path(docname)
+ self.temp_data['docname'] = docname
+ # defaults to the global default, but can be re-set in a document
+ self.temp_data['default_domain'] = \
+ self.domains.get(self.config.default_domain)
+
+ self.settings['input_encoding'] = self.config.source_encoding
+ self.settings['trim_footnote_reference_space'] = \
+ self.config.trim_footnote_reference_space
+
+ self.patch_lookup_functions()
+
if self.config.default_role:
role_fn, messages = roles.role(self.config.default_role, english,
0, dummy_reporter)
@@ -569,13 +628,6 @@ class BuildEnvironment:
self.warn(docname, 'default role %s not found' %
self.config.default_role)
- self.docname = docname
- self.settings['input_encoding'] = self.config.source_encoding
- self.settings['trim_footnote_reference_space'] = \
- self.config.trim_footnote_reference_space
-
- codecs.register_error('sphinx', self.warn_and_replace)
-
codecs.register_error('sphinx', self.warn_and_replace)
class SphinxSourceClass(FileInput):
@@ -607,6 +659,8 @@ class BuildEnvironment:
doctree = pub.document
except UnicodeError, err:
raise SphinxError(str(err))
+
+ # post-processing
self.filter_messages(doctree)
self.process_dependencies(docname, doctree)
self.process_images(docname, doctree)
@@ -618,12 +672,13 @@ class BuildEnvironment:
self.note_citations_from(docname, doctree)
self.build_toc_from(docname, doctree)
- # store time of build, for outdated files detection
- self.all_docs[docname] = time.time()
-
+ # allow extension-specific post-processing
if app:
app.emit('doctree-read', doctree)
+ # store time of build, for outdated files detection
+ self.all_docs[docname] = time.time()
+
# make it picklable
doctree.reporter = None
doctree.transformer = None
@@ -635,10 +690,7 @@ class BuildEnvironment:
metanode.__class__ = addnodes.meta
# cleanup
- self.docname = None
- self.currmodule = None
- self.currclass = None
- self.gloss_entries = set()
+ self.temp_data.clear()
if save_parsed:
# save the parsed doctree
@@ -655,6 +707,35 @@ class BuildEnvironment:
else:
return doctree
+ # utilities to use while reading a document
+
+ @property
+ def docname(self):
+ """Backwards compatible alias."""
+ return self.temp_data['docname']
+
+ @property
+ def currmodule(self):
+ """Backwards compatible alias."""
+ return self.temp_data.get('py:module')
+
+ @property
+ def currclass(self):
+ """Backwards compatible alias."""
+ return self.temp_data.get('py:class')
+
+ def new_serialno(self, category=''):
+ """Return a serial number, e.g. for index entry targets."""
+ key = category + 'serialno'
+ cur = self.temp_data.get(key, 0)
+ self.temp_data[key] = cur + 1
+ return cur
+
+ def note_dependency(self, filename):
+ self.dependencies.setdefault(self.docname, set()).add(filename)
+
+ # post-processing of read doctrees
+
def filter_messages(self, doctree):
"""
Filter system messages from a doctree.
@@ -816,7 +897,7 @@ class BuildEnvironment:
if name.isdigit() or node.has_key('refuri') or \
node.tagname.startswith('desc_'):
# ignore footnote labels, labels automatically generated from a
- # link and description units
+ # link and object descriptions
continue
if name in self.labels:
self.warn(docname, 'duplicate label %s, ' % name +
@@ -846,11 +927,11 @@ class BuildEnvironment:
def note_citations_from(self, docname, document):
for node in document.traverse(nodes.citation):
label = node[0].astext()
- if ('citation', label) in self.reftargets:
+ if label in self.citations:
self.warn(docname, 'duplicate citation %s, ' % label +
'other instance in %s' % self.doc2path(
- self.reftargets['citation', label][0]), node.line)
- self.reftargets['citation', label] = (docname, node['ids'][0])
+ self.citations[label][0]), node.line)
+ self.citations[label] = (docname, node['ids'][0])
def note_toctree(self, docname, toctreenode):
"""Note a TOC tree directive in a document and gather information about
@@ -938,13 +1019,14 @@ class BuildEnvironment:
node['refuri'] = node['anchorname'] or '#'
return toc
- def get_toctree_for(self, docname, builder, collapse):
+ def get_toctree_for(self, docname, builder, collapse, maxdepth=0):
"""Return the global TOC nodetree."""
doctree = self.get_doctree(self.config.master_doc)
toctrees = []
for toctreenode in doctree.traverse(addnodes.toctree):
toctree = self.resolve_toctree(docname, builder, toctreenode,
prune=True, collapse=collapse,
+ maxdepth=maxdepth,
includehidden=True)
toctrees.append(toctree)
if not toctrees:
@@ -954,36 +1036,13 @@ class BuildEnvironment:
result.extend(toctree.children)
return result
- # -------
- # 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)
-
- def note_reftarget(self, type, name, labelid):
- self.reftargets[type, name] = (self.docname, labelid)
-
- def note_versionchange(self, type, version, node, lineno):
- self.versionchanges.setdefault(version, []).append(
- (type, self.docname, lineno, self.currmodule, self.currdesc,
- node.astext()))
-
- def note_dependency(self, filename):
- 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 ------------------------------
@@ -1167,15 +1226,7 @@ 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):
- reftarget_roles = set(('token', 'term', 'citation'))
- # add all custom xref types too
- reftarget_roles.update(i[0] for i in additional_xref_types.values())
-
for node in doctree.traverse(addnodes.pending_xref):
contnode = node[0].deepcopy()
newnode = None
@@ -1183,10 +1234,20 @@ class BuildEnvironment:
typ = node['reftype']
target = node['reftarget']
refdoc = node.get('refdoc', fromdocname)
+ warned = False
try:
- if typ == 'ref':
- if node['refcaption']:
+ 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)
+ # really hardwired reference types
+ elif typ == 'ref':
+ if node['refexplicit']:
# reference to anonymous label; the reference uses
# the supplied link caption
docname, labelid = self.anonlabels.get(target, ('',''))
@@ -1194,8 +1255,9 @@ class BuildEnvironment:
if not docname:
self.warn(refdoc, 'undefined label: %s' %
target, node.line)
+ warned = True
else:
- # reference to the named label; the final node will
+ # reference to named label; the final node will
# contain the section name after the label
docname, labelid, sectname = self.labels.get(target,
('','',''))
@@ -1204,6 +1266,7 @@ class BuildEnvironment:
'undefined label: %s' % target + ' -- if you '
'don\'t give a link caption the label must '
'precede a section header.', node.line)
+ warned = True
if docname:
newnode = nodes.reference('', '')
innernode = nodes.emphasis(sectname, sectname)
@@ -1221,18 +1284,16 @@ class BuildEnvironment:
if labelid:
newnode['refuri'] += '#' + labelid
newnode.append(innernode)
- else:
- newnode = contnode
elif typ == 'doc':
# directly reference to document by source name;
# can be absolute or relative
docname = docname_join(refdoc, target)
if docname not in self.all_docs:
- self.warn(refdoc, 'unknown document: %s' % docname,
- node.line)
- newnode = contnode
+ self.warn(refdoc,
+ 'unknown document: %s' % docname, node.line)
+ warned = True
else:
- if node['refcaption']:
+ if node['refexplicit']:
# reference with explicit title
caption = node.astext()
else:
@@ -1242,100 +1303,42 @@ class BuildEnvironment:
newnode['refuri'] = builder.get_relative_uri(
fromdocname, docname)
newnode.append(innernode)
+ elif typ == 'citation':
+ docname, labelid = self.citations.get(target, ('', ''))
+ if not docname:
+ self.warn(refdoc,
+ 'citation not found: %s' % target, node.line)
+ warned = True
+ else:
+ newnode = make_refnode(builder, fromdocname, docname,
+ labelid, contnode)
elif typ == 'keyword':
- # keywords are referenced by named labels
+ # keywords are oddballs: they are referenced by named labels
docname, labelid, _ = self.labels.get(target, ('','',''))
if not docname:
#self.warn(refdoc, '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)
- elif typ == 'option':
- progname = node['refprogram']
- docname, labelid = self.progoptions.get((progname, target),
- ('', ''))
- 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)
- elif typ in reftarget_roles:
- docname, labelid = self.reftargets.get((typ, target),
- ('', ''))
- if not docname:
- if typ == 'term':
- self.warn(refdoc,
- 'term not in glossary: %s' % target,
- node.line)
- elif typ == 'citation':
- self.warn(refdoc, 'citation not found: %s' % target,
- node.line)
- newnode = contnode
+ pass
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
- 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)
+ # still not found? warn if in nit-picky mode
+ if newnode is None and not warned and self.config.nitpicky:
+ self.warn(refdoc,
+ 'reference target not found: %stype %s, target %s'
+ % (node.get('refdomain') and
+ 'domain %s, ' % node['refdomain'] or '',
+ typ, target))
except NoUri:
newnode = contnode
- if newnode:
- node.replace_self(newnode)
+ node.replace_self(newnode or contnode)
for node in doctree.traverse(addnodes.only):
try:
@@ -1499,7 +1502,7 @@ class BuildEnvironment:
i += 1
# group the entries by letter
- def keyfunc((k, v), letters=string.ascii_uppercase + '_'):
+ def keyfunc2((k, v), letters=string.ascii_uppercase + '_'):
# hack: mutating the subitems dicts to a list in the keyfunc
v[1] = sorted((si, se) for (si, (se, void)) in v[1].iteritems())
# now calculate the key
@@ -1510,7 +1513,7 @@ class BuildEnvironment:
# get all other symbols under one heading
return 'Symbols'
return [(key, list(group))
- for (key, group) in groupby(newlist, keyfunc)]
+ for (key, group) in groupby(newlist, keyfunc2)]
def collect_relations(self):
relations = {}
@@ -1565,119 +1568,6 @@ class BuildEnvironment:
if docname == self.config.master_doc:
# the master file is not included anywhere ;)
continue
+ if 'orphan' in self.metadata[docname]:
+ 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 classname and classname + '.' + name in self.descrefs:
- newname = classname + '.' + 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/errors.py b/sphinx/errors.py
index 4738f0cc..b614d9ab 100644
--- a/sphinx/errors.py
+++ b/sphinx/errors.py
@@ -54,3 +54,11 @@ class ThemeError(SphinxError):
class VersionRequirementError(SphinxError):
category = 'Sphinx version error'
+
+
+class PycodeError(Exception):
+ def __str__(self):
+ res = self.args[0]
+ if len(self.args) > 1:
+ res += ' (exception was: %r)' % self.args[1]
+ return res
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index ca96195e..35968916 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -21,6 +21,7 @@ from docutils.utils import assemble_option_dict
from docutils.statemachine import ViewList
from sphinx.util import rpartition, force_decode
+from sphinx.locale import _
from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.application import ExtensionError
from sphinx.util.nodes import nested_parse_with_titles
@@ -399,9 +400,11 @@ class Documenter(object):
def add_directive_header(self, sig):
"""Add the directive header and options to the generated content."""
+ domain = getattr(self, 'domain', 'py')
directive = getattr(self, 'directivetype', self.objtype)
name = self.format_name()
- self.add_line(u'.. %s:: %s%s' % (directive, name, sig), '<autodoc>')
+ self.add_line(u'.. %s:%s:: %s%s' % (domain, directive, name, sig),
+ '<autodoc>')
if self.options.noindex:
self.add_line(u' :noindex:', '<autodoc>')
if self.objpath:
@@ -566,9 +569,9 @@ class Documenter(object):
do all members, else those given by *self.options.members*.
"""
# set current namespace for finding members
- self.env.autodoc_current_module = self.modname
+ self.env.temp_data['autodoc:module'] = self.modname
if self.objpath:
- self.env.autodoc_current_class = self.objpath[0]
+ self.env.temp_data['autodoc:class'] = self.objpath[0]
want_all = all_members or self.options.inherited_members or \
self.options.members is ALL
@@ -596,12 +599,19 @@ class Documenter(object):
'.'.join(self.objpath + [mname])
documenter = classes[-1](self.directive, full_mname, self.indent)
memberdocumenters.append((documenter, isattr))
-
- if (self.options.member_order or self.env.config.autodoc_member_order) \
- == 'groupwise':
+ member_order = self.options.member_order or \
+ self.env.config.autodoc_member_order
+ if member_order == 'groupwise':
# sort by group; relies on stable sort to keep items in the
# same group sorted alphabetically
- memberdocumenters.sort(key=lambda d: d[0].member_order)
+ memberdocumenters.sort(key=lambda e: e[0].member_order)
+ elif member_order == 'bysource' and self.analyzer:
+ # sort by source order, by virtue of the module analyzer
+ tagorder = self.analyzer.tagorder
+ def keyfunc(entry):
+ fullname = entry[0].name.split('::')[1]
+ return tagorder.get(fullname, len(tagorder))
+ memberdocumenters.sort(key=keyfunc)
for documenter, isattr in memberdocumenters:
documenter.generate(
@@ -609,8 +619,8 @@ class Documenter(object):
check_module=members_check_module and not isattr)
# reset current objects
- self.env.autodoc_current_module = None
- self.env.autodoc_current_class = None
+ self.env.temp_data['autodoc:module'] = None
+ self.env.temp_data['autodoc:class'] = None
def generate(self, more_content=None, real_modname=None,
check_module=False, all_members=False):
@@ -763,11 +773,10 @@ class ModuleLevelDocumenter(Documenter):
else:
# if documenting a toplevel object without explicit module,
# it can be contained in another auto directive ...
- if hasattr(self.env, 'autodoc_current_module'):
- modname = self.env.autodoc_current_module
+ modname = self.env.temp_data.get('autodoc:module')
# ... or in the scope of a module directive
if not modname:
- modname = self.env.currmodule
+ modname = self.env.temp_data.get('py:module')
# ... else, it stays None, which means invalid
return modname, parents + [base]
@@ -786,21 +795,20 @@ class ClassLevelDocumenter(Documenter):
# if documenting a class-level object without path,
# there must be a current class, either from a parent
# auto directive ...
- if hasattr(self.env, 'autodoc_current_class'):
- mod_cls = self.env.autodoc_current_class
+ mod_cls = self.env.temp_data.get('autodoc:class')
# ... or from a class directive
if mod_cls is None:
- mod_cls = self.env.currclass
+ mod_cls = self.env.temp_data.get('py:class')
# ... if still None, there's no way to know
if mod_cls is None:
return None, []
modname, cls = rpartition(mod_cls, '.')
parents = [cls]
# if the module name is still missing, get it like above
- if not modname and hasattr(self.env, 'autodoc_current_module'):
- modname = self.env.autodoc_current_module
if not modname:
- modname = self.env.currmodule
+ modname = self.env.temp_data.get('autodoc:module')
+ if not modname:
+ modname = self.env.temp_data.get('py:module')
# ... else, it stays None, which means invalid
return modname, parents + [base]
@@ -1144,7 +1152,7 @@ class AutoDirective(Directive):
# record all filenames as dependencies -- this will at least
# partially make automatic invalidation possible
for fn in self.filename_set:
- self.env.note_dependency(fn)
+ self.state.document.settings.record_dependencies.add(fn)
# use a custom reporter that correctly assigns lines to source
# filename/description and lineno
diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py
index 90d8599e..cf67c7fb 100644
--- a/sphinx/ext/autosummary/__init__.py
+++ b/sphinx/ext/autosummary/__init__.py
@@ -63,7 +63,7 @@ from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
from docutils import nodes
-from sphinx import addnodes, roles
+from sphinx import addnodes
from sphinx.util.compat import Directive
@@ -192,7 +192,6 @@ class Autosummary(Directive):
if 'toctree' in self.options:
suffix = env.config.source_suffix
- all_docnames = env.found_docs.copy()
dirname = posixpath.dirname(env.docname)
tree_prefix = self.options['toctree'].strip()
@@ -226,8 +225,9 @@ class Autosummary(Directive):
env = self.state.document.settings.env
prefixes = ['']
- if env.currmodule:
- prefixes.insert(0, env.currmodule)
+ currmodule = env.temp_data.get('py:module')
+ if currmodule:
+ prefixes.insert(0, currmodule)
items = []
@@ -441,8 +441,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]
@@ -485,11 +486,13 @@ def setup(app):
app.add_node(autosummary_toc,
html=(autosummary_toc_visit_html, autosummary_noop),
latex=(autosummary_noop, autosummary_noop),
- text=(autosummary_noop, autosummary_noop))
+ text=(autosummary_noop, autosummary_noop),
+ man=(autosummary_noop, autosummary_noop))
app.add_node(autosummary_table,
html=(autosummary_table_visit_html, autosummary_noop),
latex=(autosummary_noop, autosummary_noop),
- text=(autosummary_noop, autosummary_noop))
+ text=(autosummary_noop, autosummary_noop),
+ man=(autosummary_noop, autosummary_noop))
app.add_directive('autosummary', Autosummary)
app.add_role('autolink', autolink_role)
app.connect('doctree-read', process_autosummary_toc)
diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py
index 0d2487f0..4924d30b 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/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py
index a271e101..b930d8ca 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
@@ -97,7 +96,7 @@ class InheritanceGraph(object):
# two possibilities: either it is a module, then import it
try:
- module = __import__(fullname)
+ __import__(fullname)
todoc = sys.modules[fullname]
except ImportError:
# else it is a class, then import the module
@@ -110,7 +109,7 @@ class InheritanceGraph(object):
'Could not import class %r specified for '
'inheritance diagram' % base)
try:
- module = __import__(path)
+ __import__(path)
todoc = getattr(sys.modules[path], base)
except (ImportError, AttributeError):
raise InheritanceException(
@@ -280,10 +279,12 @@ 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:
- graph = InheritanceGraph(class_names, env.currmodule)
+ graph = InheritanceGraph(class_names,
+ env.temp_data.get('py:module'))
except InheritanceException, err:
return [node.document.reporter.warning(err.args[0],
line=self.lineno)]
@@ -293,7 +294,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
@@ -360,7 +361,8 @@ def setup(app):
inheritance_diagram,
latex=(latex_visit_inheritance_diagram, None),
html=(html_visit_inheritance_diagram, None),
- text=(skip, None))
+ text=(skip, None),
+ man=(skip, None))
app.add_directive('inheritance-diagram', InheritanceDiagram)
app.add_config_value('inheritance_graph_attrs', {}, False),
app.add_config_value('inheritance_node_attrs', {}, False),
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py
index e20cc266..a264e94f 100644
--- a/sphinx/ext/intersphinx.py
+++ b/sphinx/ext/intersphinx.py
@@ -3,17 +3,17 @@
sphinx.ext.intersphinx
~~~~~~~~~~~~~~~~~~~~~~
- Insert links to Python objects documented in remote Sphinx documentation.
+ Insert links to objects documented in remote Sphinx documentation.
This works as follows:
- * Each Sphinx HTML build creates a file named "objects.inv" that contains
- a mapping from Python identifiers to URIs relative to the HTML set's root.
+ * Each Sphinx HTML build creates a file named "objects.inv" that contains a
+ mapping from object names to URIs relative to the HTML set's root.
* Projects using the Intersphinx extension can specify links to such mapping
files in the `intersphinx_mapping` config value. The mapping will then be
- used to resolve otherwise missing references to Python objects into links
- to the other documentation.
+ used to resolve otherwise missing references to objects into links to the
+ other documentation.
* By default, the mapping file is assumed to be at the same location as the
rest of the documentation; however, the location of the mapping file can
@@ -25,6 +25,7 @@
"""
import time
+import zlib
import urllib2
import posixpath
from os import path
@@ -41,12 +42,68 @@ if hasattr(urllib2, 'HTTPSHandler'):
urllib2.install_opener(urllib2.build_opener(*handlers))
+def read_inventory_v1(f, uri, join):
+ invdata = {}
+ line = f.next()
+ projname = line.rstrip()[11:].decode('utf-8')
+ line = f.next()
+ version = line.rstrip()[11:]
+ for line in f:
+ name, type, location = line.rstrip().split(None, 2)
+ location = join(uri, location)
+ # version 1 did not add anchors to the location
+ if type == 'mod':
+ type = 'py:module'
+ location += '#module-' + name
+ else:
+ type = 'py:' + type
+ location += '#' + name
+ invdata.setdefault(type, {})[name] = (projname, version, location)
+ return invdata
+
+
+def read_inventory_v2(f, uri, join, bufsize=16*1024):
+ invdata = {}
+ line = f.readline()
+ projname = line.rstrip()[11:].decode('utf-8')
+ line = f.readline()
+ version = line.rstrip()[11:]
+ line = f.readline()
+ if 'zlib' not in line:
+ raise ValueError
+
+ def read_chunks():
+ decompressor = zlib.decompressobj()
+ for chunk in iter(lambda: f.read(bufsize), ''):
+ yield decompressor.decompress(chunk)
+ yield decompressor.flush()
+
+ def split_lines(iter):
+ buf = ''
+ for chunk in iter:
+ buf += chunk
+ lineend = buf.find('\n')
+ while lineend != -1:
+ yield buf[:lineend]
+ buf = buf[lineend+1:]
+ lineend = buf.find('\n')
+ assert not buf
+
+ for line in split_lines(read_chunks()):
+ name, type, prio, location = line.rstrip().split(None, 3)
+ if location.endswith('$'):
+ location = location[:-1] + name
+ location = join(uri, location)
+ invdata.setdefault(type, {})[name] = (projname, version, location)
+ return invdata
+
+
def fetch_inventory(app, uri, inv):
"""Fetch, parse and return an intersphinx inventory file."""
- invdata = {}
# both *uri* (base URI of the links to generate) and *inv* (actual
# location of the inventory file) can be local or remote URIs
localuri = uri.find('://') == -1
+ join = localuri and path.join or posixpath.join
try:
if inv.find('://') != -1:
f = urllib2.urlopen(inv)
@@ -57,24 +114,21 @@ def fetch_inventory(app, uri, inv):
'%s: %s' % (inv, err.__class__, err))
return
try:
- line = f.next()
- if line.rstrip() != '# Sphinx inventory version 1':
- raise ValueError('unknown or unsupported inventory version')
- line = f.next()
- projname = line.rstrip()[11:].decode('utf-8')
- line = f.next()
- version = line.rstrip()[11:]
- for line in f:
- name, type, location = line.rstrip().split(None, 2)
- if localuri:
- location = path.join(uri, location)
+ line = f.readline().rstrip()
+ try:
+ if line == '# Sphinx inventory version 1':
+ invdata = read_inventory_v1(f, uri, join)
+ elif line == '# Sphinx inventory version 2':
+ invdata = read_inventory_v2(f, uri, join)
else:
- location = posixpath.join(uri, location)
- invdata[name] = (type, projname, version, location)
- f.close()
+ raise ValueError
+ f.close()
+ except ValueError:
+ f.close()
+ raise ValueError('unknown or unsupported inventory version')
except Exception, err:
app.warn('intersphinx inventory %r not readable due to '
- '%s: %s' % (inv, err.__class__, err))
+ '%s: %s' % (inv, err.__class__.__name__, err))
else:
return invdata
@@ -110,31 +164,24 @@ def load_mappings(app):
def missing_reference(app, env, node, contnode):
"""Attempt to resolve a missing reference via intersphinx references."""
- type = node['reftype']
+ domain = node.get('refdomain')
+ if not domain:
+ # only objects in domains are in the inventory
+ return
target = node['reftarget']
- if type == 'mod':
- type, proj, version, uri = env.intersphinx_inventory.get(target,
- ('','','',''))
- if type != 'mod':
- return None
- target = 'module-' + target # for link anchor
+ objtypes = env.domains[domain].objtypes_for_role(node['reftype'])
+ if not objtypes:
+ return
+ for objtype in objtypes:
+ fulltype = '%s:%s' % (domain, objtype)
+ if fulltype in env.intersphinx_inventory and \
+ target in env.intersphinx_inventory[fulltype]:
+ break
else:
- if target[-2:] == '()':
- target = target[:-2]
- target = target.rstrip(' *')
- # special case: exceptions and object methods
- if type == 'exc' and '.' not in target and \
- 'exceptions.' + target in env.intersphinx_inventory:
- target = 'exceptions.' + target
- elif type in ('func', 'meth') and '.' not in target and \
- 'object.' + target in env.intersphinx_inventory:
- target = 'object.' + target
- if target not in env.intersphinx_inventory:
- return None
- type, proj, version, uri = env.intersphinx_inventory[target]
- # print "Intersphinx hit:", target, uri
+ return
+ proj, version, uri = env.intersphinx_inventory[fulltype][target]
newnode = nodes.reference('', '')
- newnode['refuri'] = uri + '#' + target
+ newnode['refuri'] = uri
newnode['reftitle'] = '(in %s v%s)' % (proj, version)
newnode['class'] = 'external-xref'
newnode.append(contnode)
diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py
index 774f5608..8a5b75d3 100644
--- a/sphinx/ext/mathbase.py
+++ b/sphinx/ext/mathbase.py
@@ -108,6 +108,20 @@ def text_visit_eqref(self, node):
raise nodes.SkipNode
+def man_visit_math(self, node):
+ self.body.append(node['latex'])
+ raise nodes.SkipNode
+
+def man_visit_displaymath(self, node):
+ self.visit_centered(node)
+def man_depart_displaymath(self, node):
+ self.depart_centered(node)
+
+def man_visit_eqref(self, node):
+ self.body.append(node['target'])
+ raise nodes.SkipNode
+
+
def html_visit_eqref(self, node):
self.body.append('<a href="#equation-%s">' % node['target'])
@@ -136,14 +150,17 @@ def setup_math(app, htmlinlinevisitors, htmldisplayvisitors):
app.add_node(math,
latex=(latex_visit_math, None),
text=(text_visit_math, None),
+ man=(man_visit_math, None),
html=htmlinlinevisitors)
app.add_node(displaymath,
latex=(latex_visit_displaymath, None),
text=(text_visit_displaymath, None),
+ man=(man_visit_displaymath, man_depart_displaymath),
html=htmldisplayvisitors)
app.add_node(eqref,
latex=(latex_visit_eqref, None),
text=(text_visit_eqref, None),
+ man=(man_visit_eqref, None),
html=(html_visit_eqref, html_depart_eqref))
app.add_role('math', math_role)
app.add_role('eq', eq_role)
diff --git a/sphinx/ext/refcounting.py b/sphinx/ext/refcounting.py
index 398520b8..6ab9fe4b 100644
--- a/sphinx/ext/refcounting.py
+++ b/sphinx/ext/refcounting.py
@@ -69,7 +69,7 @@ class Refcounts(dict):
def add_refcount_annotations(self, app, doctree):
for node in doctree.traverse(addnodes.desc_content):
par = node.parent
- if par['desctype'] != 'cfunction':
+ if par['domain'] != 'c' or par['objtype'] != 'function':
continue
if not par[0].has_key('names') or not par[0]['names']:
continue
diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py
index 33ae8901..ac362919 100644
--- a/sphinx/ext/todo.py
+++ b/sphinx/ext/todo.py
@@ -14,6 +14,7 @@
from docutils import nodes
+from sphinx.locale import _
from sphinx.environment import NoUri
from sphinx.util.compat import Directive, make_admonition
@@ -34,9 +35,7 @@ class Todo(Directive):
def run(self):
env = self.state.document.settings.env
-
- targetid = "todo-%s" % env.index_num
- env.index_num += 1
+ targetid = 'index-%s' % env.new_serialno('index')
targetnode = nodes.target('', '', ids=[targetid])
ad = make_admonition(todo_node, self.name, [_('Todo')], self.options,
@@ -160,7 +159,8 @@ def setup(app):
app.add_node(todo_node,
html=(visit_todo_node, depart_todo_node),
latex=(visit_todo_node, depart_todo_node),
- text=(visit_todo_node, depart_todo_node))
+ text=(visit_todo_node, depart_todo_node),
+ man=(visit_todo_node, depart_todo_node))
app.add_directive('todo', Todo)
app.add_directive('todolist', TodoList)
diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py
new file mode 100644
index 00000000..ac2a957f
--- /dev/null
+++ b/sphinx/ext/viewcode.py
@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.ext.viewcode
+ ~~~~~~~~~~~~~~~~~~~
+
+ Add links to module code in Python object descriptions.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes
+
+from sphinx import addnodes
+from sphinx.locale import _
+from sphinx.pycode import ModuleAnalyzer
+from sphinx.util.nodes import make_refnode
+
+
+def doctree_read(app, doctree):
+ env = app.builder.env
+ if not hasattr(env, '_viewcode_modules'):
+ env._viewcode_modules = {}
+
+ def has_tag(modname, fullname, docname):
+ entry = env._viewcode_modules.get(modname, None)
+ if entry is None:
+ try:
+ analyzer = ModuleAnalyzer.for_module(modname)
+ except Exception:
+ env._viewcode_modules[modname] = False
+ return
+ analyzer.find_tags()
+ entry = analyzer.code, analyzer.tags, {}
+ env._viewcode_modules[modname] = entry
+ elif entry is False:
+ return
+ code, tags, used = entry
+ if fullname in tags:
+ used[fullname] = docname
+ return True
+
+ for objnode in doctree.traverse(addnodes.desc):
+ if objnode['domain'] != 'py':
+ continue
+ names = set()
+ for signode in objnode:
+ if not isinstance(signode, addnodes.desc_signature):
+ continue
+ modname = signode['module']
+ if not modname:
+ continue
+ fullname = signode['fullname']
+ if not has_tag(modname, fullname, env.docname):
+ continue
+ if fullname in names:
+ # only one link per name, please
+ continue
+ names.add(fullname)
+ pagename = '_modules/' + modname.replace('.', '/')
+ onlynode = addnodes.only(expr='html')
+ onlynode += addnodes.pending_xref(
+ '', reftype='viewcode', refdomain='std', refexplicit=False,
+ reftarget=pagename, refid=fullname,
+ refdoc=env.docname)
+ onlynode[0] += nodes.inline('', _('[source]'),
+ classes=['viewcode-link'])
+ signode += onlynode
+
+
+def missing_reference(app, env, node, contnode):
+ # resolve our "viewcode" reference nodes -- they need special treatment
+ if node['reftype'] == 'viewcode':
+ return make_refnode(app.builder, node['refdoc'], node['reftarget'],
+ node['refid'], contnode)
+
+
+def collect_pages(app):
+ env = app.builder.env
+ if not hasattr(env, '_viewcode_modules'):
+ return
+ highlighter = app.builder.highlighter
+ urito = app.builder.get_relative_uri
+
+ modnames = set(env._viewcode_modules)
+
+ app.builder.info(' (%d module code pages)' %
+ len(env._viewcode_modules), nonl=1)
+
+ for modname, (code, tags, used) in env._viewcode_modules.iteritems():
+ # construct a page name for the highlighted source
+ pagename = '_modules/' + modname.replace('.', '/')
+ # highlight the source using the builder's highlighter
+ highlighted = highlighter.highlight_block(code, 'python', False)
+ # split the code into lines
+ lines = highlighted.splitlines()
+ # split off wrap markup from the first line of the actual code
+ before, after = lines[0].split('<pre>')
+ lines[0:1] = [before + '<pre>', after]
+ # nothing to do for the last line; it always starts with </pre> anyway
+ # now that we have code lines (starting at index 1), insert anchors for
+ # the collected tags (HACK: this only works if the tag boundaries are
+ # properly nested!)
+ for name, docname in used.iteritems():
+ type, start, end = tags[name]
+ backlink = urito(pagename, docname) + '#' + modname + '.' + name
+ lines[start] = (
+ '<div class="viewcode-block" id="%s"><a class="viewcode-back" '
+ 'href="%s">%s</a>' % (name, backlink, _('[docs]'))
+ + lines[start])
+ lines[end - 1] += '</div>'
+ # try to find parents (for submodules)
+ parents = []
+ parent = modname
+ while '.' in parent:
+ parent = parent.rsplit('.', 1)[0]
+ if parent in modnames:
+ parents.append({
+ 'link': urito(pagename, '_modules/' +
+ parent.replace('.', '/')),
+ 'title': parent})
+ parents.append({'link': urito(pagename, '_modules/index'),
+ 'title': _('Module code')})
+ parents.reverse()
+ # putting it all together
+ context = {
+ 'parents': parents,
+ 'title': modname,
+ 'body': _('<h1>Source code for %s</h1>') % modname + \
+ '\n'.join(lines)
+ }
+ yield (pagename, context, 'page.html')
+
+ if not modnames:
+ return
+
+ app.builder.info(' _modules/index')
+ html = ['\n']
+ # the stack logic is needed for using nested lists for submodules
+ stack = ['']
+ for modname in sorted(modnames):
+ if modname.startswith(stack[-1]):
+ stack.append(modname + '.')
+ html.append('<ul>')
+ else:
+ stack.pop()
+ while not modname.startswith(stack[-1]):
+ stack.pop()
+ html.append('</ul>')
+ stack.append(modname + '.')
+ html.append('<li><a href="%s">%s</a></li>\n' % (
+ urito('_modules/index', '_modules/' + modname.replace('.', '/')),
+ modname))
+ html.append('</ul>' * (len(stack) - 1))
+ context = {
+ 'title': _('Overview: module code'),
+ 'body': _('<h1>All modules for which code is available</h1>') + \
+ ''.join(html),
+ }
+
+ yield ('_modules/index', context, 'page.html')
+
+
+def setup(app):
+ app.connect('doctree-read', doctree_read)
+ app.connect('html-collect-pages', collect_pages)
+ app.connect('missing-reference', missing_reference)
+ #app.add_config_value('viewcode_include_modules', [], 'env')
+ #app.add_config_value('viewcode_exclude_modules', [], 'env')
diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py
index cb992487..a6f1a853 100644
--- a/sphinx/jinja2glue.py
+++ b/sphinx/jinja2glue.py
@@ -30,7 +30,7 @@ def accesskey(context, key):
"""Helper to output each access key only once."""
if '_accesskeys' not in context:
context.vars['_accesskeys'] = {}
- if key not in context.vars['_accesskeys']:
+ if key and key not in context.vars['_accesskeys']:
context.vars['_accesskeys'][key] = 1
return 'accesskey="%s"' % key
return ''
@@ -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,8 @@ 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 4ad3f4c6..badcca1c 100644
--- a/sphinx/locale/__init__.py
+++ b/sphinx/locale/__init__.py
@@ -8,41 +8,180 @@
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+import gettext
+import UserString
+
+
+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 _
+translator = None
+
+def _(message):
+ return translator.gettext(message)
-def init():
- for dct in (admonitionlabels, versionlabels, pairindextypes):
- for key in dct:
- dct[key] = _(dct[key])
+def init(locale_dirs, language):
+ global translator
+ # the None entry is the system's default locale path
+ 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
+ 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
new file mode 100644
index 00000000..d9cc44ce
--- /dev/null
+++ b/sphinx/locale/ca/LC_MESSAGES/sphinx.mo
Binary files differ
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 &ndash; %(key)s"
+msgstr "Índes &ndash; %(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 "&copy; <a href=\"%(path)s\">Copyright</a> %(copyright)s."
+msgstr "&copy; <a href=\\\"%(path)s\\\">Copyright</a> %(copyright)s."
+
+#: sphinx/themes/basic/layout.html:186
+#, python-format
+msgid "&copy; Copyright %(copyright)s."
+msgstr "&copy; 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 &mdash; %(docstitle)s"
+msgstr "Canvis a la Versió %(version)s &mdash; %(docstitle)s"
+
+#: sphinx/themes/basic/changes/rstsource.html:5
+#, python-format
+msgid "%(filename)s &mdash; %(docstitle)s"
+msgstr "%(filename)s &mdash; %(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/sphinx.pot b/sphinx/locale/sphinx.pot
index d6337cf7..64bc69dd 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/[?1034h2e1ab15e035e\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2009-08-06 23:04+0200\n"
+"POT-Creation-Date: 2009-11-08 16:28+0100\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,12 +17,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.4\n"
-#: sphinx/environment.py:103 sphinx/writers/latex.py:184
+#: sphinx/environment.py:130 sphinx/writers/latex.py:184
#, python-format
msgid "%B %d, %Y"
msgstr ""
-#: sphinx/environment.py:324 sphinx/themes/basic/genindex-single.html:2
+#: sphinx/environment.py:348 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
@@ -31,60 +31,56 @@ msgstr ""
msgid "Index"
msgstr ""
-#: sphinx/environment.py:325 sphinx/writers/latex.py:189
+#: sphinx/environment.py:349 sphinx/writers/latex.py:189
msgid "Module Index"
msgstr ""
-#: sphinx/environment.py:326 sphinx/themes/basic/defindex.html:16
+#: sphinx/environment.py:350 sphinx/themes/basic/defindex.html:16
msgid "Search Page"
msgstr ""
-#: sphinx/roles.py:55 sphinx/directives/desc.py:747
-#, python-format
-msgid "environment variable; %s"
-msgstr ""
-
-#: sphinx/roles.py:62
+#: sphinx/roles.py:167
#, python-format
msgid "Python Enhancement Proposals!PEP %s"
msgstr ""
-#: sphinx/builders/changes.py:71
+#: sphinx/builders/changes.py:70
msgid "Builtins"
msgstr ""
-#: sphinx/builders/changes.py:73
+#: sphinx/builders/changes.py:72
msgid "Module level"
msgstr ""
-#: sphinx/builders/html.py:222
+#: sphinx/builders/html.py:224
#, python-format
msgid "%b %d, %Y"
msgstr ""
-#: sphinx/builders/html.py:241 sphinx/themes/basic/defindex.html:21
+#: sphinx/builders/html.py:243 sphinx/themes/basic/defindex.html:21
msgid "General Index"
msgstr ""
-#: sphinx/builders/html.py:241
+#: sphinx/builders/html.py:243
msgid "index"
msgstr ""
-#: sphinx/builders/html.py:243 sphinx/builders/htmlhelp.py:219
+#: sphinx/builders/html.py:247 sphinx/builders/htmlhelp.py:220
#: 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/builders/html.py:244
+#: sphinx/builders/html.py:248
msgid "modules"
msgstr ""
-#: sphinx/builders/html.py:300
+#: sphinx/builders/html.py:304
msgid "next"
msgstr ""
-#: sphinx/builders/html.py:309
+#: sphinx/builders/html.py:313
msgid "previous"
msgstr ""
@@ -92,249 +88,323 @@ msgstr ""
msgid " (in "
msgstr ""
-#: sphinx/directives/desc.py:97
+#: sphinx/directives/__init__.py:78 sphinx/directives/__init__.py:79
+#: sphinx/directives/__init__.py:80 sphinx/directives/__init__.py:81
msgid "Raises"
msgstr ""
-#: sphinx/directives/desc.py:101
+#: sphinx/directives/__init__.py:82 sphinx/directives/__init__.py:83
+#: sphinx/directives/__init__.py:84
msgid "Variable"
msgstr ""
-#: sphinx/directives/desc.py:104
+#: sphinx/directives/__init__.py:85 sphinx/directives/__init__.py:86
+#: sphinx/directives/__init__.py:92 sphinx/directives/__init__.py:93
msgid "Returns"
msgstr ""
-#: sphinx/directives/desc.py:113
+#: sphinx/directives/__init__.py:94
msgid "Return type"
msgstr ""
-#: sphinx/directives/desc.py:186
+#: sphinx/directives/__init__.py:169
msgid "Parameter"
msgstr ""
-#: sphinx/directives/desc.py:190
+#: sphinx/directives/__init__.py:173
msgid "Parameters"
msgstr ""
-#: sphinx/directives/desc.py:418
+#: sphinx/directives/other.py:127
+msgid "Section author: "
+msgstr ""
+
+#: sphinx/directives/other.py:129
+msgid "Module author: "
+msgstr ""
+
+#: sphinx/directives/other.py:131
+msgid "Author: "
+msgstr ""
+
+#: sphinx/directives/other.py:233
+msgid "See also"
+msgstr ""
+
+#: sphinx/domains/c.py:124
+#, python-format
+msgid "%s (C function)"
+msgstr ""
+
+#: sphinx/domains/c.py:126
+#, python-format
+msgid "%s (C member)"
+msgstr ""
+
+#: sphinx/domains/c.py:128
+#, python-format
+msgid "%s (C macro)"
+msgstr ""
+
+#: sphinx/domains/c.py:130
+#, python-format
+msgid "%s (C type)"
+msgstr ""
+
+#: sphinx/domains/c.py:132
+#, python-format
+msgid "%s (C variable)"
+msgstr ""
+
+#: sphinx/domains/c.py:162
+msgid "C function"
+msgstr ""
+
+#: sphinx/domains/c.py:163
+msgid "C member"
+msgstr ""
+
+#: sphinx/domains/c.py:164
+msgid "C macro"
+msgstr ""
+
+#: sphinx/domains/c.py:165
+msgid "C type"
+msgstr ""
+
+#: sphinx/domains/c.py:166
+msgid "C variable"
+msgstr ""
+
+#: sphinx/domains/python.py:186
#, python-format
msgid "%s() (built-in function)"
msgstr ""
-#: sphinx/directives/desc.py:419 sphinx/directives/desc.py:476
-#: sphinx/directives/desc.py:488
+#: sphinx/domains/python.py:187 sphinx/domains/python.py:244
+#: sphinx/domains/python.py:256 sphinx/domains/python.py:269
#, python-format
msgid "%s() (in module %s)"
msgstr ""
-#: sphinx/directives/desc.py:422
+#: sphinx/domains/python.py:190
#, python-format
msgid "%s (built-in variable)"
msgstr ""
-#: sphinx/directives/desc.py:423 sphinx/directives/desc.py:514
+#: sphinx/domains/python.py:191 sphinx/domains/python.py:282
#, python-format
msgid "%s (in module %s)"
msgstr ""
-#: sphinx/directives/desc.py:439
+#: sphinx/domains/python.py:207
#, python-format
msgid "%s (built-in class)"
msgstr ""
-#: sphinx/directives/desc.py:440
+#: sphinx/domains/python.py:208
#, python-format
msgid "%s (class in %s)"
msgstr ""
-#: sphinx/directives/desc.py:480
+#: sphinx/domains/python.py:248
#, python-format
msgid "%s() (%s.%s method)"
msgstr ""
-#: sphinx/directives/desc.py:482
+#: sphinx/domains/python.py:250
#, python-format
msgid "%s() (%s method)"
msgstr ""
-#: sphinx/directives/desc.py:492
+#: sphinx/domains/python.py:260
#, python-format
msgid "%s() (%s.%s static method)"
msgstr ""
-#: sphinx/directives/desc.py:495
+#: sphinx/domains/python.py:263
#, python-format
msgid "%s() (%s static method)"
msgstr ""
-#: sphinx/directives/desc.py:518
+#: sphinx/domains/python.py:273
#, python-format
-msgid "%s (%s.%s attribute)"
+msgid "%s() (%s.%s class method)"
msgstr ""
-#: sphinx/directives/desc.py:520
+#: sphinx/domains/python.py:276
#, python-format
-msgid "%s (%s attribute)"
+msgid "%s() (%s class method)"
msgstr ""
-#: sphinx/directives/desc.py:609
+#: sphinx/domains/python.py:286
#, python-format
-msgid "%s (C function)"
+msgid "%s (%s.%s attribute)"
msgstr ""
-#: sphinx/directives/desc.py:611
+#: sphinx/domains/python.py:288
#, python-format
-msgid "%s (C member)"
+msgid "%s (%s attribute)"
msgstr ""
-#: sphinx/directives/desc.py:613
-#, python-format
-msgid "%s (C macro)"
+#: sphinx/domains/python.py:334
+msgid "Platforms: "
msgstr ""
-#: sphinx/directives/desc.py:615
+#: sphinx/domains/python.py:340
#, python-format
-msgid "%s (C type)"
+msgid "%s (module)"
msgstr ""
-#: sphinx/directives/desc.py:617
-#, python-format
-msgid "%s (C variable)"
+#: sphinx/domains/python.py:396
+msgid "function"
msgstr ""
-#: sphinx/directives/desc.py:665
-#, python-format
-msgid "%scommand line option; %s"
+#: sphinx/domains/python.py:397
+msgid "data"
msgstr ""
-#: sphinx/directives/other.py:140
-msgid "Platforms: "
+#: sphinx/domains/python.py:398
+msgid "class"
msgstr ""
-#: sphinx/directives/other.py:146
+#: sphinx/domains/python.py:399 sphinx/locale/__init__.py:161
+msgid "exception"
+msgstr ""
+
+#: sphinx/domains/python.py:400
+msgid "method"
+msgstr ""
+
+#: sphinx/domains/python.py:401
+msgid "attribute"
+msgstr ""
+
+#: sphinx/domains/python.py:402 sphinx/locale/__init__.py:157
+msgid "module"
+msgstr ""
+
+#: sphinx/domains/std.py:67 sphinx/domains/std.py:83
#, python-format
-msgid "%s (module)"
+msgid "environment variable; %s"
msgstr ""
-#: sphinx/directives/other.py:195
-msgid "Section author: "
+#: sphinx/domains/std.py:156
+#, python-format
+msgid "%scommand line option; %s"
msgstr ""
-#: sphinx/directives/other.py:197
-msgid "Module author: "
+#: sphinx/domains/std.py:324
+msgid "glossary term"
msgstr ""
-#: sphinx/directives/other.py:199
-msgid "Author: "
+#: sphinx/domains/std.py:325
+msgid "grammar token"
msgstr ""
-#: sphinx/directives/other.py:319
-msgid "See also"
+#: sphinx/domains/std.py:326
+msgid "environment variable"
+msgstr ""
+
+#: sphinx/domains/std.py:327
+msgid "program option"
msgstr ""
-#: sphinx/ext/autodoc.py:889
+#: sphinx/ext/autodoc.py:892
#, python-format
msgid " Bases: %s"
msgstr ""
-#: sphinx/ext/autodoc.py:922
+#: sphinx/ext/autodoc.py:925
#, python-format
msgid "alias of :class:`%s`"
msgstr ""
-#: sphinx/ext/todo.py:41
+#: sphinx/ext/todo.py:40
msgid "Todo"
msgstr ""
-#: sphinx/ext/todo.py:99
+#: sphinx/ext/todo.py:98
#, python-format
msgid "(The original entry is located in %s, line %d and can be found "
msgstr ""
-#: sphinx/ext/todo.py:105
+#: sphinx/ext/todo.py:104
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
-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
-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 +518,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 "&copy; <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 "&copy; 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 ""
@@ -498,7 +568,7 @@ msgid "search"
msgstr ""
#: sphinx/themes/basic/search.html:25
-#: sphinx/themes/basic/static/searchtools.js:462
+#: sphinx/themes/basic/static/searchtools.js:473
msgid "Search Results"
msgstr ""
@@ -534,16 +604,16 @@ msgstr ""
msgid "Other changes"
msgstr ""
-#: sphinx/themes/basic/static/doctools.js:139 sphinx/writers/html.py:473
-#: sphinx/writers/html.py:478
+#: sphinx/themes/basic/static/doctools.js:138 sphinx/writers/html.py:462
+#: sphinx/writers/html.py:467
msgid "Permalink to this headline"
msgstr ""
-#: sphinx/themes/basic/static/doctools.js:145 sphinx/writers/html.py:80
+#: sphinx/themes/basic/static/doctools.js:144 sphinx/writers/html.py:80
msgid "Permalink to this definition"
msgstr ""
-#: sphinx/themes/basic/static/doctools.js:174
+#: sphinx/themes/basic/static/doctools.js:173
msgid "Hide Search Matches"
msgstr ""
@@ -555,21 +625,17 @@ msgstr ""
msgid "Preparing search..."
msgstr ""
-#: sphinx/themes/basic/static/searchtools.js:347
-msgid "module, in "
-msgstr ""
-
-#: sphinx/themes/basic/static/searchtools.js:356
+#: sphinx/themes/basic/static/searchtools.js:352
msgid ", in "
msgstr ""
-#: sphinx/themes/basic/static/searchtools.js:464
+#: sphinx/themes/basic/static/searchtools.js:475
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 ""
-#: sphinx/themes/basic/static/searchtools.js:466
+#: sphinx/themes/basic/static/searchtools.js:477
#, python-format
msgid "Search finished, found %s page(s) matching the search query."
msgstr ""
@@ -578,15 +644,15 @@ msgstr ""
msgid "Release"
msgstr ""
-#: sphinx/writers/latex.py:578
+#: sphinx/writers/latex.py:579
msgid "Footnotes"
msgstr ""
-#: sphinx/writers/latex.py:646
+#: sphinx/writers/latex.py:647
msgid "continued from previous page"
msgstr ""
-#: sphinx/writers/latex.py:651
+#: sphinx/writers/latex.py:652
msgid "Continued on next page"
msgstr ""
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 93a11ca8..63303a85 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -14,8 +14,10 @@ import sys
from os import path
from cStringIO import StringIO
+from sphinx.errors import PycodeError
from sphinx.pycode import nodes
from sphinx.pycode.pgen2 import driver, token, tokenize, parse, literals
+from sphinx.util import get_module_source
from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc
@@ -56,9 +58,17 @@ class AttrDocVisitor(nodes.NodeVisitor):
self.encoding = encoding
self.namespace = []
self.collected = {}
+ self.tagnumber = 0
+ self.tagorder = {}
+
+ def add_tag(self, name):
+ name = '.'.join(self.namespace + [name])
+ self.tagorder[name] = self.tagnumber
+ self.tagnumber += 1
def visit_classdef(self, node):
"""Visit a class."""
+ self.add_tag(node[1].value)
self.namespace.append(node[1].value)
self.generic_visit(node)
self.namespace.pop()
@@ -66,6 +76,7 @@ class AttrDocVisitor(nodes.NodeVisitor):
def visit_funcdef(self, node):
"""Visit a function (or method)."""
# usually, don't descend into functions -- nothing interesting there
+ self.add_tag(node[1].value)
if node[1].value == '__init__':
# however, collect attributes set in __init__ methods
self.in_init += 1
@@ -89,8 +100,7 @@ class AttrDocVisitor(nodes.NodeVisitor):
prefix = pnode.get_prefix()
prefix = prefix.decode(self.encoding)
docstring = prepare_commentdoc(prefix)
- if docstring:
- self.add_docstring(node, docstring)
+ self.add_docstring(node, docstring)
def visit_simple_stmt(self, node):
"""Visit a docstring statement which may have an assignment before."""
@@ -131,17 +141,11 @@ class AttrDocVisitor(nodes.NodeVisitor):
continue
else:
name = target.value
- namespace = '.'.join(self.namespace)
- if namespace.startswith(self.scope):
- self.collected[namespace, name] = docstring
-
-
-class PycodeError(Exception):
- def __str__(self):
- res = self.args[0]
- if len(self.args) > 1:
- res += ' (exception was: %r)' % self.args[1]
- return res
+ self.add_tag(name)
+ if docstring:
+ namespace = '.'.join(self.namespace)
+ if namespace.startswith(self.scope):
+ self.collected[namespace, name] = docstring
class ModuleAnalyzer(object):
@@ -173,33 +177,11 @@ class ModuleAnalyzer(object):
return entry
try:
- if modname not in sys.modules:
- try:
- __import__(modname)
- except ImportError, err:
- raise PycodeError('error importing %r' % modname, err)
- mod = sys.modules[modname]
- if hasattr(mod, '__loader__'):
- try:
- source = mod.__loader__.get_source(modname)
- except Exception, err:
- raise PycodeError('error getting source for %r' % modname,
- err)
+ type, source = get_module_source(modname)
+ if type == 'string':
obj = cls.for_string(source, modname)
- cls.cache['module', modname] = obj
- return obj
- filename = getattr(mod, '__file__', None)
- if filename is None:
- raise PycodeError('no source found for module %r' % modname)
- filename = path.normpath(path.abspath(filename))
- lfilename = filename.lower()
- if lfilename.endswith('.pyo') or lfilename.endswith('.pyc'):
- filename = filename[:-1]
- elif not lfilename.endswith('.py'):
- raise PycodeError('source is not a .py file: %r' % filename)
- if not path.isfile(filename):
- raise PycodeError('source file is not present: %r' % filename)
- obj = cls.for_file(filename, modname)
+ else:
+ obj = cls.for_file(source, modname)
except PycodeError, err:
cls.cache['module', modname] = err
raise
@@ -214,12 +196,18 @@ class ModuleAnalyzer(object):
# file-like object yielding source lines
self.source = source
+ # cache the source code as well
+ pos = self.source.tell()
+ self.code = self.source.read()
+ self.source.seek(pos)
+
# will be filled by tokenize()
self.tokens = None
# will be filled by parse()
self.parsetree = None
# will be filled by find_attr_docs()
self.attr_docs = None
+ self.tagorder = None
# will be filled by find_tags()
self.tags = None
@@ -257,6 +245,7 @@ class ModuleAnalyzer(object):
attr_visitor = AttrDocVisitor(number2name, scope, self.encoding)
attr_visitor.visit(self.parsetree)
self.attr_docs = attr_visitor.collected
+ self.tagorder = attr_visitor.tagorder
# now that we found everything we could in the tree, throw it away
# (it takes quite a bit of memory for large modules)
self.parsetree = None
diff --git a/sphinx/pycode/pgen2/driver.py b/sphinx/pycode/pgen2/driver.py
index edc882fa..39e347b7 100644
--- a/sphinx/pycode/pgen2/driver.py
+++ b/sphinx/pycode/pgen2/driver.py
@@ -35,7 +35,7 @@ class Driver(object):
def parse_tokens(self, tokens, debug=False):
"""Parse a series of tokens and return the syntax tree."""
- # XXX Move the prefix computation into a wrapper around tokenize.
+ # X X X Move the prefix computation into a wrapper around tokenize.
p = parse.Parser(self.grammar, self.convert)
p.setup()
lineno = 1
diff --git a/sphinx/pycode/pgen2/grammar.py b/sphinx/pycode/pgen2/grammar.py
index 381d80e8..5a433578 100644
--- a/sphinx/pycode/pgen2/grammar.py
+++ b/sphinx/pycode/pgen2/grammar.py
@@ -16,7 +16,7 @@ fallback token code OP, but the parser needs the actual token code.
import pickle
# Local imports
-from sphinx.pycode.pgen2 import token, tokenize
+from sphinx.pycode.pgen2 import token
class Grammar(object):
diff --git a/sphinx/pycode/pgen2/pgen.py b/sphinx/pycode/pgen2/pgen.py
index d6895eae..0a04447d 100644
--- a/sphinx/pycode/pgen2/pgen.py
+++ b/sphinx/pycode/pgen2/pgen.py
@@ -54,12 +54,12 @@ class ParserGenerator(object):
first = {}
for label in rawfirst:
ilabel = self.make_label(c, label)
- ##assert ilabel not in first # XXX failed on <> ... !=
+ ##assert ilabel not in first # X X X failed on <> ... !=
first[ilabel] = 1
return first
def make_label(self, c, label):
- # XXX Maybe this should be a method on a subclass of converter?
+ # X X X Maybe this should be a method on a subclass of converter?
ilabel = len(c.labels)
if label[0].isalpha():
# Either a symbol name or a named token
@@ -157,9 +157,9 @@ class ParserGenerator(object):
#self.dump_nfa(name, a, z)
dfa = self.make_dfa(a, z)
#self.dump_dfa(name, dfa)
- oldlen = len(dfa)
+ #oldlen = len(dfa)
self.simplify_dfa(dfa)
- newlen = len(dfa)
+ #newlen = len(dfa)
dfas[name] = dfa
#print name, oldlen, newlen
if startsymbol is None:
diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py
index 7e261e4b..8479575a 100644
--- a/sphinx/quickstart.py
+++ b/sphinx/quickstart.py
@@ -164,7 +164,7 @@ html_static_path = ['%(dot)sstatic']
#html_additional_pages = {}
# If false, no module index is generated.
-#html_use_modindex = True
+#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
@@ -223,16 +223,28 @@ latex_documents = [
#latex_appendices = []
# If false, no module index is generated.
-#latex_use_modindex = True
+#latex_domain_indices = True
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('%(master_str)s', '%(project_manpage)s', u'%(project_doc)s',
+ [u'%(author_str)s'], 1)
+]
+'''
+
+EPUB_CONFIG = '''
+
# -- Options for Epub output ---------------------------------------------------
# Bibliographic Dublin Core info.
-#epub_title = ''
-#epub_author = ''
-#epub_publisher = ''
-#epub_copyright = ''
+epub_title = u'%(project_str)s'
+epub_author = u'%(author_str)s'
+epub_publisher = u'%(author_str)s'
+epub_copyright = u'%(copyright_str)s'
# The language of the text. It defaults to the language option
# or en if the language is not set.
@@ -308,8 +320,8 @@ PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) \
$(SPHINXOPTS) %(rsrcdir)s
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp epub \
-latex changes linkcheck doctest
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp \
+epub latex latexpdf text man changes linkcheck doctest
help:
\t@echo "Please use \\`make <target>' where <target> is one of"
@@ -324,6 +336,8 @@ help:
\t@echo " epub to make an epub"
\t@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
\t@echo " latexpdf to make LaTeX files and run them through pdflatex"
+\t@echo " text to make text files"
+\t@echo " man to make manual pages"
\t@echo " changes to make an overview of all changed/added/deprecated items"
\t@echo " linkcheck to check all external links for integrity"
\t@echo " doctest to run all doctests embedded in the documentation \
@@ -373,12 +387,12 @@ qthelp:
\t@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/%(project_fn)s.qhc"
devhelp:
-\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) %(rbuilddir)s/devhelp
+\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
\t@echo
\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\
+\t@echo "# ln -s $(BUILDDIR)/devhelp\
$$HOME/.local/share/devhelp/%(project_fn)s"
\t@echo "# devhelp"
@@ -395,10 +409,20 @@ latex:
\t "run these through (pdf)latex."
latexpdf: latex
-\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) %(rbuilddir)s/latex
+\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
\t@echo "Running LaTeX files through pdflatex..."
-\tmake -C %(rbuilddir)s/latex all-pdf
-\t@echo "pdflatex finished; the PDF files are in %(rbuilddir)s/latex."
+\tmake -C $(BUILDDIR)/latex all-pdf
+\t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+\t@echo
+\t@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+\t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+\t@echo
+\t@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@@ -446,6 +470,8 @@ if "%%1" == "help" (
\techo. devhelp to make HTML files and a Devhelp project
\techo. epub to make an epub
\techo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+\techo. text to make text files
+\techo. man to make manual pages
\techo. changes to make an overview over all changed/added/deprecated items
\techo. linkcheck to check all external links for integrity
\techo. doctest to run all doctests embedded in the documentation if enabled
@@ -513,7 +539,7 @@ if "%%1" == "qthelp" (
)
if "%%1" == "devhelp" (
-\t%%SPHINXBUILD%% -b devhelp %%ALLSPHINXOPTS%% %(rbuilddir)s/devhelp
+\t%%SPHINXBUILD%% -b devhelp %%ALLSPHINXOPTS%% %%BUILDDIR%%/devhelp
\techo.
\techo.Build finished.
\tgoto end
@@ -533,6 +559,20 @@ if "%%1" == "latex" (
\tgoto end
)
+if "%%1" == "text" (
+\t%%SPHINXBUILD%% -b text %%ALLSPHINXOPTS%% %%BUILDDIR%%/text
+\techo.
+\techo.Build finished. The text files are in %%BUILDDIR%%/text.
+\tgoto end
+)
+
+if "%%1" == "man" (
+\t%%SPHINXBUILD%% -b man %%ALLSPHINXOPTS%% %%BUILDDIR%%/man
+\techo.
+\techo.Build finished. The manual pages are in %%BUILDDIR%%/man.
+\tgoto end
+)
+
if "%%1" == "changes" (
\t%%SPHINXBUILD%% -b changes %%ALLSPHINXOPTS%% %%BUILDDIR%%/changes
\techo.
@@ -706,6 +746,11 @@ document is a custom template, you can also set this to another filename.'''
'existing file and press Enter', d['master'])
print '''
+Sphinx can also add configuration for epub output:'''
+ do_prompt(d, 'epub', 'Do you want to use the epub builder (y/N)',
+ 'n', boolean)
+
+ print '''
Please indicate if you want to use one of the following Sphinx extensions:'''
do_prompt(d, 'ext_autodoc', 'autodoc: automatically insert docstrings '
'from modules (y/N)', 'n', boolean)
@@ -726,6 +771,8 @@ Please indicate if you want to use one of the following Sphinx extensions:'''
pngmath has been deselected.'''
do_prompt(d, 'ext_ifconfig', 'ifconfig: conditional inclusion of '
'content based on config values (y/N)', 'n', boolean)
+ do_prompt(d, 'ext_viewcode', 'viewcode: include links to the source code '
+ 'of documented Python objects (y/N)', 'n', boolean)
print '''
A Makefile and a Windows command file can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
@@ -735,12 +782,13 @@ directly.'''
'y', boolean)
d['project_fn'] = make_filename(d['project'])
+ d['project_manpage'] = d['project_fn'].lower()
d['now'] = time.asctime()
d['underline'] = len(d['project']) * '='
d['extensions'] = ', '.join(
repr('sphinx.ext.' + name)
for name in ('autodoc', 'doctest', 'intersphinx', 'todo', 'coverage',
- 'pngmath', 'jsmath', 'ifconfig')
+ 'pngmath', 'jsmath', 'ifconfig', 'viewcode')
if d['ext_' + name])
d['copyright'] = time.strftime('%Y') + ', ' + d['author']
d['author_texescaped'] = unicode(d['author']).\
@@ -751,7 +799,7 @@ directly.'''
# escape backslashes and single quotes in strings that are put into
# a Python string literal
- for key in ('project', 'copyright', 'author_texescaped',
+ for key in ('project', 'copyright', 'author', 'author_texescaped',
'project_doc_texescaped', 'version', 'release', 'master'):
d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'")
@@ -772,6 +820,8 @@ directly.'''
mkdir_p(path.join(srcdir, d['dot'] + 'static'))
conf_text = QUICKSTART_CONF % d
+ if d['epub']:
+ conf_text += EPUB_CONFIG % d
if d['ext_intersphinx']:
conf_text += INTERSPHINX_CONFIG
diff --git a/sphinx/roles.py b/sphinx/roles.py
index 6dfcb760..e93e00d6 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -10,11 +10,13 @@
"""
import re
+import warnings
from docutils import nodes, utils
from docutils.parsers.rst import roles
from sphinx import addnodes
+from sphinx.locale import _
from sphinx.util import ws_re
from sphinx.util.nodes import split_explicit_title
@@ -29,36 +31,147 @@ 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,
}
for rolename, nodeclass in generic_docroles.iteritems():
- role = roles.GenericRole(rolename, nodeclass)
+ generic = roles.GenericRole(rolename, nodeclass)
+ role = roles.CustomRole(rolename, generic, {'classes': [rolename]})
roles.register_local_role(rolename, role)
+# -- generic cross-reference role ----------------------------------------------
+
+class XRefRole(object):
+ """
+ A generic cross-referencing role. To create a callable that can be used as
+ a role function, create an instance of this class.
+
+ The general features of this role are:
+
+ * Automatic creation of a reference and a content node.
+ * Optional separation of title and target with `title <target>`.
+ * The implementation is a class rather than a function to make
+ customization easier.
+
+ Customization can be done in two ways:
+
+ * Supplying constructor parameters:
+ * `fix_parens` to normalize parentheses (strip from target, and add to
+ title if configured)
+ * `lowercase` to lowercase the target
+ * `nodeclass` and `innernodeclass` select the node classes for
+ the reference and the content node
+
+ * Subclassing and overwriting `process_link()` and/or `result_nodes()`.
+ """
+
+ nodeclass = addnodes.pending_xref
+ innernodeclass = nodes.literal
+
+ def __init__(self, fix_parens=False, lowercase=False,
+ nodeclass=None, innernodeclass=None):
+ self.fix_parens = fix_parens
+ self.lowercase = lowercase
+ if nodeclass is not None:
+ self.nodeclass = nodeclass
+ if innernodeclass is not None:
+ self.innernodeclass = innernodeclass
+
+ def _fix_parens(self, env, has_explicit_title, title, target):
+ if not has_explicit_title:
+ if title.endswith('()'):
+ # remove parentheses
+ title = title[:-2]
+ if env.config.add_function_parentheses:
+ # add them back to all occurrences if configured
+ title += '()'
+ # remove parentheses from the target too
+ if target.endswith('()'):
+ target = target[:-2]
+ return title, target
+
+ def __call__(self, typ, rawtext, text, lineno, inliner,
+ options={}, content=[]):
+ env = inliner.document.settings.env
+ if not typ:
+ typ = env.config.default_role
+ else:
+ typ = typ.lower()
+ if ':' not in typ:
+ domain, role = '', typ
+ classes = ['xref', role]
+ else:
+ domain, role = typ.split(':', 1)
+ classes = ['xref', domain, '%s-%s' % (domain, role)]
+ # if the first character is a bang, don't cross-reference at all
+ if text[0:1] == '!':
+ text = utils.unescape(text)
+ if self.fix_parens:
+ text, tgt = self._fix_parens(env, False, text[1:], "")
+ innernode = self.innernodeclass(rawtext, text, classes=classes)
+ return self.result_nodes(inliner.document, env, innernode,
+ is_ref=False)
+ # split title and target in role content
+ has_explicit_title, title, target = split_explicit_title(text)
+ title = utils.unescape(title)
+ target = utils.unescape(target)
+ # fix-up title and target
+ if self.lowercase:
+ target = target.lower()
+ if self.fix_parens:
+ title, target = self._fix_parens(
+ env, has_explicit_title, title, target)
+ # create the reference node
+ refnode = self.nodeclass(rawtext, reftype=role, refdomain=domain,
+ refexplicit=has_explicit_title)
+ # we may need the line number for warnings
+ refnode.line = lineno
+ title, target = self.process_link(
+ env, refnode, has_explicit_title, title, target)
+ # now that the target and title are finally determined, set them
+ refnode['reftarget'] = target
+ refnode += self.innernodeclass(rawtext, title, classes=classes)
+ # we also need the source document
+ refnode['refdoc'] = env.docname
+ # result_nodes allow further modification of return values
+ return self.result_nodes(inliner.document, env, refnode, is_ref=True)
+
+ # methods that can be overwritten
+
+ def process_link(self, env, refnode, has_explicit_title, title, target):
+ """
+ Called after parsing title and target text, and creating the reference
+ node (given in *refnode*). This method can alter the reference node and
+ must return a new (or the same) ``(title, target)`` tuple.
+ """
+ return title, ws_re.sub(' ', target)
+
+ def result_nodes(self, document, env, node, is_ref):
+ """
+ Called before returning the finished nodes. *node* is the reference
+ node if one was created (*is_ref* is then true), else the content node.
+ This method can add other nodes and must return a ``(nodes, messages)``
+ tuple (the usual return value of a role function).
+ """
+ return [node], []
+
+
def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
options={}, content=[]):
+ """Role for PEP/RFC references that generate an index entry."""
env = inliner.document.settings.env
if not typ:
typ = env.config.default_role
else:
typ = typ.lower()
text = utils.unescape(etext)
- targetid = 'index-%s' % env.index_num
- env.index_num += 1
+ targetid = 'index-%s' % env.new_serialno('index')
indexnode = addnodes.index()
targetnode = nodes.target('', '', ids=[targetid])
inliner.document.note_explicit_target(targetnode)
- if typ == 'envvar':
- 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]
- return [indexnode, targetnode] + xref_nodes, []
- elif typ == 'pep':
+ if typ == 'pep':
indexnode['entries'] = [
('single', _('Python Enhancement Proposals!PEP %s') % text,
targetid, 'PEP %s' % text)]
@@ -71,7 +184,7 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
return [prb], [msg]
ref = inliner.document.settings.pep_base_url + 'pep-%04d' % pepnum
sn = nodes.strong('PEP '+text, 'PEP '+text)
- rn = nodes.reference('', '', refuri=ref)
+ rn = nodes.reference('', '', refuri=ref, classes=[typ])
rn += sn
return [indexnode, targetnode, rn], []
elif typ == 'rfc':
@@ -86,122 +199,16 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
return [prb], [msg]
ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum
sn = nodes.strong('RFC '+text, 'RFC '+text)
- rn = nodes.reference('', '', refuri=ref)
+ rn = nodes.reference('', '', refuri=ref, classes=[typ])
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['refdoc'] = env.docname
- 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}'))], []
+ rawtext, utils.unescape(text).replace('-->', u'\N{TRIANGULAR BULLET}'),
+ classes=[typ])], []
+ return role
_litvar_re = re.compile('{([^}]+)}')
@@ -210,7 +217,7 @@ def emph_literal_role(typ, rawtext, text, lineno, inliner,
options={}, content=[]):
text = utils.unescape(text)
pos = 0
- retnode = nodes.literal(role=typ.lower())
+ retnode = nodes.literal(role=typ.lower(), classes=[typ])
for m in _litvar_re.finditer(text):
if m.start() > pos:
txt = text[pos:m.start()]
@@ -235,30 +242,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,
+ # links to download references
+ 'download': XRefRole(nodeclass=addnodes.download_reference),
+ # links to headings or arbitrary labels
+ 'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
+ # links to documents
+ 'doc': XRefRole(),
+ # links to labels, without a different title
+ 'keyword': XRefRole(),
+ 'pep': indexmarkup_role,
+ 'rfc': indexmarkup_role,
'menuselection': menusel_role,
'file': emph_literal_role,
'samp': emph_literal_role,
@@ -267,3 +261,10 @@ specific_docroles = {
for rolename, func in specific_docroles.iteritems():
roles.register_local_role(rolename, func)
+
+
+# backwards compatibility alias
+def xfileref_role(*args, **kwds):
+ warnings.warn('xfileref_role is deprecated, use XRefRole',
+ DeprecationWarning, stacklevel=2)
+ return XRefRole()(*args, **kwds)
diff --git a/sphinx/search.py b/sphinx/search.py
index 7161bc4c..17a8354d 100644
--- a/sphinx/search.py
+++ b/sphinx/search.py
@@ -119,8 +119,10 @@ class IndexBuilder(object):
self._titles = {}
# stemmed word -> set(filenames)
self._mapping = {}
- # desctypes -> index
- self._desctypes = {}
+ # objtype -> index
+ self._objtypes = {}
+ # objtype index -> objname (localized)
+ self._objnames = {}
def load(self, stream, format):
"""Reconstruct from frozen data."""
@@ -138,7 +140,7 @@ class IndexBuilder(object):
self._mapping[k] = set([index2fn[v]])
else:
self._mapping[k] = set(index2fn[i] for i in v)
- # no need to load keywords/desctypes
+ # no need to load keywords/objtypes
def dump(self, stream, format):
"""Dump the frozen index to a stream."""
@@ -146,27 +148,30 @@ class IndexBuilder(object):
format = self.formats[format]
format.dump(self.freeze(), stream)
- def get_modules(self, fn2index):
+ def get_objects(self, fn2index):
rv = {}
- for name, (doc, _, _, _) in self.env.modules.iteritems():
- if doc in fn2index:
- rv[name] = fn2index[doc]
- return rv
-
- def get_descrefs(self, fn2index):
- rv = {}
- dt = self._desctypes
- for fullname, (doc, desctype) in self.env.descrefs.iteritems():
- if doc not in fn2index:
- continue
- prefix, name = rpartition(fullname, '.')
- pdict = rv.setdefault(prefix, {})
- try:
- i = dt[desctype]
- except KeyError:
- i = len(dt)
- dt[desctype] = i
- pdict[name] = (fn2index[doc], i)
+ otypes = self._objtypes
+ onames = self._objnames
+ for domainname, domain in self.env.domains.iteritems():
+ for fullname, type, docname, anchor, prio in domain.get_objects():
+ if docname not in fn2index:
+ continue
+ if prio < 0:
+ continue
+ # XXX splitting at dot is kind of Python specific
+ prefix, name = rpartition(fullname, '.')
+ pdict = rv.setdefault(prefix, {})
+ try:
+ i = otypes[domainname, type]
+ except KeyError:
+ i = len(otypes)
+ otypes[domainname, type] = i
+ otype = domain.object_types.get(type)
+ if otype:
+ onames[i] = str(otype.lname) # fire translation proxies
+ else:
+ onames[i] = type
+ pdict[name] = (fn2index[docname], i, prio)
return rv
def get_terms(self, fn2index):
@@ -185,14 +190,13 @@ class IndexBuilder(object):
filenames = self._titles.keys()
titles = self._titles.values()
fn2index = dict((f, i) for (i, f) in enumerate(filenames))
- return dict(
- filenames=filenames,
- titles=titles,
- terms=self.get_terms(fn2index),
- descrefs=self.get_descrefs(fn2index),
- modules=self.get_modules(fn2index),
- desctypes=dict((v, k) for (k, v) in self._desctypes.items()),
- )
+ terms = self.get_terms(fn2index)
+ objects = self.get_objects(fn2index) # populates _objtypes
+ objtypes = dict((v, k[0] + ':' + k[1])
+ for (k, v) in self._objtypes.iteritems())
+ objnames = self._objnames
+ return dict(filenames=filenames, titles=titles, terms=terms,
+ objects=objects, objtypes=objtypes, objnames=objnames)
def prune(self, filenames):
"""Remove data for all filenames not in the list."""
diff --git a/sphinx/texinputs/Makefile b/sphinx/texinputs/Makefile
index 5c0d5018..d5a73f5b 100644
--- a/sphinx/texinputs/Makefile
+++ b/sphinx/texinputs/Makefile
@@ -37,7 +37,6 @@ bz2: tar
latex $(LATEXOPTS) '$<'
latex $(LATEXOPTS) '$<'
-makeindex -s python.ist '$(basename $<).idx'
- -makeindex -s python.ist '$(basename mod$<).idx'
latex $(LATEXOPTS) '$<'
latex $(LATEXOPTS) '$<'
@@ -46,7 +45,6 @@ bz2: tar
pdflatex $(LATEXOPTS) '$<'
pdflatex $(LATEXOPTS) '$<'
-makeindex -s python.ist '$(basename $<).idx'
- -makeindex -s python.ist '$(basename mod$<).idx'
pdflatex $(LATEXOPTS) '$<'
pdflatex $(LATEXOPTS) '$<'
diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty
index 7525126e..52c069f1 100644
--- a/sphinx/texinputs/sphinx.sty
+++ b/sphinx/texinputs/sphinx.sty
@@ -6,7 +6,7 @@
%
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
-\ProvidesPackage{sphinx}[2008/05/01 LaTeX package (Sphinx markup)]
+\ProvidesPackage{sphinx}[2010/01/15 LaTeX package (Sphinx markup)]
\RequirePackage{textcomp}
\RequirePackage{fancyhdr}
@@ -130,8 +130,6 @@
\newcommand{\samp}[1]{`\code{#1}'}
\newcommand{\email}[1]{\textsf{#1}}
-\newcommand{\py@modulebadkey}{{--just-some-junk--}}
-
% Redefine the Verbatim environment to allow border and background colors.
% The original environment is still used for verbatims within tables.
\let\OriginalVerbatim=\Verbatim
@@ -193,89 +191,12 @@
\index{#4!#1 #2 #3}
}
-% support for the module index
-\newif\ifpy@UseModuleIndex
-\py@UseModuleIndexfalse
-
-\newcommand{\makemodindex}{
- \newwrite\modindexfile
- \openout\modindexfile=mod\jobname.idx
- \py@UseModuleIndextrue
-}
-
-\newcommand{\printmodindex}{
- \@input@{mod\jobname.ind}
-}
-
-% Add the defining entry for a module
-\newcommand{\py@modindex}[2]{%
- \renewcommand{\py@thismodule}{#1}
- \ifpy@UseModuleIndex%
- \@ifundefined{py@modplat@\py@thismodulekey}{
- \write\modindexfile{\protect\indexentry{#1@{\texttt{#1}}|hyperpage}{\thepage}}%
- }{\write\modindexfile{\protect\indexentry{#1@{\texttt{#1 }%
- \emph{(\platformof{\py@thismodulekey})}}|hyperpage}{\thepage}}%
- }
- \fi%
-}
-
-% "Current" keys
-\newcommand{\py@thisclass}{}
-\newcommand{\py@thismodule}{}
-\newcommand{\py@thismodulekey}{}
-\newcommand{\py@thismoduletype}{}
-\newcommand{\py@emptymodule}{}
-
-% \declaremodule[key]{type}{name}
-\newcommand{\declaremodule}[3][\py@modulebadkey]{
- \renewcommand{\py@thismoduletype}{#2}
- \ifx\py@modulebadkey#1
- \renewcommand{\py@thismodulekey}{#3}
- \else
- \renewcommand{\py@thismodulekey}{#1}
- \fi
- \py@modindex{#3}{}
- %\label{module-\py@thismodulekey}
-}
-
-% Record module platforms for the Module Index
-\newif\ifpy@ModPlatformFileIsOpen \py@ModPlatformFileIsOpenfalse
-\long\def\py@writeModPlatformFile#1{%
- \protected@write\py@ModPlatformFile%
- {\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}%
- {\string#1}%
-}
-\newcommand{\py@ModPlatformFilename}{\jobname.pla}
-\newcommand{\platform}[1]{
- \ifpy@ModPlatformFileIsOpen\else
- \newwrite\py@ModPlatformFile
- \openout\py@ModPlatformFile=\py@ModPlatformFilename
- \py@ModPlatformFileIsOpentrue
- \fi
- \py@writeModPlatformFile{\py@defplatform{\py@thismodulekey}{#1}}
-}
-\newcommand{\py@defplatform}[2]{\expandafter\def\csname py@modplat@#1\endcsname{#2}}
-\newcommand{\platformof}[1]{\csname py@modplat@#1\endcsname}
-
-\InputIfFileExists{\jobname.pla}{}{}
-
% \moduleauthor{name}{email}
\newcommand{\moduleauthor}[2]{}
% \sectionauthor{name}{email}
\newcommand{\sectionauthor}[2]{}
-% Ignore module synopsis.
-\newcommand{\modulesynopsis}[1]{}
-
-% Reset "current" objects.
-\newcommand{\resetcurrentobjects}{
- \renewcommand{\py@thisclass}{}
- \renewcommand{\py@thismodule}{}
- \renewcommand{\py@thismodulekey}{}
- \renewcommand{\py@thismoduletype}{}
-}
-
% Augment the sectioning commands used to get our own font family in place,
% and reset some internal data items:
\titleformat{\section}{\Large\py@HeaderFamily}%
@@ -287,14 +208,7 @@
\titleformat{\paragraph}{\large\py@HeaderFamily}%
{\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor}
-
-% Now for a lot of semantically-loaded environments that do a ton of magical
-% things to get the right formatting and index entries for the stuff in
-% Python modules and C API.
-
-
-% {fulllineitems} is used in one place in libregex.tex, but is really for
-% internal use in this file.
+% {fulllineitems} is the main environment for object descriptions.
%
\newcommand{\py@itemnewline}[1]{%
\@tempdima\linewidth%
@@ -308,222 +222,19 @@
\let\makelabel=\py@itemnewline}
}{\end{list}}
-% \optional is mostly for use in the arguments parameters to the various
-% {*desc} environments defined below, but may be used elsewhere. Known to
-% be used in the debugger chapter.
-%
-% Typical usage:
-%
-% \begin{funcdesc}{myfunc}{reqparm\optional{, optparm}}
-% ^^^ ^^^
-% No space here No space here
-%
-% When a function has multiple optional parameters, \optional should be
-% nested, not chained. This is right:
-%
-% \begin{funcdesc}{myfunc}{\optional{parm1\optional{, parm2}}}
-%
-\let\py@badkey=\@undefined
-
+% \optional is used for ``[, arg]``, i.e. desc_optional nodes.
\newcommand{\optional}[1]{%
{\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}}
-% This can be used when a function or method accepts an varying number
-% of arguments, such as by using the *args syntax in the parameter list.
-\newcommand{\py@moreargs}{...}
-
-% This can be used when you don't want to document the parameters to a
-% function or method, but simply state that it's an alias for
-% something else.
-\newcommand{\py@unspecified}{...}
-
-\newcommand{\py@varvars}[1]{{%
- {\let\unspecified=\py@unspecified%
- \let\moreargs=\py@moreargs%
- \emph{#1}}}}
-
\newlength{\py@argswidth}
-\newcommand{\py@sigparams}[1]{%
- \parbox[t]{\py@argswidth}{\py@varvars{#1}\code{)}}}
-\newcommand{\py@sigline}[2]{%
+\newcommand{\py@sigparams}[2]{%
+ \parbox[t]{\py@argswidth}{#1\code{)}#2}}
+\newcommand{\pysigline}[1]{\item[#1]\nopagebreak}
+\newcommand{\pysiglinewithargsret}[3]{%
\settowidth{\py@argswidth}{#1\code{(}}%
\addtolength{\py@argswidth}{-2\py@argswidth}%
\addtolength{\py@argswidth}{\textwidth}%
- \item[#1\code{(}\py@sigparams{#2}]}
-
-% C functions ------------------------------------------------------------
-% \begin{cfuncdesc}[refcount]{type}{name}{arglist}
-% Note that the [refcount] slot should only be filled in by
-% tools/anno-api.py; it pulls the value from the refcounts database.
-\newcommand{\cfuncline}[3]{
- \py@sigline{\code{#1 \bfcode{#2}}}{#3}%
-}
-\newenvironment{cfuncdesc}[3]{
- \begin{fulllineitems}
- \cfuncline{#1}{#2}{#3}
-}{\end{fulllineitems}}
-
-% C variables ------------------------------------------------------------
-% \begin{cvardesc}{type}{name}
-\newenvironment{cvardesc}[2]{
- \begin{fulllineitems}
- \item[\code{#1 \bfcode{#2}}]
-}{\end{fulllineitems}}
-
-% C data types -----------------------------------------------------------
-% \begin{ctypedesc}[index name]{typedef name}
-\newenvironment{ctypedesc}[2][\py@badkey]{
- \begin{fulllineitems}
- \item[\bfcode{#2}]
-}{\end{fulllineitems}}
-
-% C type fields ----------------------------------------------------------
-% \begin{cmemberdesc}{container type}{ctype}{membername}
-\newcommand{\cmemberline}[3]{
- \item[\code{#2 \bfcode{#3}}]
-}
-\newenvironment{cmemberdesc}[3]{
- \begin{fulllineitems}
- \cmemberline{#1}{#2}{#3}
-}{\end{fulllineitems}}
-
-% Funky macros -----------------------------------------------------------
-% \begin{csimplemacrodesc}{name}
-% -- "simple" because it has no args; NOT for constant definitions!
-\newenvironment{csimplemacrodesc}[1]{
- \begin{fulllineitems}
- \item[\bfcode{#1}]
-}{\end{fulllineitems}}
-
-% simple functions (not methods) -----------------------------------------
-% \begin{funcdesc}{name}{args}
-\newcommand{\funcline}[2]{%
- \py@sigline{\bfcode{#1}}{#2}}
-\newenvironment{funcdesc}[2]{
- \begin{fulllineitems}
- \funcline{#1}{#2}
-}{\end{fulllineitems}}
-
-% classes ----------------------------------------------------------------
-% \begin{classdesc}{name}{constructor args}
-\newcommand{\classline}[2]{
- \py@sigline{\strong{class }\bfcode{#1}}{#2}}
-\newenvironment{classdesc}[2]{
- % Using \renewcommand doesn't work for this, for unknown reasons:
- \global\def\py@thisclass{#1}
- \begin{fulllineitems}
- \classline{#1}{#2}
-}{\end{fulllineitems}}
-
-% \begin{excclassdesc}{name}{constructor args}
-% but indexes as an exception
-\newenvironment{excclassdesc}[2]{
- % Using \renewcommand doesn't work for this, for unknown reasons:
- \global\def\py@thisclass{#1}
- \begin{fulllineitems}
- \py@sigline{\strong{exception }\bfcode{#1}}{#2}%
-}{\end{fulllineitems}}
-
-% There is no corresponding {excclassdesc*} environment. To describe
-% a class exception without parameters, use the {excdesc} environment.
-
-
-\let\py@classbadkey=\@undefined
-
-% object method ----------------------------------------------------------
-% \begin{methoddesc}[classname]{methodname}{args}
-\newcommand{\methodline}[3][\@undefined]{
- \py@sigline{\bfcode{#2}}{#3}}
-\newenvironment{methoddesc}[3][\@undefined]{
- \begin{fulllineitems}
- \ifx\@undefined#1\relax
- \methodline{#2}{#3}
- \else
- \def\py@thisclass{#1}
- \methodline{#2}{#3}
- \fi
-}{\end{fulllineitems}}
-
-% static method ----------------------------------------------------------
-% \begin{staticmethoddesc}[classname]{methodname}{args}
-\newcommand{\staticmethodline}[3][\@undefined]{
- \py@sigline{static \bfcode{#2}}{#3}}
-\newenvironment{staticmethoddesc}[3][\@undefined]{
- \begin{fulllineitems}
- \ifx\@undefined#1\relax
- \staticmethodline{#2}{#3}
- \else
- \def\py@thisclass{#1}
- \staticmethodline{#2}{#3}
- \fi
-}{\end{fulllineitems}}
-
-% class method ----------------------------------------------------------
-% \begin{classmethoddesc}[classname]{methodname}{args}
-\newcommand{\classmethodline}[3][\@undefined]{
- \py@sigline{class \bfcode{#2}}{#3}}
-\newenvironment{classmethoddesc}[3][\@undefined]{
- \begin{fulllineitems}
- \ifx\@undefined#1\relax
- \classmethodline{#2}{#3}
- \else
- \def\py@thisclass{#1}
- \classmethodline{#2}{#3}
- \fi
-}{\end{fulllineitems}}
-
-% object data attribute --------------------------------------------------
-% \begin{memberdesc}[classname]{membername}
-\newcommand{\memberline}[2][\py@classbadkey]{%
- \ifx\@undefined#1\relax
- \item[\bfcode{#2}]
- \else
- \item[\bfcode{#2}]
- \fi
-}
-\newenvironment{memberdesc}[2][\py@classbadkey]{
- \begin{fulllineitems}
- \ifx\@undefined#1\relax
- \memberline{#2}
- \else
- \def\py@thisclass{#1}
- \memberline{#2}
- \fi
-}{\end{fulllineitems}}
-
-% For exceptions: --------------------------------------------------------
-% \begin{excdesc}{name}
-% -- for constructor information, use excclassdesc instead
-\newenvironment{excdesc}[1]{
- \begin{fulllineitems}
- \item[\strong{exception }\bfcode{#1}]
-}{\end{fulllineitems}}
-
-% Module data or constants: ----------------------------------------------
-% \begin{datadesc}{name}
-\newcommand{\dataline}[1]{%
- \item[\bfcode{#1}]\nopagebreak}
-\newenvironment{datadesc}[1]{
- \begin{fulllineitems}
- \dataline{#1}
-}{\end{fulllineitems}}
-
-% bytecode instruction ---------------------------------------------------
-% \begin{opcodedesc}{name}{var}
-% -- {var} may be {}
-\newenvironment{opcodedesc}[2]{
- \begin{fulllineitems}
- \item[\bfcode{#1}\quad\emph{#2}]
-}{\end{fulllineitems}}
-
-% generic description ----------------------------------------------------
-\newcommand{\descline}[1]{%
- \item[\bfcode{#1}]\nopagebreak%
-}
-\newenvironment{describe}[1]{
- \begin{fulllineitems}
- \descline{#1}
-}{\end{fulllineitems}}
+ \item[#1\code{(}\py@sigparams{#2}{#3}]}
% This version is being checked in for the historical record; it shows
% how I've managed to get some aspects of this to work. It will not
@@ -533,9 +244,10 @@
% the example completely.
%
\newcommand{\grammartoken}[1]{\texttt{#1}}
-\newenvironment{productionlist}[1][\py@badkey]{
+\newenvironment{productionlist}[1][\@undefined]{
\def\optional##1{{\Large[}##1{\Large]}}
- \def\production##1##2{\code{##1}&::=&\code{##2}\\}
+ \def\production##1##2{\hypertarget{grammar-token-##1}{}%
+ \code{##1}&::=&\code{##2}\\}
\def\productioncont##1{& &\code{##1}\\}
\def\token##1{##1}
\let\grammartoken=\token
@@ -728,8 +440,7 @@
% Include hyperref last.
\RequirePackage[colorlinks,breaklinks,
linkcolor=InnerLinkColor,filecolor=OuterLinkColor,
- menucolor=OuterLinkColor,pagecolor=OuterLinkColor,
- urlcolor=OuterLinkColor]{hyperref}
+ menucolor=OuterLinkColor,urlcolor=OuterLinkColor]{hyperref}
% From docutils.writers.latex2e
\providecommand{\DUspan}[2]{%
diff --git a/sphinx/themes/agogo/static/agogo.css_t b/sphinx/themes/agogo/static/agogo.css_t
index 777035bd..d2233dfb 100644
--- a/sphinx/themes/agogo/static/agogo.css_t
+++ b/sphinx/themes/agogo/static/agogo.css_t
@@ -118,6 +118,10 @@ p.admonition-title {
font-weight: bold;
}
+dt:target, .highlighted {
+ background-color: #fbe54e;
+}
+
/* Header */
div.header {
@@ -398,3 +402,21 @@ img.toggler {
cursor: pointer;
}
+/* -- viewcode extension ---------------------------------------------------- */
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family:: {{ theme_bodyfont }};
+}
+
+div.viewcode-block:target {
+ margin: -1px -3px;
+ padding: 0 3px;
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
diff --git a/sphinx/themes/basic/domainindex.html b/sphinx/themes/basic/domainindex.html
new file mode 100644
index 00000000..0aca7e69
--- /dev/null
+++ b/sphinx/themes/basic/domainindex.html
@@ -0,0 +1,57 @@
+{#
+ basic/domainindex.html
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ Template for domain indices (module index, ...).
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{% extends "layout.html" %}
+{% set title = indextitle %}
+{% block extrahead %}
+{{ super() }}
+{% if not embedded and collapse_index %}
+ <script type="text/javascript">
+ DOCUMENTATION_OPTIONS.COLLAPSE_INDEX = true;
+ </script>
+{% endif %}
+{% endblock %}
+{% block body %}
+
+ {%- set curr_group = 0 %}
+
+ <h1>{{ indextitle }}</h1>
+
+ <div class="modindex-jumpbox">
+ {%- for (letter, entries) in content %}
+ <a href="#cap-{{ letter }}"><strong>{{ letter }}</strong></a>
+ {%- if not loop.last %} | {% endif %}
+ {%- endfor %}
+ </div>
+
+ <table class="indextable modindextable" cellspacing="0" cellpadding="2">
+ {%- for letter, entries in content %}
+ <tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-{{ letter }}">
+ <strong>{{ letter }}</strong></a></td><td></td></tr>
+ {%- for (name, grouptype, page, anchor, extra, qualifier, description)
+ in entries %}
+ {%- if grouptype == 1 %}{% set curr_group = curr_group + 1 %}{% endif %}
+ <tr{% if grouptype == 2 %} class="cg-{{ curr_group }}"{% endif %}>
+ <td>{% if grouptype == 1 -%}
+ <img src="{{ pathto('_static/minus.png', 1) }}" id="toggle-{{ curr_group }}"
+ class="toggler" style="display: none" alt="-" />
+ {%- endif %}</td>
+ <td>{% if grouptype == 2 %}&nbsp;&nbsp;&nbsp;{% endif %}
+ {% if page %}<a href="{{ pathto(page) }}#{{ anchor }}">{% endif -%}
+ <tt class="xref">{{ name|e }}</tt>
+ {%- if page %}</a>{% endif %}
+ {%- if extra %} <em>({{ extra|e }})</em>{% endif -%}
+ </td><td>{% if qualifier %}<strong>{{ qualifier|e }}:</strong>{% endif %}
+ <em>{{ description|e }}</em></td></tr>
+ {%- endfor %}
+ {%- endfor %}
+ </table>
+
+{% endblock %}
diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html
index d3ef88ab..c844dabc 100644
--- a/sphinx/themes/basic/layout.html
+++ b/sphinx/themes/basic/layout.html
@@ -98,7 +98,7 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '{{ pathto("", 1) }}',
VERSION: '{{ release|e }}',
- COLLAPSE_MODINDEX: false,
+ COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ file_suffix }}',
HAS_SOURCE: {{ has_source|lower }}
};
diff --git a/sphinx/themes/basic/modindex.html b/sphinx/themes/basic/modindex.html
deleted file mode 100644
index 96f8ac43..00000000
--- a/sphinx/themes/basic/modindex.html
+++ /dev/null
@@ -1,52 +0,0 @@
-{#
- basic/modindex.html
- ~~~~~~~~~~~~~~~~~~~
-
- Template for the module index.
-
- :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-#}
-{% 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="indextable modindextable" cellspacing="0" cellpadding="2">
- {%- for modname, collapse, cgroup, indent, fname, synops, pform, dep, stripped in modindexentries %}
- {%- if not modname -%}
- <tr class="pcap"><td></td><td>&nbsp;</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 %}&nbsp;&nbsp;&nbsp;{% 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/basic/static/basic.css b/sphinx/themes/basic/static/basic.css
index bd0a8544..7cfacd5b 100644
--- a/sphinx/themes/basic/static/basic.css
+++ b/sphinx/themes/basic/static/basic.css
@@ -316,7 +316,7 @@ dd {
margin-left: 30px;
}
-dt:target, .highlight {
+dt:target, .highlighted {
background-color: #fbe54e;
}
@@ -408,6 +408,20 @@ h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
background-color: transparent;
}
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+ margin: -1px -10px;
+ padding: 0 10px;
+}
+
/* -- math display ---------------------------------------------------------- */
img.math {
diff --git a/sphinx/themes/basic/static/doctools.js b/sphinx/themes/basic/static/doctools.js
index c2bd1ac5..23e217c3 100644
--- a/sphinx/themes/basic/static/doctools.js
+++ b/sphinx/themes/basic/static/doctools.js
@@ -17,14 +17,15 @@ $u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
- */
if (!window.console || !console.firebug) {
- var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
- "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
+ "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
+ "profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
+ */
/**
* small helper function to urldecode strings
@@ -81,7 +82,7 @@ jQuery.fn.highlightText = function(text, className) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
- if (pos >= 0 && !jQuery.className.has(node.parentNode, className)) {
+ if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
@@ -110,7 +111,7 @@ var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
- this.initModIndex();
+ this.initIndexTable();
},
/**
@@ -181,7 +182,7 @@ var Documentation = {
var body = $('div.body');
window.setTimeout(function() {
$.each(terms, function() {
- body.highlightText(this.toLowerCase(), 'highlight');
+ body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<li class="highlight-link"><a href="javascript:Documentation.' +
@@ -191,19 +192,19 @@ var Documentation = {
},
/**
- * init the modindex toggle buttons
+ * init the domain index toggle buttons
*/
- initModIndex : function() {
+ initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
- console.log($('tr.cg-' + idnum).toggle());
+ $('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
- if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) {
+ if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
@@ -213,7 +214,7 @@ var Documentation = {
*/
hideSearchWords : function() {
$('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
- $('span.highlight').removeClass('highlight');
+ $('span.highlighted').removeClass('highlighted');
},
/**
diff --git a/sphinx/themes/basic/static/jquery.js b/sphinx/themes/basic/static/jquery.js
index 82b98e1d..5c70e4c5 100644
--- a/sphinx/themes/basic/static/jquery.js
+++ b/sphinx/themes/basic/static/jquery.js
@@ -1,32 +1,151 @@
-/*
- * jQuery 1.2.6 - New Wave Javascript
+/*!
+ * jQuery JavaScript Library v1.4
+ * http://jquery.com/
*
- * Copyright (c) 2008 John Resig (jquery.com)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://docs.jquery.com/License
*
- * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
- * $Rev: 5685 $
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Wed Jan 13 15:23:05 2010 -0500
*/
-(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
-return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
-return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
-selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
-return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
-this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
-return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
-jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
-script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
-for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
-for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
-jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
-ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
-while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
-while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
-for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
-jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
-xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
-jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
-for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
-s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
-e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})(); \ No newline at end of file
+(function(A,w){function oa(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(oa,1);return}c.ready()}}function La(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function $(a,b,d,f,e,i){var j=a.length;if(typeof b==="object"){for(var o in b)$(a,o,b[o],f,e,d);return a}if(d!==w){f=!i&&f&&c.isFunction(d);for(o=0;o<j;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,i);return a}return j?
+e(a[0],b):null}function K(){return(new Date).getTime()}function aa(){return false}function ba(){return true}function pa(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function qa(a){var b=true,d=[],f=[],e=arguments,i,j,o,p,n,t=c.extend({},c.data(this,"events").live);for(p in t){j=t[p];if(j.live===a.type||j.altLive&&c.inArray(a.type,j.altLive)>-1){i=j.data;i.beforeFilter&&i.beforeFilter[a.type]&&!i.beforeFilter[a.type](a)||f.push(j.selector)}else delete t[p]}i=c(a.target).closest(f,a.currentTarget);
+n=0;for(l=i.length;n<l;n++)for(p in t){j=t[p];o=i[n].elem;f=null;if(i[n].selector===j.selector){if(j.live==="mouseenter"||j.live==="mouseleave")f=c(a.relatedTarget).closest(j.selector)[0];if(!f||f!==o)d.push({elem:o,fn:j})}}n=0;for(l=d.length;n<l;n++){i=d[n];a.currentTarget=i.elem;a.data=i.fn.data;if(i.fn.apply(i.elem,e)===false){b=false;break}}return b}function ra(a,b){return["live",a,b.replace(/\./g,"`").replace(/ /g,"&")].join(".")}function sa(a){return!a||!a.parentNode||a.parentNode.nodeType===
+11}function ta(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var i in f)for(var j in f[i])c.event.add(this,i,f[i][j],f[i][j].data)}}})}function ua(a,b,d){var f,e,i;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&a[0].indexOf("<option")<0){e=true;if(i=c.fragments[a[0]])if(i!==1)f=i}if(!f){b=b&&b[0]?b[0].ownerDocument||b[0]:s;f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=
+i?f:1;return{fragment:f,cacheable:e}}function T(a){for(var b=0,d,f;(d=a[b])!=null;b++)if(!c.noData[d.nodeName.toLowerCase()]&&(f=d[H]))delete c.cache[f]}function L(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ma=A.jQuery,Na=A.$,s=A.document,U,Oa=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Pa=/^.[^:#\[\.,]*$/,Qa=/\S/,
+Ra=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Sa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],M,ca=Object.prototype.toString,da=Object.prototype.hasOwnProperty,ea=Array.prototype.push,R=Array.prototype.slice,V=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(typeof a==="string")if((d=Oa.exec(a))&&(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Sa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];
+c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=ua([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return U.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a)}else return!b||b.jquery?(b||U).find(a):c(b).find(a);else if(c.isFunction(a))return U.ready(a);if(a.selector!==w){this.selector=a.selector;
+this.context=a.context}return c.isArray(a)?this.setArray(a):c.makeArray(a,this)},selector:"",jquery:"1.4",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){a=c(a||null);a.prevObject=this;a.context=this.context;if(b==="find")a.selector=this.selector+(this.selector?" ":"")+d;else if(b)a.selector=this.selector+"."+b+"("+d+")";return a},setArray:function(a){this.length=
+0;ea.apply(this,a);return this},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||
+c(null)},push:ea,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,i,j,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(i in e){j=a[i];o=e[i];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){j=j&&(c.isPlainObject(j)||c.isArray(j))?j:c.isArray(o)?[]:{};a[i]=c.extend(f,j,o)}else if(o!==w)a[i]=
+o}return a};c.extend({noConflict:function(a){A.$=Na;if(a)A.jQuery=Ma;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",M,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",
+M);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&oa()}}},isFunction:function(a){return ca.call(a)==="[object Function]"},isArray:function(a){return ca.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||ca.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!da.call(a,"constructor")&&!da.call(a.constructor.prototype,"isPrototypeOf"))return false;var b;for(b in a);return b===w||da.call(a,b)},
+isEmptyObject:function(a){for(var b in a)return false;return true},noop:function(){},globalEval:function(a){if(a&&Qa.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,i=a.length,j=i===w||c.isFunction(a);
+if(d)if(j)for(f in a){if(b.apply(a[f],d)===false)break}else for(;e<i;){if(b.apply(a[e++],d)===false)break}else if(j)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<i&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Ra,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ea.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=
+0,f=b.length;d<f;d++)if(b[d]===a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,i=a.length;e<i;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,i=0,j=a.length;i<j;i++){e=b(a[i],i,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b===
+"string"){d=a;a=d[b];b=w}else if(b&&!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){var b={browser:""};a=a.toLowerCase();if(/webkit/.test(a))b={browser:"webkit",version:/webkit[\/ ]([\w.]+)/};else if(/opera/.test(a))b={browser:"opera",version:/version/.test(a)?/version[\/ ]([\w.]+)/:/opera[\/ ]([\w.]+)/};else if(/msie/.test(a))b={browser:"msie",version:/msie ([\w.]+)/};else if(/mozilla/.test(a)&&
+!/compatible/.test(a))b={browser:"mozilla",version:/rv:([\w.]+)/};b.version=(b.version&&b.version.exec(a)||[0,"0"])[1];return b},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=true;if(V)c.inArray=function(a,b){return V.call(b,a)};U=c(s);if(s.addEventListener)M=function(){s.removeEventListener("DOMContentLoaded",M,false);c.ready()};else if(s.attachEvent)M=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",
+M);c.ready()}};if(V)c.inArray=function(a,b){return V.call(b,a)};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+K();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=d.getElementsByTagName("*"),i=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!i)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,
+htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55$/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(j){}a.insertBefore(b,
+a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function o(){c.support.noCloneEvent=false;d.detachEvent("onclick",o)});d.cloneNode(true).fireEvent("onclick")}c(function(){var o=s.createElement("div");o.style.width=o.style.paddingLeft="1px";s.body.appendChild(o);c.boxModel=c.support.boxModel=o.offsetWidth===2;s.body.removeChild(o).style.display="none"});a=function(o){var p=s.createElement("div");o="on"+o;var n=o in
+p;if(!n){p.setAttribute(o,"return;");n=typeof p[o]==="function"}return n};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=i=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var H="jQuery"+K(),Ta=0,ya={},Ua={};c.extend({cache:{},expando:H,noData:{embed:true,object:true,applet:true},data:function(a,
+b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?ya:a;var f=a[H],e=c.cache;if(!b&&!f)return null;f||(f=++Ta);if(typeof b==="object"){a[H]=f;e=e[f]=c.extend(true,{},b)}else e=e[f]?e[f]:typeof d==="undefined"?Ua:(e[f]={});if(d!==w){a[H]=f;e[b]=d}return typeof b==="string"?e[b]:e}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?ya:a;var d=a[H],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{try{delete a[H]}catch(i){a.removeAttribute&&
+a.removeAttribute(H)}delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,
+a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,
+a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var za=/[\n\t]/g,fa=/\s+/,Va=/\r/g,Wa=/href|src|style/,Xa=/(button|input)/i,Ya=/(button|input|object|select|textarea)/i,Za=/^(a|area)$/i,Aa=/radio|checkbox/;c.fn.extend({attr:function(a,
+b){return $(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(p){var n=c(this);n.addClass(a.call(this,p,n.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(fa),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className)for(var i=" "+e.className+" ",j=0,o=b.length;j<o;j++){if(i.indexOf(" "+b[j]+" ")<0)e.className+=
+" "+b[j]}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(p){var n=c(this);n.removeClass(a.call(this,p,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(fa),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var i=(" "+e.className+" ").replace(za," "),j=0,o=b.length;j<o;j++)i=i.replace(" "+b[j]+" "," ");e.className=i.substring(1,i.length-1)}else e.className=""}return this},toggleClass:function(a,
+b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var i=c(this);i.toggleClass(a.call(this,e,i.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,i=0,j=c(this),o=b,p=a.split(fa);e=p[i++];){o=f?o:!j.hasClass(e);j[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=
+" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(za," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var i=b?d:0;for(d=b?d+1:e.length;i<d;i++){var j=e[i];if(j.selected){a=c(j).val();if(b)return a;f.push(a)}}return f}if(Aa.test(b.type)&&
+!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Va,"")}return w}var o=c.isFunction(a);return this.each(function(p){var n=c(this),t=a;if(this.nodeType===1){if(o)t=a.call(this,p,n.val());if(typeof t==="number")t+="";if(c.isArray(t)&&Aa.test(this.type))this.checked=c.inArray(n.val(),t)>=0;else if(c.nodeName(this,"select")){var z=c.makeArray(t);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),z)>=0});if(!z.length)this.selectedIndex=
+-1}else this.value=t}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var i=Wa.test(b);if(b in a&&f&&!i){if(e){if(b==="type"&&Xa.test(a.nodeName)&&a.parentNode)throw"type property can't be changed";a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;
+if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Ya.test(a.nodeName)||Za.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&i?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var $a=function(a){return a.replace(/[^\w\s\.\|`]/g,function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===
+3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;if(!d.guid)d.guid=c.guid++;if(f!==w){d=c.proxy(d);d.data=f}var e=c.data(a,"events")||c.data(a,"events",{}),i=c.data(a,"handle"),j;if(!i){j=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(j.elem,arguments):w};i=c.data(a,"handle",j)}if(i){i.elem=a;b=b.split(/\s+/);for(var o,p=0;o=b[p++];){var n=o.split(".");o=n.shift();d.type=n.slice(0).sort().join(".");var t=e[o],z=this.special[o]||{};if(!t){t=e[o]={};
+if(!z.setup||z.setup.call(a,f,n,d)===false)if(a.addEventListener)a.addEventListener(o,i,false);else a.attachEvent&&a.attachEvent("on"+o,i)}if(z.add)if((n=z.add.call(a,d,f,n,t))&&c.isFunction(n)){n.guid=n.guid||d.guid;d=n}t[d.guid]=d;this.global[o]=true}a=null}}},global:{},remove:function(a,b,d){if(!(a.nodeType===3||a.nodeType===8)){var f=c.data(a,"events"),e,i,j;if(f){if(b===w||typeof b==="string"&&b.charAt(0)===".")for(i in f)this.remove(a,i+(b||""));else{if(b.type){d=b.handler;b=b.type}b=b.split(/\s+/);
+for(var o=0;i=b[o++];){var p=i.split(".");i=p.shift();var n=!p.length,t=c.map(p.slice(0).sort(),$a);t=new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.)?")+"(\\.|$)");var z=this.special[i]||{};if(f[i]){if(d){j=f[i][d.guid];delete f[i][d.guid]}else for(var B in f[i])if(n||t.test(f[i][B].type))delete f[i][B];z.remove&&z.remove.call(a,p,j);for(e in f[i])break;if(!e){if(!z.teardown||z.teardown.call(a,p)===false)if(a.removeEventListener)a.removeEventListener(i,c.data(a,"handle"),false);else a.detachEvent&&a.detachEvent("on"+
+i,c.data(a,"handle"));e=null;delete f[i]}}}}for(e in f)break;if(!e){if(B=c.data(a,"handle"))B.elem=null;c.removeData(a,"events");c.removeData(a,"handle")}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[H]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();this.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
+8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;var i=c.data(d,"handle");i&&i.apply(d,b);var j,o;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()])){j=d[e];o=d["on"+e]}}catch(p){}i=c.nodeName(d,"a")&&e==="click";if(!f&&j&&!a.isDefaultPrevented()&&!i){this.triggered=true;try{d[e]()}catch(n){}}else if(o&&d["on"+e].apply(d,b)===false)a.result=false;this.triggered=false;if(!a.isPropagationStopped())(d=d.parentNode||d.ownerDocument)&&c.event.trigger(a,b,d,true)},
+handle:function(a){var b,d;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;d=a.type.split(".");a.type=d.shift();b=!d.length&&!a.exclusive;var f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)");d=(c.data(this,"events")||{})[a.type];for(var e in d){var i=d[e];if(b||f.test(i.type)){a.handler=i;a.data=i.data;i=i.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}return a.result},
+props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[H])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||
+s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&
+a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a,b){c.extend(a,b||{});a.guid+=b.selector+b.live;c.event.add(this,b.live,qa,b)},remove:function(a){if(a.length){var b=0,d=new RegExp("(^|\\.)"+a[0]+"(\\.|$)");c.each(c.data(this,"events").live||{},function(){d.test(this.type)&&b++});b<1&&c.event.remove(this,a[0],qa)}},special:{}},beforeunload:{setup:function(a,
+b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=K();this[H]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ba;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=
+ba;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ba;this.stopPropagation()},isDefaultPrevented:aa,isPropagationStopped:aa,isImmediatePropagationStopped:aa};var Ba=function(a){for(var b=a.relatedTarget;b&&b!==this;)try{b=b.parentNode}catch(d){break}if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}},Ca=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",
+mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ca:Ba,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ca:Ba)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(a,b,d){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="submit"||i==="image")&&c(e).closest("form").length)return pa("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit."+
+d.guid,function(f){var e=f.target,i=e.type;if((i==="text"||i==="password")&&c(e).closest("form").length&&f.keyCode===13)return pa("submit",this,arguments)})}else return false},remove:function(a,b){c.event.remove(this,"click.specialSubmit"+(b?"."+b.guid:""));c.event.remove(this,"keypress.specialSubmit"+(b?"."+b.guid:""))}};if(!c.support.changeBubbles){var ga=/textarea|input|select/i;function Da(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>
+-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d}function ha(a,b){var d=a.target,f,e;if(!(!ga.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Da(d);if(e!==f){if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",e);if(d.type!=="select"&&(f!=null||e)){a.type="change";return c.event.trigger(a,b,this)}}}}c.event.special.change={filters:{focusout:ha,click:function(a){var b=a.target,d=b.type;if(d===
+"radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return ha.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return ha.call(this,a)},beforeactivate:function(a){a=a.target;a.nodeName.toLowerCase()==="input"&&a.type==="radio"&&c.data(a,"_change_data",Da(a))}},setup:function(a,b,d){for(var f in W)c.event.add(this,f+".specialChange."+d.guid,W[f]);return ga.test(this.nodeName)},
+remove:function(a,b){for(var d in W)c.event.remove(this,d+".specialChange"+(b?"."+b.guid:""),W[d]);return ga.test(this.nodeName)}};var W=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,
+f,e){if(typeof d==="object"){for(var i in d)this[b](i,f,d[i],e);return this}if(c.isFunction(f)){thisObject=e;e=f;f=w}var j=b==="one"?c.proxy(e,function(o){c(this).unbind(o,j);return e.apply(this,arguments)}):e;return d==="unload"&&b!=="one"?this.one(d,f,e,thisObject):this.each(function(){c.event.add(this,d,j,f)})}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault){for(var d in a)this.unbind(d,a[d]);return this}return this.each(function(){c.event.remove(this,a,b)})},trigger:function(a,
+b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||
+a)},live:function(a,b,d){if(c.isFunction(b)){d=b;b=w}c(this.context).bind(ra(a,this.selector),{data:b,selector:this.selector,live:a},d);return this},die:function(a,b){c(this.context).unbind(ra(a,this.selector),b?{guid:b.guid+this.selector+a}:null);return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d){return d?
+this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",k,m=0;g[m];m++){k=g[m];if(k.nodeType===3||k.nodeType===4)h+=k.nodeValue;else if(k.nodeType!==8)h+=a(k.childNodes)}return h}function b(g,h,k,m,r,q){r=0;for(var v=m.length;r<v;r++){var u=m[r];if(u){u=u[g];for(var y=false;u;){if(u.sizcache===
+k){y=m[u.sizset];break}if(u.nodeType===1&&!q){u.sizcache=k;u.sizset=r}if(u.nodeName.toLowerCase()===h){y=u;break}u=u[g]}m[r]=y}}}function d(g,h,k,m,r,q){r=0;for(var v=m.length;r<v;r++){var u=m[r];if(u){u=u[g];for(var y=false;u;){if(u.sizcache===k){y=m[u.sizset];break}if(u.nodeType===1){if(!q){u.sizcache=k;u.sizset=r}if(typeof h!=="string"){if(u===h){y=true;break}}else if(p.filter(h,[u]).length>0){y=u;break}}u=u[g]}m[r]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,i=Object.prototype.toString,j=false,o=true;[0,0].sort(function(){o=false;return 0});var p=function(g,h,k,m){k=k||[];var r=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return k;for(var q=[],v,u,y,S,I=true,N=x(h),J=g;(f.exec(""),v=f.exec(J))!==null;){J=v[3];q.push(v[1]);if(v[2]){S=v[3];break}}if(q.length>1&&t.exec(g))if(q.length===2&&n.relative[q[0]])u=ia(q[0]+q[1],h);else for(u=n.relative[q[0]]?[h]:p(q.shift(),h);q.length;){g=q.shift();if(n.relative[g])g+=q.shift();
+u=ia(g,u)}else{if(!m&&q.length>1&&h.nodeType===9&&!N&&n.match.ID.test(q[0])&&!n.match.ID.test(q[q.length-1])){v=p.find(q.shift(),h,N);h=v.expr?p.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:q.pop(),set:B(m)}:p.find(q.pop(),q.length===1&&(q[0]==="~"||q[0]==="+")&&h.parentNode?h.parentNode:h,N);u=v.expr?p.filter(v.expr,v.set):v.set;if(q.length>0)y=B(u);else I=false;for(;q.length;){var E=q.pop();v=E;if(n.relative[E])v=q.pop();else E="";if(v==null)v=h;n.relative[E](y,v,N)}}else y=[]}y||(y=u);if(!y)throw"Syntax error, unrecognized expression: "+
+(E||g);if(i.call(y)==="[object Array]")if(I)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&F(h,y[g])))k.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&k.push(u[g]);else k.push.apply(k,y);else B(y,k);if(S){p(S,r,k,m);p.uniqueSort(k)}return k};p.uniqueSort=function(g){if(D){j=o;g.sort(D);if(j)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};p.matches=function(g,h){return p(g,null,null,h)};p.find=function(g,h,k){var m,r;if(!g)return[];
+for(var q=0,v=n.order.length;q<v;q++){var u=n.order[q];if(r=n.leftMatch[u].exec(g)){var y=r[1];r.splice(1,1);if(y.substr(y.length-1)!=="\\"){r[1]=(r[1]||"").replace(/\\/g,"");m=n.find[u](r,h,k);if(m!=null){g=g.replace(n.match[u],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};p.filter=function(g,h,k,m){for(var r=g,q=[],v=h,u,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var I in n.filter)if((u=n.leftMatch[I].exec(g))!=null&&u[2]){var N=n.filter[I],J,E;E=u[1];y=false;u.splice(1,1);if(E.substr(E.length-
+1)!=="\\"){if(v===q)q=[];if(n.preFilter[I])if(u=n.preFilter[I](u,v,k,q,m,S)){if(u===true)continue}else y=J=true;if(u)for(var X=0;(E=v[X])!=null;X++)if(E){J=N(E,u,X,v);var Ea=m^!!J;if(k&&J!=null)if(Ea)y=true;else v[X]=false;else if(Ea){q.push(E);y=true}}if(J!==w){k||(v=q);g=g.replace(n.match[I],"");if(!y)return[];break}}}if(g===r)if(y==null)throw"Syntax error, unrecognized expression: "+g;else break;r=g}return v};var n=p.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var k=typeof h==="string",m=k&&!/\W/.test(h);k=k&&!m;if(m)h=h.toLowerCase();m=0;for(var r=g.length,q;m<r;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=k||q&&q.nodeName.toLowerCase()===h?q||false:q===h}k&&p.filter(h,g,true)},">":function(g,h){var k=typeof h==="string";if(k&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,r=g.length;m<r;m++){var q=g[m];if(q){k=q.parentNode;g[m]=k.nodeName.toLowerCase()===h?k:false}}}else{m=0;for(r=g.length;m<r;m++)if(q=g[m])g[m]=
+k?q.parentNode:q.parentNode===h;k&&p.filter(h,g,true)}},"":function(g,h,k){var m=e++,r=d;if(typeof h==="string"&&!/\W/.test(h)){var q=h=h.toLowerCase();r=b}r("parentNode",h,m,g,q,k)},"~":function(g,h,k){var m=e++,r=d;if(typeof h==="string"&&!/\W/.test(h)){var q=h=h.toLowerCase();r=b}r("previousSibling",h,m,g,q,k)}},find:{ID:function(g,h,k){if(typeof h.getElementById!=="undefined"&&!k)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var k=[];
+h=h.getElementsByName(g[1]);for(var m=0,r=h.length;m<r;m++)h[m].getAttribute("name")===g[1]&&k.push(h[m]);return k.length===0?null:k}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,k,m,r,q){g=" "+g[1].replace(/\\/g,"")+" ";if(q)return g;q=0;for(var v;(v=h[q])!=null;q++)if(v)if(r^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))k||m.push(v);else if(k)h[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,k,m,r,q){h=g[1].replace(/\\/g,"");if(!q&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,k,m,r){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=p(g[3],null,null,h);else{g=p.filter(g[3],h,k,true^r);k||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,k){return!!p(k[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,k,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,k){return h<k[3]-0},gt:function(g,h,k){return h>k[3]-0},nth:function(g,h,k){return k[3]-0===h},eq:function(g,h,k){return k[3]-0===h}},filter:{PSEUDO:function(g,h,k,m){var r=h[1],q=n.filters[r];if(q)return q(g,k,h,m);else if(r==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(r==="not"){h=
+h[3];k=0;for(m=h.length;k<m;k++)if(h[k]===g)return false;return true}else throw"Syntax error, unrecognized expression: "+r;},CHILD:function(g,h){var k=h[1],m=g;switch(k){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(k==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":k=h[2];var r=h[3];if(k===1&&r===0)return true;h=h[0];var q=g.parentNode;if(q&&(q.sizcache!==h||!g.nodeIndex)){var v=0;for(m=q.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;q.sizcache=h}g=g.nodeIndex-r;return k===0?g===0:g%k===0&&g/k>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var k=h[1];g=n.attrHandle[k]?n.attrHandle[k](g):g[k]!=null?g[k]:g.getAttribute(k);k=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?k===h:m==="*="?k.indexOf(h)>=0:m==="~="?(" "+k+" ").indexOf(h)>=0:!h?k&&g!==false:m==="!="?k!==h:m==="^="?k.indexOf(h)===0:m==="$="?k.substr(k.length-h.length)===h:m==="|="?k===h||k.substr(0,h.length+1)===h+"-":false},POS:function(g,h,k,m){var r=n.setFilters[h[2]];if(r)return r(g,k,h,m)}}},t=n.match.POS;for(var z in n.match){n.match[z]=new RegExp(n.match[z].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[z]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[z].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var B=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){B=function(g,h){h=h||[];if(i.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var k=0,m=g.length;k<m;k++)h.push(g[k]);else for(k=0;g[k];k++)h.push(g[k]);return h}}var D;if(s.documentElement.compareDocumentPosition)D=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)j=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)j=true;return g};else if("sourceIndex"in s.documentElement)D=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)j=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)j=true;return g};else if(s.createRange)D=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)j=true;return g.ownerDocument?-1:1}var k=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();k.setStart(g,0);k.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=k.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)j=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var k=s.documentElement;k.insertBefore(g,k.firstChild);if(s.getElementById(h)){n.find.ID=function(m,r,q){if(typeof r.getElementById!=="undefined"&&!q)return(r=r.getElementById(m[1]))?r.id===m[1]||typeof r.getAttributeNode!=="undefined"&&
+r.getAttributeNode("id").nodeValue===m[1]?[r]:w:[]};n.filter.ID=function(m,r){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===r}}k.removeChild(g);k=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,k){k=k.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;k[m];m++)k[m].nodeType===1&&h.push(k[m]);k=h}return k};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=p,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){p=function(m,r,q,v){r=r||s;if(!v&&r.nodeType===9&&!x(r))try{return B(r.querySelectorAll(m),q)}catch(u){}return g(m,r,q,v)};for(var k in g)p[k]=g[k];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,k,m){if(typeof k.getElementsByClassName!=="undefined"&&!m)return k.getElementsByClassName(h[1])};g=null}}})();var F=s.compareDocumentPosition?function(g,h){return g.compareDocumentPosition(h)&16}:function(g,
+h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ia=function(g,h){var k=[],m="",r;for(h=h.nodeType?[h]:h;r=n.match.PSEUDO.exec(g);){m+=r[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;r=0;for(var q=h.length;r<q;r++)p(g,h[r],k);return p.filter(m,k)};c.find=p;c.expr=p.selectors;c.expr[":"]=c.expr.filters;c.unique=p.uniqueSort;c.getText=a;c.isXMLDoc=x;c.contains=F})();var ab=/Until$/,bb=/^(?:parents|prevUntil|prevAll)/,
+cb=/,/;R=Array.prototype.slice;var Fa=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,i){return!!b.call(e,i,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Pa.test(b))return c.filter(b,f,!d);else b=c.filter(b,a)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var i=d;i<b.length;i++)for(var j=0;j<d;j++)if(b[j]===b[i]){b.splice(i--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Fa(this,a,false),"not",a)},filter:function(a){return this.pushStack(Fa(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,i=
+{},j;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){j=a[e];i[j]||(i[j]=c.expr.match.POS.test(j)?c(j,b||this.context):j)}for(;f&&f.ownerDocument&&f!==b;){for(j in i){e=i[j];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:j,elem:f});delete i[j]}}f=f.parentNode}}return d}var p=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,t){for(;t&&t.ownerDocument&&t!==b;){if(p?p.index(t)>-1:c(t).is(a))return t;t=t.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(sa(a[0])||sa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);ab.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||cb.test(f))&&bb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ga=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,db=/(<([\w:]+)[^>]*?)\/>/g,eb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,Ha=/<([\w:]+)/,fb=/<tbody/i,gb=/<|&\w+;/,hb=function(a,b,d){return eb.test(d)?a:b+"></"+d+">"},G={option:[1,"<select multiple='multiple'>","</select>"],
+legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};G.optgroup=G.option;G.tbody=G.tfoot=G.colgroup=G.caption=G.thead;G.th=G.td;if(!c.support.htmlSerialize)G._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);
+return d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.getText(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&
+this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,
+"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ga,"").replace(Y,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ta(this,b);ta(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===
+1?this[0].innerHTML.replace(Ga,""):null;else if(typeof a==="string"&&!/<script/i.test(a)&&(c.support.leadingWhitespace||!Y.test(a))&&!G[(Ha.exec(a)||["",""])[1].toLowerCase()])try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){T(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}else c.isFunction(a)?this.each(function(e){var i=c(this),j=i.html();i.empty().append(function(){return a.call(this,e,j)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){c.isFunction(a)||(a=c(a).detach());return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(t){return c.nodeName(t,"table")?t.getElementsByTagName("tbody")[0]||t.appendChild(t.ownerDocument.createElement("tbody")):t}var e,i,j=a[0],o=[];if(c.isFunction(j))return this.each(function(t){var z=
+c(this);a[0]=j.call(this,t,b?z.html():w);return z.domManip(a,b,d)});if(this[0]){e=a[0]&&a[0].parentNode&&a[0].parentNode.nodeType===11?{fragment:a[0].parentNode}:ua(a,this,o);if(i=e.fragment.firstChild){b=b&&c.nodeName(i,"tr");for(var p=0,n=this.length;p<n;p++)d.call(b?f(this[p],i):this[p],e.cacheable||this.length>1||p>0?e.fragment.cloneNode(true):e.fragment)}o&&c.each(o,La)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},
+function(a,b){c.fn[a]=function(d){var f=[];d=c(d);for(var e=0,i=d.length;e<i;e++){var j=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),j);f=f.concat(j)}return this.pushStack(f,a,d.selector)}});c.each({remove:function(a,b){if(!a||c.filter(a,[this]).length){if(!b&&this.nodeType===1){T(this.getElementsByTagName("*"));T([this])}this.parentNode&&this.parentNode.removeChild(this)}},empty:function(){for(this.nodeType===1&&T(this.getElementsByTagName("*"));this.firstChild;)this.removeChild(this.firstChild)}},
+function(a,b){c.fn[a]=function(){return this.each(b,arguments)}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;var e=[];c.each(a,function(i,j){if(typeof j==="number")j+="";if(j){if(typeof j==="string"&&!gb.test(j))j=b.createTextNode(j);else if(typeof j==="string"){j=j.replace(db,hb);var o=(Ha.exec(j)||["",""])[1].toLowerCase(),p=G[o]||G._default,n=p[0];i=b.createElement("div");for(i.innerHTML=p[1]+j+p[2];n--;)i=i.lastChild;
+if(!c.support.tbody){n=fb.test(j);o=o==="table"&&!n?i.firstChild&&i.firstChild.childNodes:p[1]==="<table>"&&!n?i.childNodes:[];for(p=o.length-1;p>=0;--p)c.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!c.support.leadingWhitespace&&Y.test(j)&&i.insertBefore(b.createTextNode(Y.exec(j)[0]),i.firstChild);j=c.makeArray(i.childNodes)}if(j.nodeType)e.push(j);else e=c.merge(e,j)}});if(d)for(a=0;e[a];a++)if(f&&c.nodeName(e[a],"script")&&(!e[a].type||e[a].type.toLowerCase()===
+"text/javascript"))f.push(e[a].parentNode?e[a].parentNode.removeChild(e[a]):e[a]);else{e[a].nodeType===1&&e.splice.apply(e,[a+1,0].concat(c.makeArray(e[a].getElementsByTagName("script"))));d.appendChild(e[a])}return e}});var ib=/z-?index|font-?weight|opacity|zoom|line-?height/i,Ia=/alpha\([^)]*\)/,Ja=/opacity=([^)]*)/,ja=/float/i,ka=/-([a-z])/ig,jb=/([A-Z])/g,kb=/^-?\d+(?:px)?$/i,lb=/^-?\d/,mb={position:"absolute",visibility:"hidden",display:"block"},nb=["Left","Right"],ob=["Top","Bottom"],pb=s.defaultView&&
+s.defaultView.getComputedStyle,Ka=c.support.cssFloat?"cssFloat":"styleFloat",la=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return $(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!ib.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""===
+"NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=Ia.test(a)?a.replace(Ia,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Ja.exec(f.filter)[1])/100+"":""}if(ja.test(b))b=Ka;b=b.replace(ka,la);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,i=b==="width"?nb:ob;function j(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(i,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=
+parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,"border"+this+"Width",true))||0})}a.offsetWidth!==0?j():c.swap(a,mb,j);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Ja.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ja.test(b))b=Ka;if(!d&&e&&e[b])f=e[b];else if(pb){if(ja.test(b))b="float";b=b.replace(jb,"-$1").toLowerCase();e=
+a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ka,la);f=a.currentStyle[b]||a.currentStyle[d];if(!kb.test(f)&&lb.test(f)){b=e.left;var i=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=i}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=
+f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var qb=K(),rb=/<script(.|\s)*?\/script>/gi,sb=/select|textarea/i,tb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,O=/=\?(&|$)/,ma=/\?/,ub=/(\?|&)_=.*?(&|$)/,vb=/^(\w+:)?\/\/([^\/?#]+)/,
+wb=/%20/g;c.fn.extend({_load:c.fn.load,load:function(a,b,d){if(typeof a!=="string")return this._load(a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}c.ajax({url:a,type:f,dataType:"html",data:b,context:this,complete:function(i,j){if(j==="success"||j==="notmodified")this.html(e?c("<div />").append(i.responseText.replace(rb,
+"")).find(e):i.responseText);d&&this.each(d,[i.responseText,j,i])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||sb.test(this.nodeName)||tb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});
+c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},
+ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",
+text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&e.success.call(p,o,j,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(p,x,j);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(r,q){(e.context?c(e.context):c.event).trigger(r,q)}var e=c.extend(true,{},c.ajaxSettings,a),i,j,o,p=e.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,
+e.traditional);if(e.dataType==="jsonp"){if(n==="GET")O.test(e.url)||(e.url+=(ma.test(e.url)?"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!O.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&O.test(e.data)||O.test(e.url))){i=e.jsonpCallback||"jsonp"+qb++;if(e.data)e.data=(e.data+"").replace(O,"="+i+"$1");e.url=e.url.replace(O,"="+i+"$1");e.dataType="script";A[i]=A[i]||function(r){o=r;b();d();A[i]=w;try{delete A[i]}catch(q){}B&&
+B.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===false&&n==="GET"){var t=K(),z=e.url.replace(ub,"$1_="+t+"$2");e.url=z+(z===e.url?(ma.test(e.url)?"&":"?")+"_="+t:"")}if(e.data&&n==="GET")e.url+=(ma.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");t=(t=vb.exec(e.url))&&(t[1]&&t[1]!==location.protocol||t[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&t){var B=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");
+C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!i){var D=false;C.onload=C.onreadystatechange=function(){if(!D&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){D=true;b();d();C.onload=C.onreadystatechange=null;B&&C.parentNode&&B.removeChild(C)}}}B.insertBefore(C,B.firstChild);return w}var F=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",
+e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}t||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ia){}if(e.beforeSend&&e.beforeSend.call(p,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",
+[x,e]);var g=x.onreadystatechange=function(r){if(!x||x.readyState===0){F||d();F=true;if(x)x.onreadystatechange=c.noop}else if(!F&&x&&(x.readyState===4||r==="timeout")){F=true;x.onreadystatechange=c.noop;j=r==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";if(j==="success")try{o=c.httpData(x,e.dataType,e)}catch(q){j="parsererror"}if(j==="success"||j==="notmodified")i||b();else c.handleError(e,x,j);d();r==="timeout"&&x.abort();if(e.async)x=
+null}};try{var h=x.abort;x.abort=function(){if(x){h.call(x);if(x)x.readyState=0}g()}}catch(k){}e.async&&e.timeout>0&&setTimeout(function(){x&&!F&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||A,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol===
+"file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;if(e&&a.documentElement.nodeName==="parsererror")throw"parsererror";if(d&&
+d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&f.indexOf("json")>=0)if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))a=A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+a))();else throw"Invalid JSON: "+a;else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(e,i){i=
+c.isFunction(i)?i():i;f[f.length]=encodeURIComponent(e)+"="+encodeURIComponent(i)}var f=[];if(b===w)b=c.ajaxSettings.traditional;c.isArray(a)||a.jquery?c.each(a,function(){d(this.name,this.value)}):c.each(a,function e(i,j){if(c.isArray(j))c.each(j,function(o,p){b?d(i,p):e(i+"["+(typeof p==="object"||c.isArray(p)?o:"")+"]",p)});else!b&&j!=null&&typeof j==="object"?c.each(j,function(o,p){e(i+"["+o+"]",p)}):d(i,j)});return f.join("&").replace(wb,"+")}});var na={},xb=/toggle|show|hide/,yb=/^([+-]=)?([\d+-.]+)(.*)$/,
+Z,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a!=null)return this.animate(L("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(na[d])f=na[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();
+na[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a!=null)return this.animate(L("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&
+c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(L("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var i=c.extend({},e),j,o=this.nodeType===1&&c(this).is(":hidden"),
+p=this;for(j in a){var n=j.replace(ka,la);if(j!==n){a[n]=a[j];delete a[j];j=n}if(a[j]==="hide"&&o||a[j]==="show"&&!o)return i.complete.call(this);if((j==="height"||j==="width")&&this.style){i.display=c.css(this,"display");i.overflow=this.style.overflow}if(c.isArray(a[j])){(i.specialEasing=i.specialEasing||{})[j]=a[j][1];a[j]=a[j][0]}}if(i.overflow!=null)this.style.overflow="hidden";i.curAnim=c.extend({},a);c.each(a,function(t,z){var B=new c.fx(p,i,t);if(xb.test(z))B[z==="toggle"?o?"show":"hide":z](a);
+else{var C=yb.exec(z),D=B.cur(true)||0;if(C){z=parseFloat(C[2]);var F=C[3]||"px";if(F!=="px"){p.style[t]=(z||1)+F;D=(z||1)/B.cur(true)*D;p.style[t]=D+F}if(C[1])z=(C[1]==="-="?-1:1)*z+D;B.custom(D,z,F)}else B.custom(D,z,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:L("show",1),slideUp:L("hide",1),slideToggle:L("toggle",
+1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration==="number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,
+b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==
+null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(i){return e.step(i)}this.startTime=K();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!Z)Z=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop===
+"width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=K(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=
+this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=
+c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},stop:function(){clearInterval(Z);Z=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=
+null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?function(a){var b=this[0];if(!b||!b.ownerDocument)return null;if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),
+f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(!b||!b.ownerDocument)return null;if(a)return this.each(function(t){c.offset.setOffset(this,a,t)});if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=
+b,e=b.ownerDocument,i,j=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var p=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==j;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;i=e?e.getComputedStyle(b,null):b.currentStyle;p-=b.scrollTop;n-=b.scrollLeft;if(b===d){p+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){p+=parseFloat(i.borderTopWidth)||
+0;n+=parseFloat(i.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&i.overflow!=="visible"){p+=parseFloat(i.borderTopWidth)||0;n+=parseFloat(i.borderLeftWidth)||0}f=i}if(f.position==="relative"||f.position==="static"){p+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){p+=Math.max(j.scrollTop,o.scrollTop);n+=Math.max(j.scrollLeft,o.scrollLeft)}return{top:p,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),
+d,f,e,i=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);
+d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i;a.removeChild(b);c.offset.initialize=c.noop},
+bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),i=parseInt(c.curCSS(a,"top",true),10)||0,j=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,d,e);d={top:b.top-e.top+i,left:b.left-
+e.left+j};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=
+this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],i;if(!e)return null;if(f!==w)return this.each(function(){if(i=wa(this))i.scrollTo(!a?f:c(i).scrollLeft(),a?f:c(i).scrollTop());else this[d]=f});else return(i=wa(e))?"pageXOffset"in i?i[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&i.document.documentElement[d]||i.document.body[d]:e[d]}});
+c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;return"scrollTo"in e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+
+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js
index bd916628..c6864fea 100644
--- a/sphinx/themes/basic/static/searchtools.js
+++ b/sphinx/themes/basic/static/searchtools.js
@@ -31,7 +31,7 @@ jQuery.makeSearchSummary = function(text, keywords, hlwords) {
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
- rv = rv.highlightText(this, 'highlight');
+ rv = rv.highlightText(this, 'highlighted');
});
return rv;
}
@@ -334,39 +334,42 @@ var Search = {
};
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
- console.debug('SEARCH: searching for:');
- console.info('required: ', searchterms);
- console.info('excluded: ', excluded);
+ // console.debug('SEARCH: searching for:');
+ // console.info('required: ', searchterms);
+ // console.info('excluded: ', excluded);
// prepare search
var filenames = this._index.filenames;
var titles = this._index.titles;
var terms = this._index.terms;
- var descrefs = this._index.descrefs;
- var modules = this._index.modules;
- var desctypes = this._index.desctypes;
+ var objects = this._index.objects;
+ var objtypes = this._index.objtypes;
+ var objnames = this._index.objnames;
var fileMap = {};
var files = null;
+ // different result priorities
+ var importantResults = [];
var objectResults = [];
var regularResults = [];
+ var unimportantResults = [];
$('#search-progress').empty();
// lookup as object
if (object != null) {
- for (var module in modules) {
- if (module.indexOf(object) > -1) {
- fn = modules[module];
- descr = _('module, in ') + titles[fn];
- objectResults.push([filenames[fn], module, '#module-'+module, descr]);
- }
- }
- for (var prefix in descrefs) {
- for (var name in descrefs[prefix]) {
+ for (var prefix in objects) {
+ for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
- match = descrefs[prefix][name];
- descr = desctypes[match[1]] + _(', in ') + titles[match[0]];
- objectResults.push([filenames[match[0]], fullname, '#'+fullname, descr]);
+ match = objects[prefix][name];
+ descr = objnames[match[1]] + _(', in ') + titles[match[0]];
+ // XXX the generated anchors are not generally correct
+ // XXX there may be custom prefixes
+ result = [filenames[match[0]], fullname, '#'+fullname, descr];
+ switch (match[2]) {
+ case 1: objectResults.push(result); break;
+ case 0: importantResults.push(result); break;
+ case 2: unimportantResults.push(result); break;
+ }
}
}
}
@@ -377,6 +380,14 @@ var Search = {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
+ importantResults.sort(function(a, b) {
+ return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
+ });
+
+ unimportantResults.sort(function(a, b) {
+ return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
+ });
+
// perform the search on the required terms
for (var i = 0; i < searchterms.length; i++) {
@@ -432,8 +443,9 @@ var Search = {
return (left > right) ? -1 : ((left < right) ? 1 : 0);
});
- // combine both
- var results = regularResults.concat(objectResults);
+ // combine all results
+ var results = unimportantResults.concat(regularResults)
+ .concat(objectResults).concat(importantResults);
// print the results
var resultCount = results.length;
diff --git a/sphinx/themes/default/static/default.css_t b/sphinx/themes/default/static/default.css_t
index 48d73d5a..579f57a4 100644
--- a/sphinx/themes/default/static/default.css_t
+++ b/sphinx/themes/default/static/default.css_t
@@ -272,3 +272,13 @@ th {
.note tt {
background: #d6d6d6;
}
+
+.viewcode-back {
+ font-family: {{ theme_bodyfont }};
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
diff --git a/sphinx/themes/epub/static/epub.css b/sphinx/themes/epub/static/epub.css
index c6320c8c..de21c462 100644
--- a/sphinx/themes/epub/static/epub.css
+++ b/sphinx/themes/epub/static/epub.css
@@ -298,7 +298,7 @@ dd {
margin-left: 30px;
}
-dt:target, .highlight {
+dt:target, .highlighted {
background-color: #ddd;
}
diff --git a/sphinx/themes/haiku/static/haiku.css_t b/sphinx/themes/haiku/static/haiku.css_t
index 7adfb0f3..93007dfb 100644
--- a/sphinx/themes/haiku/static/haiku.css_t
+++ b/sphinx/themes/haiku/static/haiku.css_t
@@ -357,3 +357,15 @@ hr {
background: #FFF;
}
}
+
+.viewcode-back {
+ font-family: "DejaVu Sans", Arial, Helvetica, sans-serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+ margin: -1px -12px;
+ padding: 0 12px;
+}
diff --git a/sphinx/themes/nature/static/nature.css_t b/sphinx/themes/nature/static/nature.css_t
index 5991e349..d0aa912b 100644
--- a/sphinx/themes/nature/static/nature.css_t
+++ b/sphinx/themes/nature/static/nature.css_t
@@ -233,3 +233,13 @@ tt {
font-size: 1.1em;
font-family: monospace;
}
+
+.viewcode-back {
+ font-family: Arial, sans-serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
diff --git a/sphinx/themes/scrolls/static/scrolls.css_t b/sphinx/themes/scrolls/static/scrolls.css_t
index 41a725a6..589f91ab 100644
--- a/sphinx/themes/scrolls/static/scrolls.css_t
+++ b/sphinx/themes/scrolls/static/scrolls.css_t
@@ -412,3 +412,20 @@ span.highlight {
margin-bottom: 0;
margin-left: 1.5em;
}
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: 'Georgia', serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+ margin: -1px -5px;
+ padding: 0 5px;
+}
diff --git a/sphinx/themes/sphinxdoc/static/sphinxdoc.css b/sphinx/themes/sphinxdoc/static/sphinxdoc.css
index 3f1e84e5..c7e6e335 100644
--- a/sphinx/themes/sphinxdoc/static/sphinxdoc.css
+++ b/sphinx/themes/sphinxdoc/static/sphinxdoc.css
@@ -326,3 +326,14 @@ div.versioninfo {
line-height: 1.3em;
font-size: 0.9em;
}
+
+.viewcode-back {
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+ 'Verdana', sans-serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
diff --git a/sphinx/themes/traditional/static/traditional.css b/sphinx/themes/traditional/static/traditional.css
index 022e55ae..c9980fa5 100644
--- a/sphinx/themes/traditional/static/traditional.css
+++ b/sphinx/themes/traditional/static/traditional.css
@@ -717,3 +717,20 @@ form.comment textarea {
display: none;
}
}
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+ margin: -1px -10px;
+ padding: 0 10px;
+}
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index 876d3fda..8d1298cd 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -25,6 +25,7 @@ from docutils.utils import relative_path
import jinja2
import sphinx
+from sphinx.errors import PycodeError
# import other utilities; partly for backwards compatibility, so don't
# prune unused ones indiscriminately
@@ -176,6 +177,38 @@ def save_traceback():
return path
+def get_module_source(modname):
+ """Try to find the source code for a module.
+
+ Can return ('file', 'filename') in which case the source is in the given
+ file, or ('string', 'source') which which case the source is the string.
+ """
+ if modname not in sys.modules:
+ try:
+ __import__(modname)
+ except Exception, err:
+ raise PycodeError('error importing %r' % modname, err)
+ mod = sys.modules[modname]
+ if hasattr(mod, '__loader__'):
+ try:
+ source = mod.__loader__.get_source(modname)
+ except Exception, err:
+ raise PycodeError('error getting source for %r' % modname, err)
+ return 'string', source
+ filename = getattr(mod, '__file__', None)
+ if filename is None:
+ raise PycodeError('no source found for module %r' % modname)
+ filename = path.normpath(path.abspath(filename))
+ lfilename = filename.lower()
+ if lfilename.endswith('.pyo') or lfilename.endswith('.pyc'):
+ filename = filename[:-1]
+ elif not lfilename.endswith('.py'):
+ raise PycodeError('source is not a .py file: %r' % filename)
+ if not path.isfile(filename):
+ raise PycodeError('source file is not present: %r' % filename)
+ return 'file', filename
+
+
# Low-level utility functions and classes.
class Tee(object):
diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py
index 885a458e..3fbfe4b2 100644
--- a/sphinx/util/compat.py
+++ b/sphinx/util/compat.py
@@ -11,7 +11,7 @@
from docutils import nodes
-# function missing in 0.5 SVN
+# function missing in docutils 0.5
def make_admonition(node_class, name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
#if not content:
@@ -35,64 +35,13 @@ def make_admonition(node_class, name, arguments, options, content, lineno,
return [admonition_node]
-# support the class-style Directive interface even when using docutils 0.4
+# backwards-compatibility aliases for helpers in older Sphinx versions that
+# supported the docutils 0.4 directive function interface
-try:
- from docutils.parsers.rst import Directive
+from docutils.parsers.rst import Directive
-except ImportError:
- class Directive(object):
- """
- Fake Directive class to allow Sphinx directives to be written in
- class style.
- """
- required_arguments = 0
- optional_arguments = 0
- final_argument_whitespace = False
- option_spec = None
- has_content = False
-
- def __init__(self, name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- self.name = name
- self.arguments = arguments
- self.options = options
- self.content = content
- self.lineno = lineno
- self.content_offset = content_offset
- self.block_text = block_text
- self.state = state
- self.state_machine = state_machine
-
- def run(self):
- raise NotImplementedError('Must override run() is subclass.')
-
- def directive_dwim(obj):
- """
- Return something usable with register_directive(), regardless if
- class or function. For that, we need to convert classes to a
- function for docutils 0.4.
- """
- if isinstance(obj, type) and issubclass(obj, Directive):
- def _class_directive(name, arguments, options, content,
- lineno, content_offset, block_text,
- state, state_machine):
- return obj(name, arguments, options, content,
- lineno, content_offset, block_text,
- state, state_machine).run()
- _class_directive.options = obj.option_spec
- _class_directive.content = obj.has_content
- _class_directive.arguments = (obj.required_arguments,
- obj.optional_arguments,
- obj.final_argument_whitespace)
- return _class_directive
- return obj
-
-else:
- def directive_dwim(obj):
- """
- Return something usable with register_directive(), regardless if
- class or function. Nothing to do here, because docutils 0.5 takes
- care of converting functions itself.
- """
- return obj
+def directive_dwim(obj):
+ import warnings
+ warnings.warn('directive_dwim is deprecated and no longer needed',
+ DeprecationWarning, stacklevel=2)
+ return obj
diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py
new file mode 100644
index 00000000..da93c6fe
--- /dev/null
+++ b/sphinx/util/docfields.py
@@ -0,0 +1,267 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.util.docfields
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ "Doc fields" are reST field lists in object descriptions that will
+ be domain-specifically transformed to a more appealing presentation.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes
+
+from sphinx import addnodes
+
+
+def _is_single_paragraph(node):
+ """True if the node only contains one paragraph (and system messages)."""
+ if len(node) == 0:
+ return False
+ elif len(node) > 1:
+ for subnode in node[1:]:
+ if not isinstance(subnode, nodes.system_message):
+ return False
+ if isinstance(node[0], nodes.paragraph):
+ return True
+ return False
+
+
+class Field(object):
+ """
+ A doc field that is never grouped. It can have an argument or not, the
+ argument can be linked using a specified *rolename*. Field should be used
+ for doc fields that usually don't occur more than once.
+
+ Example::
+
+ :returns: description of the return value
+ :rtype: description of the return type
+ """
+ is_grouped = False
+ is_typed = False
+
+ def __init__(self, name, names=(), label=None, has_arg=True, rolename=None):
+ self.name = name
+ self.names = names
+ self.label = label
+ self.has_arg = has_arg
+ self.rolename = rolename
+
+ def make_xref(self, rolename, domain, target, innernode=nodes.emphasis):
+ if not rolename:
+ return innernode(target, target)
+ refnode = addnodes.pending_xref('', refdomain=domain, refexplicit=False,
+ reftype=rolename, reftarget=target)
+ refnode += innernode(target, target)
+ return refnode
+
+ def make_entry(self, fieldarg, content):
+ return (fieldarg, content)
+
+ def make_field(self, types, domain, item):
+ fieldarg, content = item
+ fieldname = nodes.field_name('', self.label)
+ if fieldarg:
+ fieldname += nodes.Text(' ')
+ fieldname += self.make_xref(self.rolename, domain,
+ fieldarg, nodes.Text)
+ fieldbody = nodes.field_body('', nodes.paragraph('', *content))
+ return nodes.field('', fieldname, fieldbody)
+
+
+class GroupedField(Field):
+ """
+ A doc field that is grouped; i.e., all fields of that type will be
+ transformed into one field with its body being a bulleted list. It always
+ has an argument. The argument can be linked using the given *rolename*.
+ GroupedField should be used for doc fields that can occur more than once.
+ If *can_collapse* is true, this field will revert to a Field if only used
+ once.
+
+ Example::
+
+ :raises ErrorClass: description when it is raised
+ """
+ is_grouped = True
+ list_type = nodes.bullet_list
+
+ def __init__(self, name, names=(), label=None, rolename=None,
+ can_collapse=False):
+ Field.__init__(self, name, names, label, True, rolename)
+ self.can_collapse = can_collapse
+
+ def make_field(self, types, domain, items):
+ fieldname = nodes.field_name('', self.label)
+ listnode = self.list_type()
+ if len(items) == 1 and self.can_collapse:
+ return Field.make_field(self, types, domain, items[0])
+ for fieldarg, content in items:
+ par = nodes.paragraph()
+ par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong)
+ par += nodes.Text(' -- ')
+ par += content
+ listnode += nodes.list_item('', par)
+ fieldbody = nodes.field_body('', listnode)
+ return nodes.field('', fieldname, fieldbody)
+
+
+class TypedField(GroupedField):
+ """
+ A doc field that is grouped and has type information for the arguments. It
+ always has an argument. The argument can be linked using the given
+ *rolename*, the type using the given *typerolename*.
+
+ Two uses are possible: either parameter and type description are given
+ separately, using a field from *names* and one from *typenames*,
+ respectively, or both are given using a field from *names*, see the example.
+
+ Example::
+
+ :param foo: description of parameter foo
+ :type foo: SomeClass
+
+ -- or --
+
+ :param SomeClass foo: description of parameter foo
+ """
+ is_typed = True
+
+ def __init__(self, name, names=(), typenames=(), label=None,
+ rolename=None, typerolename=None):
+ GroupedField.__init__(self, name, names, label, rolename, False)
+ self.typenames = typenames
+ self.typerolename = typerolename
+
+ def make_field(self, types, domain, items):
+ fieldname = nodes.field_name('', self.label)
+ listnode = self.list_type()
+ for fieldarg, content in items:
+ par = nodes.paragraph()
+ par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong)
+ if fieldarg in types:
+ typename = u''.join(n.astext() for n in types[fieldarg])
+ par += nodes.Text(' (')
+ par += self.make_xref(self.typerolename, domain, typename)
+ par += nodes.Text(')')
+ par += nodes.Text(' -- ')
+ par += content
+ listnode += nodes.list_item('', par)
+ fieldbody = nodes.field_body('', listnode)
+ return nodes.field('', fieldname, fieldbody)
+
+
+class DocFieldTransformer(object):
+ """
+ Transforms field lists in "doc field" syntax into better-looking
+ equivalents, using the field type definitions given on a domain.
+ """
+
+ def __init__(self, directive):
+ self.domain = directive.domain
+ if not hasattr(directive, '_doc_field_type_map'):
+ directive.__class__._doc_field_type_map = \
+ self.preprocess_fieldtypes(directive.__class__.doc_field_types)
+ self.typemap = directive._doc_field_type_map
+
+ def preprocess_fieldtypes(self, types):
+ typemap = {}
+ for fieldtype in types:
+ for name in fieldtype.names:
+ typemap[name] = fieldtype, False
+ if fieldtype.is_typed:
+ for name in fieldtype.typenames:
+ typemap[name] = fieldtype, True
+ return typemap
+
+ def transform_all(self, node):
+ """Transform all field list children of a node."""
+ # don't traverse, only handle field lists that are immediate children
+ for child in node:
+ if isinstance(child, nodes.field_list):
+ self.transform(child)
+
+ def transform(self, node):
+ """Transform a single field list *node*."""
+ typemap = self.typemap
+
+ entries = []
+ groupindices = {}
+ types = {}
+
+ # step 1: traverse all fields and collect field types and content
+ for field in node:
+ fieldname, fieldbody = field
+ try:
+ # split into field type and argument
+ fieldtype, fieldarg = fieldname.astext().split(None, 1)
+ except ValueError:
+ # maybe an argument-less field type?
+ fieldtype, fieldarg = fieldname.astext(), ''
+ typedesc, is_typefield = typemap.get(fieldtype, (None, None))
+
+ # sort out unknown fields
+ if typedesc is None or typedesc.has_arg != bool(fieldarg):
+ # either the field name is unknown, or the argument doesn't
+ # match the spec; capitalize field name and be done with it
+ new_fieldname = fieldtype.capitalize() + ' ' + fieldarg
+ fieldname[0] = nodes.Text(new_fieldname)
+ entries.append(field)
+ continue
+
+ typename = typedesc.name
+
+ # collect the content, trying not to keep unnecessary paragraphs
+ if _is_single_paragraph(fieldbody):
+ content = fieldbody.children[0].children
+ else:
+ content = fieldbody.children
+
+ # if the field specifies a type, put it in the types collection
+ if is_typefield:
+ # filter out only inline nodes; others will result in invalid
+ # markup being written out
+ content = filter(lambda n: isinstance(n, nodes.Inline), content)
+ if content:
+ types.setdefault(typename, {})[fieldarg] = content
+ continue
+
+ # also support syntax like ``:param type name:``
+ if typedesc.is_typed:
+ try:
+ argtype, argname = fieldarg.split(None, 1)
+ except ValueError:
+ pass
+ else:
+ types.setdefault(typename, {})[argname] = \
+ [nodes.Text(argtype)]
+ fieldarg = argname
+
+ # grouped entries need to be collected in one entry, while others
+ # get one entry per field
+ if typedesc.is_grouped:
+ if typename in groupindices:
+ group = entries[groupindices[typename]]
+ else:
+ groupindices[typename] = len(entries)
+ group = [typedesc, []]
+ entries.append(group)
+ group[1].append(typedesc.make_entry(fieldarg, content))
+ else:
+ entries.append([typedesc,
+ typedesc.make_entry(fieldarg, content)])
+
+ # step 2: all entries are collected, construct the new field list
+ new_list = nodes.field_list()
+ for entry in entries:
+ if isinstance(entry, nodes.field):
+ # pass-through old field
+ new_list += entry
+ else:
+ fieldtype, content = entry
+ fieldtypes = types.get(fieldtype.name, {})
+ new_list += fieldtype.make_field(fieldtypes, self.domain,
+ content)
+
+ node.replace_self(new_list)
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py
index 0c43ec20..04185436 100644
--- a/sphinx/util/nodes.py
+++ b/sphinx/util/nodes.py
@@ -12,10 +12,13 @@
import re
import types
+from docutils import nodes
+
from sphinx import addnodes
-explicit_title_re = re.compile('^(.+?)\s*<(.*?)>$', re.DOTALL)
+# \x00 means the "<" was backslash-escaped
+explicit_title_re = re.compile(r'^(.+?)\s*(?<!\x00)<(.*?)>$', re.DOTALL)
caption_ref_re = explicit_title_re # b/w compat alias
@@ -35,7 +38,7 @@ def nested_parse_with_titles(state, content, node):
def clean_astext(node):
"""Like node.astext(), but ignore images."""
node = node.deepcopy()
- for img in node.traverse(docutils.nodes.image):
+ for img in node.traverse(nodes.image):
img['alt'] = ''
return node.astext()
@@ -75,6 +78,19 @@ def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc):
return tree
+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!
@@ -104,8 +120,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/util/texescape.py b/sphinx/util/texescape.py
index 73790829..4cabd9b2 100644
--- a/sphinx/util/texescape.py
+++ b/sphinx/util/texescape.py
@@ -99,6 +99,7 @@ tex_replacements = [
]
tex_escape_map = {}
+tex_replace_map = {}
tex_hl_escape_map_old = {} # replacement map for Pygments <= 1.1
tex_hl_escape_map_new = {} # replacement map for Pygments >= 1.2
_old_cmd_chars = {ord(u'\\'): u'@', ord(u'{'): u'[', ord(u'}'): u']'}
@@ -106,6 +107,7 @@ _old_cmd_chars = {ord(u'\\'): u'@', ord(u'{'): u'[', ord(u'}'): u']'}
def init():
for a, b in tex_replacements:
tex_escape_map[ord(a)] = b
+ tex_replace_map[ord(a)] = u'_'
for a, b in tex_replacements:
if a in u'[]{}\\': continue
diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py
index 320463e2..2db4aeaa 100644
--- a/sphinx/writers/html.py
+++ b/sphinx/writers/html.py
@@ -16,7 +16,7 @@ import os
from docutils import nodes
from docutils.writers.html4css1 import Writer, HTMLTranslator as BaseTranslator
-from sphinx.locale import admonitionlabels, versionlabels
+from sphinx.locale import admonitionlabels, versionlabels, _
from sphinx.util.smartypants import sphinx_smarty_pants
try:
@@ -67,7 +67,7 @@ class HTMLTranslator(BaseTranslator):
pass
def visit_desc(self, node):
- self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))
+ self.body.append(self.starttag(node, 'dl', CLASS=node['objtype']))
def depart_desc(self, node):
self.body.append('</dl>\n\n')
@@ -75,7 +75,7 @@ class HTMLTranslator(BaseTranslator):
# the id is set automatically
self.body.append(self.starttag(node, 'dt'))
# anchor for per-desc interactive data
- if node.parent['desctype'] != 'describe' \
+ if node.parent['objtype'] != 'describe' \
and node['ids'] and node['first']:
self.body.append('<!--[%s]-->' % node['ids'][0])
def depart_desc_signature(self, node):
@@ -195,21 +195,10 @@ class HTMLTranslator(BaseTranslator):
numbers = self.builder.secnumbers[anchorname]
self.body.append('.'.join(map(str, numbers)) + '. ')
- # overwritten for docutils 0.4
- if hasattr(BaseTranslator, 'start_tag_with_title'):
- def visit_section(self, node):
- # the 0.5 version, to get the id attribute in the <div> tag
- self.section_level += 1
- self.body.append(self.starttag(node, 'div', CLASS='section'))
-
- def visit_title(self, node):
- # don't move the id attribute inside the <h> tag
- BaseTranslator.visit_title(self, node, move_ids=0)
- self.add_secnumber(node)
- else:
- def visit_title(self, node):
- BaseTranslator.visit_title(self, node)
- self.add_secnumber(node)
+ # overwritten
+ def visit_title(self, node):
+ BaseTranslator.visit_title(self, node)
+ self.add_secnumber(node)
# overwritten
def visit_literal_block(self, node):
@@ -363,11 +352,6 @@ class HTMLTranslator(BaseTranslator):
def depart_acks(self, node):
pass
- def visit_module(self, node):
- pass
- def depart_module(self, node):
- pass
-
def visit_hlist(self, node):
self.body.append('<table class="hlist"><tr>')
def depart_hlist(self, node):
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 948f5118..84ddc5f6 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -22,9 +22,9 @@ from docutils.writers.latex2e import Babel
from sphinx import addnodes
from sphinx import highlighting
from sphinx.errors import SphinxError
-from sphinx.locale import admonitionlabels, versionlabels
+from sphinx.locale import admonitionlabels, versionlabels, _
from sphinx.util.osutil import ustrftime
-from sphinx.util.texescape import tex_escape_map
+from sphinx.util.texescape import tex_escape_map, tex_replace_map
from sphinx.util.smartypants import educateQuotesLatex
HEADER = r'''%% Generated by Sphinx.
@@ -47,7 +47,6 @@ HEADER = r'''%% Generated by Sphinx.
\newcommand{\sphinxlogo}{%(logo)s}
\renewcommand{\releasename}{%(releasename)s}
%(makeindex)s
-%(makemodindex)s
'''
BEGIN_DOC = r'''
@@ -58,9 +57,6 @@ BEGIN_DOC = r'''
'''
FOOTER = r'''
-%(footer)s
-\renewcommand{\indexname}{%(modindexname)s}
-%(printmodindex)s
\renewcommand{\indexname}{%(indexname)s}
%(printindex)s
\end{document}
@@ -121,14 +117,6 @@ class Table(object):
self.longtable = False
-class Desc(object):
- def __init__(self, node):
- self.env = LaTeXTranslator.desc_map.get(node['desctype'], 'describe')
- self.type = self.cls = self.name = self.params = \
- self.annotation = self.returns = ''
- self.count = 0
-
-
class LaTeXTranslator(nodes.NodeVisitor):
sectionnames = ["part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"]
@@ -154,12 +142,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
'logo': '',
'releasename': 'Release',
'makeindex': '\\makeindex',
- 'makemodindex': '\\makemodindex',
'shorthandoff': '',
'maketitle': '\\maketitle',
'tableofcontents': '\\tableofcontents',
'footer': '',
- 'printmodindex': '\\printmodindex',
'printindex': '\\printindex',
}
@@ -184,7 +170,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
'author': document.settings.author,
'releasename': _('Release'),
'preamble': builder.config.latex_preamble,
- 'modindexname': _('Module Index'),
'indexname': _('Index'),
})
if document.settings.docclass == 'howto':
@@ -212,9 +197,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.elements['fncychap'] = '\\usepackage[Sonny]{fncychap}'
else:
self.elements['classoptions'] += ',english'
- if not builder.config.latex_use_modindex:
- self.elements['makemodindex'] = ''
- self.elements['printmodindex'] = ''
# allow the user to override them all
self.elements.update(builder.config.latex_elements)
@@ -227,7 +209,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.next_table_colspec = None
self.highlightlang = builder.config.highlight_language
self.highlightlinenothreshold = sys.maxint
- self.written_ids = set()
self.footnotestack = []
self.curfilestack = []
self.handled_abbrs = set()
@@ -238,7 +219,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.top_sectionlevel = 0
else:
self.top_sectionlevel = 1
- self.next_section_target = None
+ self.next_section_ids = set()
# flags
self.verbatim = None
self.in_title = 0
@@ -248,13 +229,71 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.literal_whitespace = 0
self.no_contractions = 0
self.compact_list = 0
+ self.first_param = 0
def astext(self):
- return (HEADER % self.elements + self.highlighter.get_stylesheet() +
- u''.join(self.body) + FOOTER % self.elements)
+ return (HEADER % self.elements +
+ self.highlighter.get_stylesheet() +
+ u''.join(self.body) +
+ '\n' + self.elements['footer'] + '\n' +
+ self.generate_indices() +
+ FOOTER % self.elements)
+
+ def hypertarget(self, id, withdoc=True, anchor=True):
+ if withdoc:
+ id = self.curfilestack[-1] + ':' + id
+ return (anchor and '\\phantomsection' or '') + \
+ '\\label{%s}' % self.idescape(id)
+
+ def hyperlink(self, id):
+ return '\\hyperref[%s]{' % (self.idescape(id))
def idescape(self, id):
- return str(unicode(id).translate(tex_escape_map))
+ return str(unicode(id).translate(tex_replace_map))
+
+ def generate_indices(self):
+ def generate(content, collapsed):
+ ret.append('\\begin{theindex}\n')
+ ret.append('\\def\\bigletter#1{{\\Large\\sffamily#1}'
+ '\\nopagebreak\\vspace{1mm}}\n')
+ for i, (letter, entries) in enumerate(content):
+ if i > 0:
+ ret.append('\\indexspace\n')
+ ret.append('\\bigletter{%s}\n' % letter)
+ for entry in entries:
+ if not entry[3]:
+ continue
+ ret.append('\\item {\\texttt{%s}}' % self.encode(entry[0]))
+ if entry[4]:
+ # add "extra" info
+ ret.append(' \\emph{(%s)}' % self.encode(entry[4]))
+ ret.append(', \\pageref{%s:%s}\n' %
+ (entry[2], self.idescape(entry[3])))
+ ret.append('\\end{theindex}\n')
+
+ ret = []
+ # latex_domain_indices can be False/True or a list of index names
+ indices_config = self.builder.config.latex_domain_indices
+ if indices_config:
+ for domain in self.builder.env.domains.itervalues():
+ for indexcls in domain.indices:
+ indexname = '%s-%s' % (domain.name, indexcls.name)
+ if isinstance(indices_config, list):
+ if indexname not in indices_config:
+ continue
+ # deprecated config value
+ if indexname == 'py-modindex' and \
+ not self.builder.config.latex_use_modindex:
+ continue
+ content, collapsed = indexcls(domain).generate(
+ self.builder.docnames)
+ if not content:
+ continue
+ ret.append('\\renewcommand{\\indexname}{%s}\n' %
+ indexcls.localname)
+ generate(content, collapsed)
+
+ return ''.join(ret)
def visit_document(self, node):
self.footnotestack.append(self.collect_footnotes(node))
@@ -268,8 +307,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\n\\appendix\n')
self.first_document = -1
if node.has_key('docname'):
- self.body.append('\\hypertarget{--doc-%s}{}' %
- self.idescape(node['docname']))
+ self.body.append(self.hypertarget(':doc'))
# "- 1" because the level is increased before the title is visited
self.sectionlevel = self.top_sectionlevel - 1
def depart_document(self, node):
@@ -280,23 +318,18 @@ class LaTeXTranslator(nodes.NodeVisitor):
widest_label = bi[0]
self.body.append('\n\\begin{thebibliography}{%s}\n' % widest_label)
for bi in self.bibitems:
- # cite_key: underscores must not be escaped
- cite_key = bi[0].replace(r"\_", "_")
- self.body.append('\\bibitem[%s]{%s}{\hypertarget{%s}{} %s}\n' %
- (bi[0], cite_key,
- self.idescape(cite_key.lower()), bi[1]))
+ target = self.hypertarget(bi[2] + ':' + bi[0].lower(),
+ withdoc=False)
+ self.body.append('\\bibitem[%s]{%s}{%s %s}\n' %
+ (bi[0], self.idescape(bi[0]), target, bi[1]))
self.body.append('\\end{thebibliography}\n')
self.bibitems = []
def visit_start_of_file(self, node):
- # This marks the begin of a new file; therefore the current module and
- # class must be reset
- self.body.append('\n\\resetcurrentobjects\n')
- # and also, new footnotes
+ # collect new footnotes
self.footnotestack.append(self.collect_footnotes(node))
# also add a document target
- self.body.append('\\hypertarget{--doc-%s}{}' %
- self.idescape(node['docname']))
+ self.next_section_ids.add(':doc')
self.curfilestack.append(node['docname'])
def collect_footnotes(self, node):
@@ -328,15 +361,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
if not self.this_is_the_title:
self.sectionlevel += 1
self.body.append('\n\n')
- if self.next_section_target:
- self.body.append(r'\hypertarget{%s}{}' %
- self.idescape(self.next_section_target))
- self.next_section_target = None
- #if node.get('ids'):
- # for id in node['ids']:
- # if id not in self.written_ids:
- # self.body.append(r'\hypertarget{%s}{}' % id)
- # self.written_ids.add(id)
+ if node.get('ids'):
+ self.next_section_ids.update(node['ids'])
def depart_section(self, node):
self.sectionlevel = max(self.sectionlevel - 1,
self.top_sectionlevel - 1)
@@ -407,6 +433,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
# just use "subparagraph", it's not numbered anyway
self.body.append(r'\%s{' % self.sectionnames[-1])
self.context.append('}\n')
+
+ if self.next_section_ids:
+ for id in self.next_section_ids:
+ self.context[-1] += self.hypertarget(id, anchor=False)
+ self.next_section_ids.clear()
+
elif isinstance(parent, (nodes.topic, nodes.sidebar)):
self.body.append(r'\textbf{')
self.context.append('}\n\n\medskip\n\n')
@@ -438,138 +470,76 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_subtitle(self, node):
self.body.append(self.context.pop())
- desc_map = {
- 'function' : 'funcdesc',
- 'class': 'classdesc',
- 'method': 'methoddesc',
- 'classmethod': 'classmethoddesc',
- 'staticmethod': 'staticmethoddesc',
- 'exception': 'excdesc',
- 'data': 'datadesc',
- 'attribute': 'memberdesc',
- 'opcode': 'opcodedesc',
-
- 'cfunction': 'cfuncdesc',
- 'cmember': 'cmemberdesc',
- 'cmacro': 'csimplemacrodesc',
- 'ctype': 'ctypedesc',
- 'cvar': 'cvardesc',
-
- 'describe': 'describe',
- # and all others are 'describe' too
- }
-
def visit_desc(self, node):
- self.descstack.append(Desc(node))
+ self.body.append('\n\n\\begin{fulllineitems}\n')
def depart_desc(self, node):
- d = self.descstack.pop()
- self.body.append("\\end{%s}\n" % d.env)
+ self.body.append('\n\\end{fulllineitems}\n\n')
def visit_desc_signature(self, node):
- d = self.descstack[-1]
- # reset these for every signature
- d.type = d.cls = d.name = d.params = ''
- def depart_desc_signature(self, node):
- d = self.descstack[-1]
- d.cls = d.cls.rstrip('.')
- if node.parent['desctype'] != 'describe' and node['ids']:
- hyper = '\\hypertarget{%s}{}' % self.idescape(node['ids'][0])
+ if node.parent['objtype'] != 'describe' and node['ids']:
+ hyper = self.hypertarget(node['ids'][0])
else:
hyper = ''
- if d.count == 0:
- t1 = "\n\n%s\\begin{%s}" % (hyper, d.env)
+ self.body.append(hyper)
+ for child in node:
+ if isinstance(child, addnodes.desc_parameterlist):
+ self.body.append(r'\pysiglinewithargsret{')
+ break
else:
- t1 = "\n%s\\%sline" % (hyper, d.env[:-4])
- d.count += 1
- if d.env in ('funcdesc', 'classdesc', 'excclassdesc'):
- t2 = "{%s}{%s}" % (d.name, d.params)
- elif d.env in ('datadesc', 'excdesc', 'csimplemacrodesc'):
- t2 = "{%s}" % (d.name)
- elif d.env in ('methoddesc', 'classmethoddesc', 'staticmethoddesc'):
- if d.cls:
- t2 = "[%s]{%s}{%s}" % (d.cls, d.name, d.params)
- else:
- t2 = "{%s}{%s}" % (d.name, d.params)
- elif d.env == 'memberdesc':
- if d.cls:
- t2 = "[%s]{%s}" % (d.cls, d.name)
- else:
- t2 = "{%s}" % d.name
- elif d.env == 'cfuncdesc':
- if d.cls:
- # C++ class names
- d.name = '%s::%s' % (d.cls, d.name)
- t2 = "{%s}{%s}{%s}" % (d.type, d.name, d.params)
- elif d.env == 'cmemberdesc':
- try:
- type, container = d.type.rsplit(' ', 1)
- container = container.rstrip('.')
- except ValueError:
- container = ''
- type = d.type
- t2 = "{%s}{%s}{%s}" % (container, type, d.name)
- elif d.env == 'cvardesc':
- t2 = "{%s}{%s}" % (d.type, d.name)
- elif d.env == 'ctypedesc':
- t2 = "{%s}" % (d.name)
- elif d.env == 'opcodedesc':
- t2 = "{%s}{%s}" % (d.name, d.params)
- elif d.env == 'describe':
- t2 = "{%s}" % d.name
- self.body.append(t1 + t2)
+ self.body.append(r'\pysigline{')
+ def depart_desc_signature(self, node):
+ self.body.append('}{}')
+
+ def visit_desc_addname(self, node):
+ self.body.append(r'\code{')
+ self.literal_whitespace += 1
+ def depart_desc_addname(self, node):
+ self.body.append('}')
+ self.literal_whitespace -= 1
def visit_desc_type(self, node):
- d = self.descstack[-1]
- if d.env == 'describe':
- d.name += self.encode(node.astext())
- else:
- self.descstack[-1].type = self.encode(node.astext().strip())
- raise nodes.SkipNode
+ pass
+ def depart_desc_type(self, node):
+ pass
def visit_desc_returns(self, node):
- d = self.descstack[-1]
- if d.env == 'describe':
- d.name += ' $\\rightarrow$ ' + self.encode(node.astext())
- else:
- self.descstack[-1].returns = self.encode(node.astext().strip())
- raise nodes.SkipNode
+ self.body.append(r'}{ $\rightarrow$ ')
+ def depart_desc_returns(self, node):
+ pass
def visit_desc_name(self, node):
- d = self.descstack[-1]
- if d.env == 'describe':
- d.name += self.encode(node.astext())
- else:
- self.descstack[-1].name = self.encode(node.astext().strip())
- raise nodes.SkipNode
-
- def visit_desc_addname(self, node):
- d = self.descstack[-1]
- if d.env == 'describe':
- d.name += self.encode(node.astext())
- else:
- self.descstack[-1].cls = self.encode(node.astext().strip())
- raise nodes.SkipNode
+ self.body.append(r'\bfcode{')
+ self.literal_whitespace += 1
+ def depart_desc_name(self, node):
+ self.body.append('}')
+ self.literal_whitespace -= 1
def visit_desc_parameterlist(self, node):
- d = self.descstack[-1]
- if d.env == 'describe':
- d.name += self.encode(node.astext())
- else:
- self.descstack[-1].params = self.encode(node.astext().strip())
- raise nodes.SkipNode
+ self.body.append('}{')
+ self.first_param = 1
+ def depart_desc_parameterlist(self, node):
+ pass
- def visit_desc_annotation(self, node):
- d = self.descstack[-1]
- if d.env == 'describe':
- d.name += self.encode(node.astext())
+ def visit_desc_parameter(self, node):
+ if not self.first_param:
+ self.body.append(', ')
else:
- self.descstack[-1].annotation = self.encode(node.astext().strip())
- raise nodes.SkipNode
+ self.first_param = 0
+ if not node.hasattr('noemph'):
+ self.body.append(r'\emph{')
+ def depart_desc_parameter(self, node):
+ if not node.hasattr('noemph'):
+ self.body.append('}')
+
+ def visit_desc_optional(self, node):
+ self.body.append(r'\optional{')
+ def depart_desc_optional(self, node):
+ self.body.append('}')
- def visit_refcount(self, node):
- self.body.append("\\emph{")
- def depart_refcount(self, node):
- self.body.append("}\\\\")
+ def visit_desc_annotation(self, node):
+ self.body.append(r'\strong{')
+ def depart_desc_annotation(self, node):
+ self.body.append('}')
def visit_desc_content(self, node):
if node.children and not isinstance(node.children[0], nodes.paragraph):
@@ -578,6 +548,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_desc_content(self, node):
pass
+ def visit_refcount(self, node):
+ self.body.append("\\emph{")
+ def depart_refcount(self, node):
+ self.body.append("}\\\\")
+
def visit_seealso(self, node):
self.body.append("\n\n\\strong{%s:}\n\n" % admonitionlabels['seealso'])
def depart_seealso(self, node):
@@ -603,6 +578,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_label(self, node):
if isinstance(node.parent, nodes.citation):
self.bibitems[-1][0] = node.astext()
+ self.bibitems[-1][2] = self.curfilestack[-1]
raise nodes.SkipNode
def visit_tabular_col_spec(self, node):
@@ -766,7 +742,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_term(self, node):
ctx = '] \\leavevmode'
if node.has_key('ids') and node['ids']:
- ctx += '\\hypertarget{%s}{}' % self.idescape(node['ids'][0])
+ ctx += self.hypertarget(node['ids'][0])
self.body.append('\\item[')
self.context.append(ctx)
def depart_term(self, node):
@@ -823,19 +799,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_hlistcol(self, node):
pass
- def visit_module(self, node):
- modname = node['modname']
- self.body.append('\n\\hypertarget{module-%s}{}' %
- self.idescape(modname.replace(' ','')))
- self.body.append('\n\\declaremodule[%s]{}{%s}' % (
- modname.replace('_', ''), self.encode(modname)))
- self.body.append('\n\\modulesynopsis{%s}' %
- self.encode(node['synopsis']))
- if node.has_key('platform'):
- self.body.append('\\platform{%s}' % self.encode(node['platform']))
- def depart_module(self, node):
- pass
-
def latex_image_length(self, width_str):
match = re.match('(\d*\.?\d*)\s*(\S*)', width_str)
if not match:
@@ -889,7 +852,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
pre.append(align_prepost[is_inline, attrs['align']][0])
post.append(align_prepost[is_inline, attrs['align']][1])
except KeyError:
- pass # XXX complain here?
+ pass
if not is_inline:
pre.append('\n')
post.append('\n')
@@ -991,19 +954,30 @@ class LaTeXTranslator(nodes.NodeVisitor):
# indexing uses standard LaTeX index markup, so the targets
# will be generated differently
if not id.startswith('index-'):
- self.body.append(r'\hypertarget{%s}{}' % self.idescape(id))
+ self.body.append(self.hypertarget(id))
- if node.has_key('refid') and node['refid'] not in self.written_ids:
- parindex = node.parent.index(node)
+ # postpone the labels until after the sectioning command
+ parindex = node.parent.index(node)
+ try:
try:
next = node.parent[parindex+1]
- if isinstance(next, nodes.section):
- self.next_section_target = node['refid']
- return
except IndexError:
- pass
+ # last node in parent, look at next after parent
+ # (for section of equal level)
+ next = node.parent.parent[node.parent.parent.index(node.parent)]
+ if isinstance(next, nodes.section):
+ if node.get('refid'):
+ self.next_section_ids.add(node['refid'])
+ self.next_section_ids.update(node['ids'])
+ return
+ except IndexError:
+ pass
+ if 'refuri' in node:
+ return
+ if node.get('refid'):
add_target(node['refid'])
- self.written_ids.add(node['refid'])
+ for id in node['ids']:
+ add_target(id)
def depart_target(self, node):
pass
@@ -1051,15 +1025,20 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\\href{%s}{' % self.encode_uri(uri))
self.context.append('}')
elif uri.startswith('#'):
- # references to labels
- self.body.append('\\hyperlink{%s}{' % self.idescape(uri[1:]))
+ # references to labels in the same document
+ self.body.append(self.hyperlink(self.curfilestack[-1] +
+ ':' + uri[1:]))
self.context.append('}')
elif uri.startswith('%'):
# references to documents or labels inside documents
hashindex = uri.find('#')
- targetname = (hashindex == -1) and '--doc-' + uri[1:] \
- or uri[hashindex+1:]
- self.body.append('\\hyperlink{%s}{' % self.idescape(targetname))
+ if hashindex == -1:
+ # reference to the document
+ id = uri[1:] + '::doc'
+ else:
+ # reference to a label
+ id = uri[1:].replace('#', ':')
+ self.body.append(self.hyperlink(id))
self.context.append('}')
elif uri.startswith('@token'):
if self.in_production_list:
@@ -1122,7 +1101,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_citation(self, node):
# TODO maybe use cite bibitems
- self.bibitems.append(['', ''])
+ self.bibitems.append(['', '', '']) # [citeid, citetext, docname]
self.context.append(len(self.body))
def depart_citation(self, node):
size = self.context.pop()
@@ -1131,8 +1110,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.bibitems[-1][1] = text
def visit_citation_reference(self, node):
- citeid = node.astext()
- self.body.append('\\cite{%s}' % citeid)
+ # This is currently never encountered, since citation_reference nodes
+ # are already replaced by pending_xref nodes in the environment.
+ self.body.append('\\cite{%s}' % self.idescape(node.astext()))
raise nodes.SkipNode
def visit_literal(self, node):
@@ -1199,9 +1179,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
* serif typeface
"""
self.body.append('{\\raggedright{}')
- self.literal_whitespace = 1
+ self.literal_whitespace += 1
def depart_line_block(self, node):
- self.literal_whitespace = 0
+ self.literal_whitespace -= 1
# remove the last \\
del self.body[-1]
self.body.append('}\n')
@@ -1282,7 +1262,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_description(self, node):
- self.body.append( ' ' )
+ self.body.append(' ')
def depart_description(self, node):
pass
diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py
new file mode 100644
index 00000000..eb35c5a5
--- /dev/null
+++ b/sphinx/writers/manpage.py
@@ -0,0 +1,323 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.writers.manpage
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ Manual page writer, extended for Sphinx custom nodes.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes
+try:
+ from docutils.writers.manpage import MACRO_DEF, Writer, \
+ Translator as BaseTranslator
+ has_manpage_writer = True
+except ImportError:
+ # define the classes in any case, sphinx.application needs it
+ Writer = BaseTranslator = object
+ has_manpage_writer = False
+
+from sphinx import addnodes
+from sphinx.locale import admonitionlabels, versionlabels, _
+from sphinx.util.osutil import ustrftime
+
+
+class ManualPageWriter(Writer):
+ def __init__(self, builder):
+ Writer.__init__(self)
+ self.builder = builder
+
+ def translate(self):
+ visitor = ManualPageTranslator(self.builder, self.document)
+ self.visitor = visitor
+ self.document.walkabout(visitor)
+ self.output = visitor.astext()
+
+
+class ManualPageTranslator(BaseTranslator):
+ """
+ Custom translator.
+ """
+
+ def __init__(self, builder, *args, **kwds):
+ BaseTranslator.__init__(self, *args, **kwds)
+ self.builder = builder
+
+ self.in_productionlist = 0
+
+ # first title is the manpage title
+ self.section_level = -1
+
+ # docinfo set by man_pages config value
+ self._docinfo['title'] = self.document.settings.title
+ self._docinfo['subtitle'] = self.document.settings.subtitle
+ if self.document.settings.authors:
+ # don't set it if no author given
+ self._docinfo['author'] = self.document.settings.authors
+ self._docinfo['manual_section'] = self.document.settings.section
+
+ # docinfo set by other config values
+ self._docinfo['title_upper'] = self._docinfo['title'].upper()
+ if builder.config.today:
+ self._docinfo['date'] = builder.config.today
+ else:
+ self._docinfo['date'] = ustrftime(builder.config.today_fmt
+ or _('%B %d, %Y'))
+ self._docinfo['copyright'] = builder.config.copyright
+ self._docinfo['version'] = builder.config.version
+ self._docinfo['manual_group'] = builder.config.project
+
+ # since self.append_header() is never called, need to do this here
+ self.body.append(MACRO_DEF)
+
+ # overwritten -- added quotes around all .TH arguments
+ def header(self):
+ tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\""
+ " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n"
+ ".SH NAME\n"
+ "%(title)s \- %(subtitle)s\n")
+ return tmpl % self._docinfo
+
+ def visit_start_of_file(self, node):
+ pass
+ def depart_start_of_file(self, node):
+ pass
+
+ def visit_desc(self, node):
+ self.visit_definition_list(node)
+ def depart_desc(self, node):
+ self.depart_definition_list(node)
+
+ def visit_desc_signature(self, node):
+ self.visit_definition_list_item(node)
+ self.visit_term(node)
+ def depart_desc_signature(self, node):
+ self.depart_term(node)
+
+ def visit_desc_addname(self, node):
+ pass
+ def depart_desc_addname(self, node):
+ pass
+
+ def visit_desc_type(self, node):
+ pass
+ def depart_desc_type(self, node):
+ pass
+
+ def visit_desc_returns(self, node):
+ self.body.append(' -> ')
+ def depart_desc_returns(self, node):
+ pass
+
+ def visit_desc_name(self, node):
+ pass
+ def depart_desc_name(self, node):
+ pass
+
+ def visit_desc_parameterlist(self, node):
+ self.body.append('(')
+ self.first_param = 1
+ def depart_desc_parameterlist(self, node):
+ self.body.append(')')
+
+ def visit_desc_parameter(self, node):
+ if not self.first_param:
+ self.body.append(', ')
+ else:
+ self.first_param = 0
+ def depart_desc_parameter(self, node):
+ pass
+
+ def visit_desc_optional(self, node):
+ self.body.append('[')
+ def depart_desc_optional(self, node):
+ self.body.append(']')
+
+ def visit_desc_annotation(self, node):
+ pass
+ def depart_desc_annotation(self, node):
+ pass
+
+ def visit_desc_content(self, node):
+ self.visit_definition(node)
+ def depart_desc_content(self, node):
+ self.depart_definition(node)
+
+ def visit_refcount(self, node):
+ self.body.append(self.defs['emphasis'][0])
+ def depart_refcount(self, node):
+ self.body.append(self.defs['emphasis'][1])
+
+ def visit_versionmodified(self, node):
+ self.visit_paragraph(node)
+ text = versionlabels[node['type']] % node['version']
+ if len(node):
+ text += ': '
+ else:
+ text += '.'
+ self.body.append(text)
+ def depart_versionmodified(self, node):
+ self.depart_paragraph(node)
+
+ # overwritten -- we don't want source comments to show up
+ def visit_comment(self, node):
+ raise nodes.SkipNode
+
+ # overwritten -- added ensure_eol()
+ def visit_footnote(self, node):
+ self.ensure_eol()
+ BaseTranslator.visit_footnote(self, node)
+
+ # overwritten -- handle footnotes rubric
+ def visit_rubric(self, node):
+ self.ensure_eol()
+ if len(node.children) == 1:
+ rubtitle = node.children[0].astext()
+ if rubtitle in ('Footnotes', _('Footnotes')):
+ self.body.append('.SH ' + self.deunicode(rubtitle).upper() +
+ '\n')
+ raise nodes.SkipNode
+ else:
+ self.body.append('.sp\n')
+ def depart_rubric(self, node):
+ pass
+
+ def visit_seealso(self, node):
+ self.visit_admonition(node)
+ def depart_seealso(self, node):
+ self.depart_admonition(node)
+
+ # overwritten -- use our own label translations
+ def visit_admonition(self, node, name=None):
+ if name:
+ self.body.append('.IP %s\n' %
+ admonitionlabels.get(name, name))
+
+ def visit_productionlist(self, node):
+ self.ensure_eol()
+ names = []
+ self.in_productionlist += 1
+ self.body.append('.sp\n.nf\n')
+ for production in node:
+ names.append(production['tokenname'])
+ maxlen = max(len(name) for name in names)
+ for production in node:
+ if production['tokenname']:
+ lastname = production['tokenname'].ljust(maxlen)
+ self.body.append(self.defs['strong'][0])
+ self.body.append(self.deunicode(lastname))
+ self.body.append(self.defs['strong'][1])
+ self.body.append(' ::= ')
+ else:
+ self.body.append('%s ' % (' '*len(lastname)))
+ production.walkabout(self)
+ self.body.append('\n')
+ self.body.append('\n.fi\n')
+ self.in_productionlist -= 1
+ raise nodes.SkipNode
+
+ def visit_production(self, node):
+ pass
+ def depart_production(self, node):
+ pass
+
+ # overwritten -- don't emit a warning for images
+ def visit_image(self, node):
+ if 'alt' in node.attributes:
+ self.body.append('[image: %s]\n' % node['alt'])
+ self.body.append('[image]\n')
+ raise nodes.SkipNode
+
+ # overwritten -- don't visit inner marked up nodes
+ def visit_reference(self, node):
+ self.body.append(self.defs['reference'][0])
+ self.body.append(node.astext())
+ self.body.append(self.defs['reference'][1])
+ raise nodes.SkipNode
+
+ def visit_centered(self, node):
+ self.ensure_eol()
+ self.body.append('.sp\n.ce\n')
+ def depart_centered(self, node):
+ self.body.append('\n.ce 0\n')
+
+ def visit_compact_paragraph(self, node):
+ pass
+ def depart_compact_paragraph(self, node):
+ pass
+
+ def visit_highlightlang(self, node):
+ pass
+ def depart_highlightlang(self, node):
+ pass
+
+ def visit_download_reference(self, node):
+ pass
+ def depart_download_reference(self, node):
+ pass
+
+ def visit_toctree(self, node):
+ raise nodes.SkipNode
+
+ def visit_index(self, node):
+ raise nodes.SkipNode
+
+ def visit_tabular_col_spec(self, node):
+ raise nodes.SkipNode
+
+ def visit_glossary(self, node):
+ pass
+ def depart_glossary(self, node):
+ pass
+
+ def visit_acks(self, node):
+ self.ensure_eol()
+ self.body.append(', '.join(n.astext()
+ for n in node.children[0].children) + '.')
+ self.body.append('\n')
+ raise nodes.SkipNode
+
+ def visit_hlist(self, node):
+ self.visit_bullet_list(node)
+ def depart_hlist(self, node):
+ self.depart_bullet_list(node)
+
+ def visit_hlistcol(self, node):
+ pass
+ def depart_hlistcol(self, node):
+ pass
+
+ def visit_literal_emphasis(self, node):
+ return self.visit_emphasis(node)
+ def depart_literal_emphasis(self, node):
+ return self.depart_emphasis(node)
+
+ def visit_abbreviation(self, node):
+ pass
+ def depart_abbreviation(self, node):
+ pass
+
+ # overwritten: handle section titles better than in 0.6 release
+ def visit_title(self, node):
+ if isinstance(node.parent, addnodes.seealso):
+ self.body.append('.IP "')
+ return
+ elif isinstance(node.parent, nodes.section):
+ if self.section_level == 0:
+ # skip the document title
+ raise nodes.SkipNode
+ elif self.section_level == 1:
+ self.body.append('.SH %s\n' %
+ self.deunicode(node.astext().upper()))
+ raise nodes.SkipNode
+ return BaseTranslator.visit_title(self, node)
+ def depart_title(self, node):
+ if isinstance(node.parent, addnodes.seealso):
+ self.body.append('"\n')
+ return
+ return BaseTranslator.depart_title(self, node)
+
+ def unknown_visit(self, node):
+ raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py
index 7923f68d..c08471f8 100644
--- a/sphinx/writers/text.py
+++ b/sphinx/writers/text.py
@@ -15,7 +15,7 @@ import textwrap
from docutils import nodes, writers
from sphinx import addnodes
-from sphinx.locale import admonitionlabels, versionlabels
+from sphinx.locale import admonitionlabels, versionlabels, _
class TextWriter(writers.Writer):
@@ -161,13 +161,6 @@ class TextTranslator(nodes.NodeVisitor):
def depart_attribution(self, node):
pass
- def visit_module(self, node):
- if node.has_key('platform'):
- self.new_state(0)
- self.add_text(_('Platform: %s') % node['platform'])
- self.end_state()
- raise nodes.SkipNode
-
def visit_desc(self, node):
pass
def depart_desc(self, node):
@@ -175,8 +168,8 @@ class TextTranslator(nodes.NodeVisitor):
def visit_desc_signature(self, node):
self.new_state(0)
- if node.parent['desctype'] in ('class', 'exception'):
- self.add_text('%s ' % node.parent['desctype'])
+ if node.parent['objtype'] in ('class', 'exception'):
+ self.add_text('%s ' % node.parent['objtype'])
def depart_desc_signature(self, node):
# XXX: wrap signatures in a way that makes sense
self.end_state(wrap=False, end=None)
diff --git a/tests/root/_templates/layout.html b/tests/root/_templates/layout.html
index 7f290fc1..82125df8 100644
--- a/tests/root/_templates/layout.html
+++ b/tests/root/_templates/layout.html
@@ -1,4 +1,5 @@
{% extends "!layout.html" %}
+
{% block extrahead %}
{# html_context variable from conf.py #}
<meta name="hc" content="{{ hckey }}" />
@@ -6,3 +7,9 @@
<meta name="hc_co" content="{{ hckey_co }}" />
{{ super() }}
{% endblock %}
+
+{% block sidebartoc %}
+{# display global TOC in addition to local TOC #}
+{{ super() }}
+{{ toctree(collapse=False, maxdepth=-1) }}
+{% endblock %} \ No newline at end of file
diff --git a/tests/root/conf.py b/tests/root/conf.py
index a3783511..71f48ce6 100644
--- a/tests/root/conf.py
+++ b/tests/root/conf.py
@@ -25,13 +25,15 @@ today_fmt = '%B %d, %Y'
exclude_patterns = ['_build', '**/excluded.*']
keep_warnings = True
pygments_style = 'sphinx'
+show_authors = True
rst_epilog = '.. |subst| replace:: global substitution'
html_theme = 'testtheme'
html_theme_path = ['.']
html_theme_options = {'testopt': 'testoverride'}
-html_sidebars = {'**': 'customsb.html', 'contents': 'contentssb.html'}
+html_sidebars = {'**': 'customsb.html',
+ 'contents': ['contentssb.html', 'localtoc.html'] }
html_style = 'default.css'
html_static_path = ['_static', 'templated.css_t']
html_last_updated_fmt = '%b %d, %Y'
@@ -49,7 +51,7 @@ latex_additional_files = ['svgimg.svg']
value_from_conf_py = 84
coverage_c_path = ['special/*.h']
-coverage_c_regexes = {'cfunction': r'^PyAPI_FUNC\(.*\)\s+([^_][\w_]+)'}
+coverage_c_regexes = {'function': r'^PyAPI_FUNC\(.*\)\s+([^_][\w_]+)'}
autosummary_generate = ['autosummary']
@@ -59,7 +61,12 @@ extlinks = {'issue': ('http://bugs.python.org/issue%s', 'issue '),
# modify tags from conf.py
tags.add('confpytag')
+
+# -- extension API
+
+from docutils import nodes
from sphinx import addnodes
+from sphinx.util.compat import Directive
def userdesc_parse(env, sig, signode):
x, y = sig.split(':')
@@ -68,7 +75,18 @@ def userdesc_parse(env, sig, signode):
signode[-1] += addnodes.desc_parameter(y, y)
return x
+def functional_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ return [nodes.strong(text='from function: %s' % options['opt'])]
+
+class ClassDirective(Directive):
+ option_spec = {'opt': lambda x: x}
+ def run(self):
+ return [nodes.strong(text='from class: %s' % self.options['opt'])]
+
def setup(app):
app.add_config_value('value_from_conf_py', 42, False)
- app.add_description_unit('userdesc', 'userdescrole', '%s (userdesc)',
- userdesc_parse)
+ app.add_directive('funcdir', functional_directive, opt=lambda x: x)
+ app.add_directive('clsdir', ClassDirective)
+ app.add_object_type('userdesc', 'userdescrole', '%s (userdesc)',
+ userdesc_parse, objname='user desc')
diff --git a/tests/root/contents.txt b/tests/root/contents.txt
index c9005d57..e052e04b 100644
--- a/tests/root/contents.txt
+++ b/tests/root/contents.txt
@@ -11,12 +11,13 @@ Contents:
:maxdepth: 2
:numbered:
+ extapi
images
subdir/images
subdir/includes
includes
markup
- desc
+ objects
bom
math
autodoc
diff --git a/tests/root/desc.txt b/tests/root/desc.txt
deleted file mode 100644
index d6915dc2..00000000
--- a/tests/root/desc.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-Testing description units
-=========================
-
-.. function:: func_without_module(a, b, *c[, d])
-
- Does something.
-
-.. function:: func_without_body()
-
-.. function:: func_noindex
- :noindex:
-
-
-.. module:: mod
- :synopsis: Module synopsis.
- :platform: UNIX
-
-.. function:: func_in_module
-
-.. class:: Cls
-
- .. method:: meth1
-
- .. staticmethod:: meths
-
- .. attribute:: attr
-
-.. explicit class given
-.. method:: Cls.meth2
-
-.. explicit module given
-.. exception:: Error(arg1, arg2)
- :module: errmod
-
-.. data:: var
-
-
-.. currentmodule:: None
-
-.. function:: func_without_module2() -> annotation
-
-
-C items
-=======
-
-.. cfunction:: Sphinx_DoSomething()
-
-.. cmember:: SphinxStruct.member
-
-.. cmacro:: SPHINX_USE_PYTHON
-
-.. ctype:: SphinxType
-
-.. cvar:: sphinx_global
-
-
-Testing references
-==================
-
-Referencing :class:`mod.Cls` or :Class:`mod.Cls` should be the same.
-
-
-User markup
-===========
-
-.. userdesc:: myobj:parameter
-
- Description of userdesc.
-
-
-Referencing :userdescrole:`myobj`.
diff --git a/tests/root/extapi.txt b/tests/root/extapi.txt
new file mode 100644
index 00000000..4728e3de
--- /dev/null
+++ b/tests/root/extapi.txt
@@ -0,0 +1,10 @@
+Extension API tests
+===================
+
+Testing directives:
+
+.. funcdir::
+ :opt: Foo
+
+.. clsdir::
+ :opt: Bar
diff --git a/tests/root/markup.txt b/tests/root/markup.txt
index cdb8c5fc..65156e7e 100644
--- a/tests/root/markup.txt
+++ b/tests/root/markup.txt
@@ -5,7 +5,11 @@
Testing various markup
======================
+Meta markup
+-----------
+
.. sectionauthor:: Georg Brandl
+.. moduleauthor:: Georg Brandl
.. contents:: TOC
@@ -13,7 +17,11 @@ Testing various markup
:author: Me
:keywords: docs, sphinx
-A |subst|.
+
+Generic reST
+------------
+
+A |subst| (the definition is in rst_epilog).
.. _label:
@@ -21,22 +29,14 @@ A |subst|.
some code
-Admonitions
------------
-
-.. note:: Note
- Note text.
-
-.. warning:: Warning
-
- Warning text.
+Option list:
-.. tip::
- Tip text.
+-h help
+--help also help
Body directives
----------------
+^^^^^^^^^^^^^^^
.. topic:: Title
@@ -69,7 +69,67 @@ Body directives
b
-
+
+Admonitions
+^^^^^^^^^^^
+
+.. admonition:: My Admonition
+
+ Admonition text.
+
+.. note::
+ Note text.
+
+.. warning::
+
+ Warning text.
+
+.. tip::
+ Tip text.
+
+
+Inline markup
+-------------
+
+*Generic inline markup*
+
+* :command:`command`
+* :dfn:`dfn`
+* :guilabel:`guilabel`
+* :kbd:`kbd`
+* :mailheader:`mailheader`
+* :makevar:`makevar`
+* :manpage:`manpage`
+* :mimetype:`mimetype`
+* :newsgroup:`newsgroup`
+* :program:`program`
+* :regexp:`regexp`
+* :menuselection:`File --> Close`
+* :file:`a/{varpart}/b`
+* :samp:`print {i}`
+
+*Linking inline markup*
+
+* :pep:`8`
+* :rfc:`1`
+* :envvar:`HOME`
+* :keyword:`with`
+* :token:`try statement <try_stmt>`
+* :doc:`subdir/includes`
+* ``:download:`` is tested in includes.txt
+* :option:`Python -c option <python -c>`
+
+Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`.
+
+
+.. _with:
+
+With
+----
+
+(Empty section.)
+
+
Tables
------
@@ -96,6 +156,17 @@ Version markup
Boring stuff.
+Code blocks
+-----------
+
+.. code-block:: ruby
+ :linenos:
+
+ def ruby?
+ false
+ end
+
+
Misc stuff
----------
@@ -124,11 +195,6 @@ This is a side note.
This tests :CLASS:`role names in uppercase`.
-Option list:
-
--h help
---help also help
-
.. centered:: LICENSE AGREEMENT
.. acks::
@@ -146,7 +212,7 @@ Option list:
Particle with half-integer spin.
.. productionlist::
- try_stmt: try1_stmt | try2_stmt
+ try_stmt: `try1_stmt` | `try2_stmt`
try1_stmt: "try" ":" `suite`
: ("except" [`expression` ["," `target`]] ":" `suite`)+
: ["else" ":" `suite`]
@@ -154,7 +220,6 @@ Option list:
try2_stmt: "try" ":" `suite`
: "finally" ":" `suite`
-Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`.
Index markup
------------
@@ -180,11 +245,6 @@ Invalid index markup...
Testing öäü...
-Object markup
--------------
-
-:cfunc:`CFunction`.
-
Only directive
--------------
@@ -208,3 +268,4 @@ Only directive
.. rubric:: Footnotes
.. [#] Like footnotes.
+
diff --git a/tests/root/objects.txt b/tests/root/objects.txt
new file mode 100644
index 00000000..7a93aeed
--- /dev/null
+++ b/tests/root/objects.txt
@@ -0,0 +1,110 @@
+Testing object descriptions
+===========================
+
+.. function:: func_without_module(a, b, *c[, d])
+
+ Does something.
+
+.. function:: func_without_body()
+
+.. function:: func_noindex
+ :noindex:
+
+.. function:: func_with_module
+ :module: foolib
+
+.. module:: mod
+ :synopsis: Module synopsis.
+ :platform: UNIX
+
+.. function:: func_in_module
+
+.. class:: Cls
+
+ .. method:: meth1
+
+ .. staticmethod:: meths
+
+ .. attribute:: attr
+
+.. explicit class given
+.. method:: Cls.meth2
+
+.. explicit module given
+.. exception:: Error(arg1, arg2)
+ :module: errmod
+
+.. data:: var
+
+
+.. currentmodule:: None
+
+.. function:: func_without_module2() -> annotation
+
+.. class:: TimeInt
+
+.. class:: Time(hour, minute, isdst)
+
+ :param hour: The year.
+ :type hour: TimeInt
+ :param TimeInt minute: The minute.
+ :param isdst: whether it's DST
+ :type isdst: * some complex
+ * expression
+ :returns: a new :class:`Time` instance
+ :rtype: :class:`Time`
+ :raises ValueError: if the values are out of range
+ :ivar int hour: like *hour*
+ :ivar minute: like *minute*
+ :vartype minute: int
+
+
+C items
+=======
+
+.. c:function:: Sphinx_DoSomething()
+
+.. c:member:: SphinxStruct.member
+
+.. c:macro:: SPHINX_USE_PYTHON
+
+.. c:type:: SphinxType
+
+.. c:var:: sphinx_global
+
+
+References
+==========
+
+Referencing :class:`mod.Cls` or :Class:`mod.Cls` should be the same.
+
+With target: :c:func:`Sphinx_DoSomething()` (parentheses are handled),
+:c:member:`SphinxStruct.member`, :c:macro:`SPHINX_USE_PYTHON`,
+:c:type:`SphinxType *` (pointer is handled), :c:data:`sphinx_global`.
+
+Without target: :c:func:`CFunction`. :c:func:`!malloc`.
+
+
+Others
+======
+
+.. envvar:: HOME
+
+.. program:: python
+
+.. cmdoption:: -c command
+
+.. program:: perl
+
+.. cmdoption:: -c
+
+
+User markup
+===========
+
+.. userdesc:: myobj:parameter
+
+ Description of userdesc.
+
+
+Referencing :userdescrole:`myobj`.
diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py
index 58bdfaef..62768b20 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -14,7 +14,7 @@ from util import *
from docutils.statemachine import ViewList
-from sphinx.ext.autodoc import AutoDirective, Documenter, add_documenter, \
+from sphinx.ext.autodoc import AutoDirective, add_documenter, \
ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL
@@ -97,28 +97,28 @@ def test_parse_name():
verify('function', 'util.raises', ('util', ['raises'], None, None))
verify('function', 'util.raises(exc) -> None',
('util', ['raises'], 'exc', 'None'))
- directive.env.autodoc_current_module = 'util'
+ directive.env.temp_data['autodoc:module'] = 'util'
verify('function', 'raises', ('util', ['raises'], None, None))
- directive.env.autodoc_current_module = None
- directive.env.currmodule = 'util'
+ del directive.env.temp_data['autodoc:module']
+ directive.env.temp_data['py:module'] = 'util'
verify('function', 'raises', ('util', ['raises'], None, None))
verify('class', 'TestApp', ('util', ['TestApp'], None, None))
# for members
- directive.env.currmodule = 'foo'
+ directive.env.temp_data['py:module'] = 'foo'
verify('method', 'util.TestApp.cleanup',
('util', ['TestApp', 'cleanup'], None, None))
- directive.env.currmodule = 'util'
- directive.env.currclass = 'Foo'
- directive.env.autodoc_current_class = 'TestApp'
+ directive.env.temp_data['py:module'] = 'util'
+ directive.env.temp_data['py:class'] = 'Foo'
+ directive.env.temp_data['autodoc:class'] = 'TestApp'
verify('method', 'cleanup', ('util', ['TestApp', 'cleanup'], None, None))
verify('method', 'TestApp.cleanup',
('util', ['TestApp', 'cleanup'], None, None))
# and clean up
- directive.env.currmodule = None
- directive.env.currclass = None
- directive.env.autodoc_current_class = None
+ del directive.env.temp_data['py:module']
+ del directive.env.temp_data['py:class']
+ del directive.env.temp_data['autodoc:class']
def test_format_signature():
@@ -307,7 +307,7 @@ def test_new_documenter():
del directive.result[:]
options.members = ['integer']
- assert_result_contains('.. data:: integer', 'module', 'test_autodoc')
+ assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc')
def test_generate():
@@ -341,6 +341,26 @@ def test_generate():
assert item in directive.result
del directive.result[:]
+ def assert_order(items, objtype, name, member_order, **kw):
+ inst = AutoDirective._registry[objtype](directive, name)
+ inst.options.member_order = member_order
+ inst.generate(**kw)
+ assert len(_warnings) == 0, _warnings
+ items = list(reversed(items))
+ lineiter = iter(directive.result)
+ #for line in directive.result:
+ # if line.strip():
+ # print repr(line)
+ while items:
+ item = items.pop()
+ for line in lineiter:
+ if line == item:
+ break
+ else: # ran out of items!
+ assert False, 'item %r not found in result or not in the ' \
+ ' correct order' % item
+ del directive.result[:]
+
options.members = []
# no module found?
@@ -354,7 +374,7 @@ def test_generate():
'function', 'util.foobar', more_content=None)
# test auto and given content mixing
- directive.env.currmodule = 'test_autodoc'
+ directive.env.temp_data['py:module'] = 'test_autodoc'
assert_result_contains(' Function.', 'method', 'Class.meth')
add_content = ViewList()
add_content.append('Content.', '', 0)
@@ -398,7 +418,8 @@ def test_generate():
options.members = []
# test module flags
- assert_result_contains('.. module:: test_autodoc', 'module', 'test_autodoc')
+ assert_result_contains('.. py:module:: test_autodoc',
+ 'module', 'test_autodoc')
options.synopsis = 'Synopsis'
assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc')
options.deprecated = True
@@ -407,9 +428,9 @@ def test_generate():
assert_result_contains(' :platform: Platform', 'module', 'test_autodoc')
# test if __all__ is respected for modules
options.members = ALL
- assert_result_contains('.. class:: Class(arg)', 'module', 'test_autodoc')
+ assert_result_contains('.. py:class:: Class(arg)', 'module', 'test_autodoc')
try:
- assert_result_contains('.. exception:: CustomEx',
+ assert_result_contains('.. py:exception:: CustomEx',
'module', 'test_autodoc')
except AssertionError:
pass
@@ -423,7 +444,7 @@ def test_generate():
assert_result_contains(' :noindex:', 'class', 'Base')
# okay, now let's get serious about mixing Python and C signature stuff
- assert_result_contains('.. class:: CustomDict', 'class', 'CustomDict',
+ assert_result_contains('.. py:class:: CustomDict', 'class', 'CustomDict',
all_members=True)
# test inner class handling
@@ -437,10 +458,26 @@ def test_generate():
'attribute', 'test_autodoc.Class.descr')
# test generation for C modules (which have no source file)
- directive.env.currmodule = 'time'
+ directive.env.temp_data['py:module'] = 'time'
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
+ # test autodoc_member_order == 'source'
+ directive.env.temp_data['py:module'] = 'test_autodoc'
+ assert_order(['.. py:class:: Class(arg)',
+ ' .. py:attribute:: Class.descr',
+ ' .. py:method:: Class.meth()',
+ ' .. py:method:: Class.undocmeth()',
+ ' .. py:attribute:: Class.attr',
+ ' .. py:attribute:: Class.prop',
+ ' .. py:attribute:: Class.docattr',
+ ' .. py:attribute:: Class.udocattr',
+ ' .. py:attribute:: Class.inst_attr_comment',
+ ' .. py:attribute:: Class.inst_attr_string',
+ ' .. py:method:: Class.inheritedmeth()',
+ ],
+ 'class', 'Class', member_order='bysource', all_members=True)
+
# --- generate fodder ------------
diff --git a/tests/test_build.py b/tests/test_build.py
index 4cd7bc0c..f18ff175 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -3,105 +3,18 @@
test_build
~~~~~~~~~~
- Test the entire build process with the test root.
+ Test all builders that have no special checks.
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
-import os
-import re
-import sys
-import difflib
-from StringIO import StringIO
-from subprocess import Popen, PIPE
-
-from sphinx.builders.latex import LaTeXBuilder
-from sphinx.writers.latex import LaTeXTranslator
-
from util import *
def teardown_module():
(test_root / '_build').rmtree(True)
-
-latex_warnfile = StringIO()
-
-ENV_WARNINGS = """\
-%(root)s/images.txt:9: WARNING: image file not readable: foo.png
-%(root)s/images.txt:23: WARNING: nonlocal image URI found: \
-http://www.python.org/logo.png
-%(root)s/includes.txt:: (WARNING/2) Encoding 'utf-8-sig' used for reading \
-included file u'wrongenc.inc' seems to be wrong, try giving an :encoding: option
-%(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png
-"""
-
-LATEX_WARNINGS = ENV_WARNINGS + """\
-None:None: WARNING: no matching candidate for image URI u'foo.*'
-WARNING: invalid pair index entry u''
-"""
-
-
-@with_app(buildername='latex', warning=latex_warnfile, cleanenv=True)
-def test_latex(app):
- LaTeXTranslator.ignore_missing_images = True
- app.builder.build_all()
- latex_warnings = latex_warnfile.getvalue().replace(os.sep, '/')
- latex_warnings_exp = LATEX_WARNINGS % {'root': app.srcdir}
- assert latex_warnings == latex_warnings_exp, 'Warnings don\'t match:\n' + \
- '\n'.join(difflib.ndiff(latex_warnings_exp.splitlines(),
- latex_warnings.splitlines()))
- # file from latex_additional_files
- assert (app.outdir / 'svgimg.svg').isfile()
-
- # only run latex if all needed packages are there
- def kpsetest(filename):
- try:
- p = Popen(['kpsewhich', filename], stdout=PIPE)
- except OSError, err:
- # no kpsewhich... either no tex distribution is installed or it is
- # a "strange" one -- don't bother running latex
- return None
- else:
- p.communicate()
- if p.returncode != 0:
- # not found
- return False
- # found
- return True
-
- if kpsetest('article.sty') is None:
- print >>sys.stderr, \
- 'info: not running latex, it doesn\'t seem to be installed'
- return
- for filename in ['fancyhdr.sty', 'fancybox.sty', 'titlesec.sty',
- 'amsmath.sty', 'framed.sty', 'color.sty', 'fancyvrb.sty',
- 'threeparttable.sty']:
- if not kpsetest(filename):
- print >>sys.stderr, \
- 'info: not running latex, the %s package doesn\'t ' \
- 'seem to be installed' % filename
- return
-
- # now, try to run latex over it
- cwd = os.getcwd()
- os.chdir(app.outdir)
- try:
- try:
- p = Popen(['pdflatex', '--interaction=nonstopmode',
- 'SphinxTests.tex'], stdout=PIPE, stderr=PIPE)
- except OSError, err:
- pass # most likely pdflatex was not found
- else:
- stdout, stderr = p.communicate()
- if p.returncode != 0:
- print stdout
- del app.cleanup_trees[:]
- assert False, 'latex exited with error'
- finally:
- os.chdir(cwd)
-
# just let the remaining ones run for now
@with_app(buildername='pickle')
@@ -132,6 +45,15 @@ def test_epub(app):
def test_changes(app):
app.builder.build_all()
+try:
+ from docutils.writers.manpage import Writer
+except ImportError:
+ pass
+else:
+ @with_app(buildername='man')
+ def test_man(app):
+ app.builder.build_all()
+
@with_app(buildername='singlehtml', cleanenv=True)
def test_singlehtml(app):
app.builder.build_all()
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index 25f733a4..bfa0f1cf 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -22,7 +22,6 @@ except ImportError:
from sphinx import __version__
from util import *
-from test_build import ENV_WARNINGS
from etree13 import ElementTree as ET
@@ -32,6 +31,15 @@ def teardown_module():
html_warnfile = StringIO()
+ENV_WARNINGS = """\
+%(root)s/images.txt:9: WARNING: image file not readable: foo.png
+%(root)s/images.txt:23: WARNING: nonlocal image URI found: \
+http://www.python.org/logo.png
+%(root)s/includes.txt:: (WARNING/2) Encoding 'utf-8-sig' used for reading \
+included file u'wrongenc.inc' seems to be wrong, try giving an :encoding: option
+%(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png
+"""
+
HTML_WARNINGS = ENV_WARNINGS + """\
%(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.*'
%(root)s/markup.txt:: WARNING: invalid index entry u''
@@ -66,26 +74,87 @@ HTML_XPATH = {
".//dt[@id='test_autodoc.function']/em": r'\*\*kwds',
".//dd": r'Return spam\.',
},
+ 'extapi.html': {
+ ".//strong": 'from function: Foo',
+ ".//strong": 'from class: Bar',
+ },
'markup.html': {
+ ".//title": 'set by title directive',
+ ".//p/em": 'Section author: Georg Brandl',
+ ".//p/em": 'Module author: Georg Brandl',
+ # created by the meta directive
".//meta[@name='author'][@content='Me']": '',
".//meta[@name='keywords'][@content='docs, sphinx']": '',
- ".//a[@href='contents.html#ref1']": '',
+ # a label created by ``.. _label:``
".//div[@id='label']": '',
+ # code with standard code blocks
+ ".//pre": '^some code$',
+ # an option list
".//span[@class='option']": '--help',
+ # admonitions
+ ".//p[@class='first admonition-title']": 'My Admonition',
+ ".//p[@class='last']": 'Note text.',
+ ".//p[@class='last']": 'Warning text.',
+ # inline markup
+ ".//li/strong": '^command$',
+ ".//li/strong": '^program$',
+ ".//li/em": '^dfn$',
+ ".//li/tt/span[@class='pre']": '^kbd$',
+ ".//li/em": u'File \N{TRIANGULAR BULLET} Close',
+ ".//li/tt/span[@class='pre']": '^a/$',
+ ".//li/tt/em/span[@class='pre']": '^varpart$',
+ ".//li/tt/em/span[@class='pre']": '^i$',
+ ".//a[@href='http://www.python.org/dev/peps/pep-0008']/strong": 'PEP 8',
+ ".//a[@href='http://tools.ietf.org/html/rfc1.html']/strong": 'RFC 1',
+ ".//a[@href='objects.html#envvar-HOME']/tt/span[@class='pre']": 'HOME',
+ ".//a[@href='#with']/tt/span[@class='pre']": '^with$',
+ ".//a[@href='#grammar-token-try_stmt']/tt/span": '^statement$',
+ ".//a[@href='subdir/includes.html']/em": 'Including in subdir',
+ ".//a[@href='objects.html#cmdoption-python-c']/em": 'Python -c option',
+ # abbreviations
+ ".//abbr[@title='abbreviation']": '^abbr$',
+ # version stuff
+ ".//span[@class='versionmodified']": 'New in version 0.6',
+ # footnote reference
+ ".//a[@class='footnote-reference']": r'\[1\]',
+ # created by reference lookup
+ ".//a[@href='contents.html#ref1']": '',
+ # ``seealso`` directive
+ ".//div/p[@class='first admonition-title']": 'See also',
+ # a ``hlist`` directive
+ ".//table[@class='hlist']/tr/td/ul/li": '^This$',
+ # a ``centered`` directive
+ ".//p[@class='centered']/strong": 'LICENSE',
+ # a glossary
+ ".//dl/dt[@id='term-boson']": 'boson',
+ # a production list
+ ".//pre/strong": 'try_stmt',
+ ".//pre/a[@href='#grammar-token-try1_stmt']/tt/span": 'try1_stmt',
+ # tests for ``only`` directive
".//p": 'A global substitution.',
".//p": 'In HTML.',
".//p": 'In both.',
".//p": 'Always present',
- ".//title": 'set by title directive',
- ".//span[@class='pre']": 'CFunction()',
},
- 'desc.html': {
+ 'objects.html': {
".//dt[@id='mod.Cls.meth1']": '',
".//dt[@id='errmod.Error']": '',
".//a[@href='#mod.Cls']": '',
".//dl[@class='userdesc']": '',
- ".//dt[@id='userdescrole-myobj']": '',
- ".//a[@href='#userdescrole-myobj']": '',
+ ".//dt[@id='userdesc-myobj']": '',
+ ".//a[@href='#userdesc-myobj']": '',
+ # C references
+ ".//span[@class='pre']": 'CFunction()',
+ ".//a[@href='#Sphinx_DoSomething']": '',
+ ".//a[@href='#SphinxStruct.member']": '',
+ ".//a[@href='#SPHINX_USE_PYTHON']": '',
+ ".//a[@href='#SphinxType']": '',
+ ".//a[@href='#sphinx_global']": '',
+ # test global TOC created by toctree()
+ ".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='']":
+ 'Testing object descriptions',
+ ".//li[@class='toctree-l1']/a[@href='markup.html']":
+ 'Testing various markup',
# custom sidebar
".//h4": 'Custom sidebar',
},
@@ -93,13 +162,16 @@ HTML_XPATH = {
".//meta[@name='hc'][@content='hcval']": '',
".//meta[@name='hc_co'][@content='hcval_co']": '',
".//meta[@name='testopt'][@content='testoverride']": '',
- #".//td[@class='label']": r'\[Ref1\]', # docutils 0.5 only
+ ".//td[@class='label']": r'\[Ref1\]',
".//td[@class='label']": '',
".//li[@class='toctree-l1']/a": 'Testing various markup',
- ".//li[@class='toctree-l2']/a": 'Admonitions',
+ ".//li[@class='toctree-l2']/a": 'Inline markup',
".//title": 'Sphinx <Tests>',
".//div[@class='footer']": 'Georg Brandl & Team',
".//a[@href='http://python.org/']": '',
+ ".//li/a[@href='genindex.html']/em": 'Index',
+ ".//li/a[@href='py-modindex.html']/em": 'Module Index',
+ ".//li/a[@href='search.html']/em": 'Search Page',
# custom sidebar only for contents
".//h4": 'Contents sidebar',
},
diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py
new file mode 100644
index 00000000..4f40cc11
--- /dev/null
+++ b/tests/test_build_latex.py
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+"""
+ test_build_latex
+ ~~~~~~~~~~~~~~~~
+
+ Test the build process with LaTeX builder with the test root.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import os
+import sys
+import difflib
+from StringIO import StringIO
+from subprocess import Popen, PIPE
+
+from sphinx.writers.latex import LaTeXTranslator
+
+from util import *
+from test_build_html import ENV_WARNINGS
+
+
+def teardown_module():
+ (test_root / '_build').rmtree(True)
+
+
+latex_warnfile = StringIO()
+
+LATEX_WARNINGS = ENV_WARNINGS + """\
+None:None: WARNING: no matching candidate for image URI u'foo.*'
+WARNING: invalid pair index entry u''
+"""
+
+
+@with_app(buildername='latex', warning=latex_warnfile, cleanenv=True)
+def test_latex(app):
+ LaTeXTranslator.ignore_missing_images = True
+ app.builder.build_all()
+ latex_warnings = latex_warnfile.getvalue().replace(os.sep, '/')
+ latex_warnings_exp = LATEX_WARNINGS % {'root': app.srcdir}
+ assert latex_warnings == latex_warnings_exp, 'Warnings don\'t match:\n' + \
+ '\n'.join(difflib.ndiff(latex_warnings_exp.splitlines(),
+ latex_warnings.splitlines()))
+ # file from latex_additional_files
+ assert (app.outdir / 'svgimg.svg').isfile()
+
+ # only run latex if all needed packages are there
+ def kpsetest(filename):
+ try:
+ p = Popen(['kpsewhich', filename], stdout=PIPE)
+ except OSError:
+ # no kpsewhich... either no tex distribution is installed or it is
+ # a "strange" one -- don't bother running latex
+ return None
+ else:
+ p.communicate()
+ if p.returncode != 0:
+ # not found
+ return False
+ # found
+ return True
+
+ if kpsetest('article.sty') is None:
+ print >>sys.stderr, \
+ 'info: not running latex, it doesn\'t seem to be installed'
+ return
+ for filename in ['fancyhdr.sty', 'fancybox.sty', 'titlesec.sty',
+ 'amsmath.sty', 'framed.sty', 'color.sty', 'fancyvrb.sty',
+ 'threeparttable.sty']:
+ if not kpsetest(filename):
+ print >>sys.stderr, \
+ 'info: not running latex, the %s package doesn\'t ' \
+ 'seem to be installed' % filename
+ return
+
+ # now, try to run latex over it
+ cwd = os.getcwd()
+ os.chdir(app.outdir)
+ try:
+ try:
+ p = Popen(['pdflatex', '--interaction=nonstopmode',
+ 'SphinxTests.tex'], stdout=PIPE, stderr=PIPE)
+ except OSError:
+ pass # most likely pdflatex was not found
+ else:
+ stdout, stderr = p.communicate()
+ if p.returncode != 0:
+ print stdout
+ print stderr
+ del app.cleanup_trees[:]
+ assert False, 'latex exited with return code %s' % p.returncode
+ finally:
+ os.chdir(cwd)
diff --git a/tests/test_config.py b/tests/test_config.py
index 0d18bf7f..cb4e1105 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -34,7 +34,7 @@ def test_core_config(app):
# simple default values
assert 'locale_dirs' not in cfg.__dict__
assert cfg.locale_dirs == []
- assert cfg.show_authors == False
+ assert cfg.trim_footnote_reference_space == False
# complex default values
assert 'html_title' not in cfg.__dict__
diff --git a/tests/test_coverage.py b/tests/test_coverage.py
index 282db677..1262ebf5 100644
--- a/tests/test_coverage.py
+++ b/tests/test_coverage.py
@@ -36,7 +36,7 @@ def test_build(app):
undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').text())
assert len(undoc_c) == 1
# the key is the full path to the header file, which isn't testable
- assert undoc_c.values()[0] == [('cfunction', 'Py_SphinxTest')]
+ assert undoc_c.values()[0] == [('function', 'Py_SphinxTest')]
assert 'test_autodoc' in undoc_py
assert 'funcs' in undoc_py['test_autodoc']
diff --git a/tests/test_cpp_domain.py b/tests/test_cpp_domain.py
new file mode 100644
index 00000000..1e722602
--- /dev/null
+++ b/tests/test_cpp_domain.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+"""
+ test_cpp_domain
+ ~~~~~~~~~~~~~~~
+
+ Tests the C++ Domain
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from util import *
+
+from sphinx.domains.cpp import DefinitionParser
+
+
+def parse(name, string):
+ return getattr(DefinitionParser(string), 'parse_' + name)()
+
+
+def test_type_definitions():
+ rv = parse('member_object', ' const std::string & name = 42')
+ assert unicode(rv) == 'const std::string& name = 42'
+
+ rv = parse('member_object', ' const std::string & name leftover')
+ assert unicode(rv) == 'const std::string& name'
+
+ rv = parse('member_object', 'const std::vector< unsigned int, long> &name')
+ assert unicode(rv) == 'const std::vector<unsigned int, long>& name'
+
+ x = 'std::vector<std::pair<std::string, int>>& module::test(register ' \
+ 'foo, bar, std::string baz="foobar, blah, bleh") const = 0'
+ assert unicode(parse('function', x)) == x
+
+ x = 'module::myclass::operator std::vector<std::string>()'
+ assert unicode(parse('function', x)) == x
+ x = 'explicit module::myclass::foo::foo()'
+ assert unicode(parse('function', x)) == x
+
+ x = 'std::vector<std::pair<std::string, long long>> module::blah'
+ assert unicode(parse('type_object', x)) == x
+
+ assert unicode(parse('type_object', 'long long int foo')) == 'long long foo'
+
+
+def test_operators():
+ x = parse('function', 'void operator new [ ] ()')
+ assert unicode(x) == 'void operator new[]()'
+
+ x = parse('function', 'void operator delete ()')
+ assert unicode(x) == 'void operator delete()'
+
+ for op in '*-+=/%!':
+ x = parse('function', 'void operator %s ()' % op)
+ assert unicode(x) == 'void operator%s()' % op
diff --git a/tests/test_env.py b/tests/test_env.py
index 0090d6b6..4ecbaac4 100644
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -11,7 +11,6 @@
from util import *
-from sphinx.environment import BuildEnvironment
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.builders.latex import LaTeXBuilder
@@ -20,8 +19,8 @@ warnings = []
def setup_module():
global app, env
- app = TestApp(srcdir='(temp)')
- env = BuildEnvironment(app.srcdir, app.doctreedir, app.config)
+ app = TestApp(srcdir='(temp)', freshenv=True)
+ env = app.env
env.set_warnfunc(lambda *args: warnings.append(args))
def teardown_module():
@@ -53,7 +52,7 @@ def test_images():
tree = env.get_doctree('images')
app._warning.reset()
- htmlbuilder = StandaloneHTMLBuilder(app, env)
+ htmlbuilder = StandaloneHTMLBuilder(app)
htmlbuilder.post_process_images(tree)
assert "no matching candidate for image URI u'foo.*'" in \
app._warning.content[-1]
@@ -63,7 +62,7 @@ def test_images():
set(['img.png', 'img1.png', 'simg.png', 'svgimg.svg'])
app._warning.reset()
- latexbuilder = LaTeXBuilder(app, env)
+ latexbuilder = LaTeXBuilder(app)
latexbuilder.post_process_images(tree)
assert "no matching candidate for image URI u'foo.*'" in \
app._warning.content[-1]
@@ -94,10 +93,10 @@ def test_second_update():
assert 'autodoc' not in env.found_docs
def test_object_inventory():
- refs = env.descrefs
+ refs = env.domaindata['py']['objects']
assert 'func_without_module' in refs
- assert refs['func_without_module'] == ('desc', 'function')
+ assert refs['func_without_module'] == ('objects', 'function')
assert 'func_without_module2' in refs
assert 'mod.func_in_module' in refs
assert 'mod.Cls' in refs
@@ -111,5 +110,8 @@ def test_object_inventory():
assert 'func_in_module' not in refs
assert 'func_noindex' not in refs
- assert 'mod' in env.modules
- assert env.modules['mod'] == ('desc', 'Module synopsis.', 'UNIX', False)
+ assert env.domaindata['py']['modules']['mod'] == \
+ ('objects', 'Module synopsis.', 'UNIX', False)
+
+ assert env.domains['py'].data is env.domaindata['py']
+ assert env.domains['c'].data is env.domaindata['c']
diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py
new file mode 100644
index 00000000..5263d724
--- /dev/null
+++ b/tests/test_intersphinx.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+"""
+ test_intersphinx
+ ~~~~~~~~~~~~~~~~
+
+ Test the intersphinx extension.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import zlib
+import posixpath
+from cStringIO import StringIO
+
+from docutils import nodes
+
+from sphinx import addnodes
+from sphinx.ext.intersphinx import read_inventory_v1, read_inventory_v2, \
+ load_mappings, missing_reference
+
+from util import *
+
+
+inventory_v1 = '''\
+# Sphinx inventory version 1
+# Project: foo
+# Version: 1.0
+module mod foo.html
+module.cls class foo.html
+'''
+
+inventory_v2 = '''\
+# Sphinx inventory version 2
+# Project: foo
+# Version: 2.0
+# The remainder of this file is compressed with zlib.
+''' + zlib.compress('''\
+module1 py:module 0 foo.html#module-module1
+module2 py:module 0 foo.html#module-$
+module1.func py:function 1 sub/foo.html#$
+CFunc c:function 2 cfunc.html#CFunc
+''')
+
+
+def test_read_inventory_v1():
+ f = StringIO(inventory_v1)
+ f.readline()
+ invdata = read_inventory_v1(f, '/util', posixpath.join)
+ assert invdata['py:module']['module'] == \
+ ('foo', '1.0', '/util/foo.html#module-module')
+ assert invdata['py:class']['module.cls'] == \
+ ('foo', '1.0', '/util/foo.html#module.cls')
+
+
+def test_read_inventory_v2():
+ f = StringIO(inventory_v2)
+ f.readline()
+ invdata1 = read_inventory_v2(f, '/util', posixpath.join)
+
+ # try again with a small buffer size to test the chunking algorithm
+ f = StringIO(inventory_v2)
+ f.readline()
+ invdata2 = read_inventory_v2(f, '/util', posixpath.join, bufsize=5)
+
+ assert invdata1 == invdata2
+
+ assert len(invdata1['py:module']) == 2
+ assert invdata1['py:module']['module1'] == \
+ ('foo', '2.0', '/util/foo.html#module-module1')
+ assert invdata1['py:module']['module2'] == \
+ ('foo', '2.0', '/util/foo.html#module-module2')
+ assert invdata1['py:function']['module1.func'][2] == \
+ '/util/sub/foo.html#module1.func'
+ assert invdata1['c:function']['CFunc'][2] == '/util/cfunc.html#CFunc'
+
+
+@with_app(confoverrides={'extensions': 'sphinx.ext.intersphinx'})
+@with_tempdir
+def test_missing_reference(tempdir, app):
+ inv_file = tempdir / 'inventory'
+ write_file(inv_file, inventory_v2)
+ app.config.intersphinx_mapping = {'http://docs.python.org/': inv_file}
+ app.config.intersphinx_cache_limit = 0
+
+ # load the inventory and check if it's done correctly
+ load_mappings(app)
+ inv = app.env.intersphinx_inventory
+
+ assert inv['py:module']['module2'] == \
+ ('foo', '2.0', 'http://docs.python.org/foo.html#module-module2')
+
+ # create fake nodes and check referencing
+ contnode = nodes.emphasis('foo')
+ refnode = addnodes.pending_xref('')
+ refnode['reftarget'] = 'module1.func'
+ refnode['reftype'] = 'func'
+ refnode['refdomain'] = 'py'
+
+ rn = missing_reference(app, app.env, refnode, contnode)
+ assert isinstance(rn, nodes.reference)
+ assert rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func'
+ assert rn['reftitle'] == '(in foo v2.0)'
+ assert rn[0] is contnode
+
+ # create unresolvable nodes and check None return value
+ refnode['reftype'] = 'foo'
+ assert missing_reference(app, app.env, refnode, contnode) is None
+
+ refnode['reftype'] = 'function'
+ refnode['reftarget'] = 'foo.func'
+ assert missing_reference(app, app.env, refnode, contnode) is None
diff --git a/tests/test_markup.py b/tests/test_markup.py
index 899fedf7..0277d327 100644
--- a/tests/test_markup.py
+++ b/tests/test_markup.py
@@ -28,6 +28,8 @@ def setup_module():
components=(rst.Parser, HTMLWriter, LaTeXWriter))
settings = optparser.get_default_values()
settings.env = app.builder.env
+ settings.env.patch_lookup_functions()
+ settings.env.temp_data['docname'] = 'dummy'
parser = rst.Parser()
def teardown_module():
@@ -59,7 +61,7 @@ def verify_re(rst, html_expected, latex_expected):
html_translator = ForgivingHTMLTranslator(app.builder, document)
document.walkabout(html_translator)
html_translated = ''.join(html_translator.fragment).strip()
- assert re.match(html_expected, html_translated), 'from' + rst
+ assert re.match(html_expected, html_translated), 'from ' + rst
if latex_expected:
latex_translator = ForgivingLaTeXTranslator(document, app.builder)
@@ -78,26 +80,26 @@ def verify(rst, html_expected, latex_expected):
def test_inline():
# correct interpretation of code with whitespace
- _html = ('<p><tt class="docutils literal"><span class="pre">'
+ _html = ('<p><tt class="(samp )?docutils literal"><span class="pre">'
'code</span>&nbsp;&nbsp; <span class="pre">sample</span></tt></p>')
- yield verify, '``code sample``', _html, '\\code{code sample}'
- yield verify, ':samp:`code sample`', _html, '\\samp{code sample}'
+ yield verify_re, '``code sample``', _html, r'\\code{code sample}'
+ yield verify_re, ':samp:`code sample`', _html, r'\\samp{code sample}'
# interpolation of braces in samp and file roles (HTML only)
yield (verify, ':samp:`a{b}c`',
- '<p><tt class="docutils literal"><span class="pre">a</span>'
+ '<p><tt class="samp docutils literal"><span class="pre">a</span>'
'<em><span class="pre">b</span></em>'
'<span class="pre">c</span></tt></p>',
'\\samp{abc}')
# interpolation of arrows in menuselection
yield (verify, ':menuselection:`a --> b`',
- u'<p><em>a \N{TRIANGULAR BULLET} b</em></p>',
+ u'<p><em class="menuselection">a \N{TRIANGULAR BULLET} b</em></p>',
'\\emph{a \\(\\rightarrow\\) b}')
# non-interpolation of dashes in option role
yield (verify_re, ':option:`--with-option`',
- '<p><em( class="xref")?>--with-option</em></p>$',
+ '<p><em( class="xref std std-option")?>--with-option</em></p>$',
r'\\emph{\\texttt{-{-}with-option}}$')
# verify smarty-pants quotes
@@ -108,6 +110,11 @@ def test_inline():
'&quot;John&quot;</span></tt></p>',
'\\code{"John"}')
+ # verify classes for inline roles
+ yield (verify, ':manpage:`mp(1)`',
+ '<p><em class="manpage">mp(1)</em></p>',
+ '\\emph{\\texttt{mp(1)}}')
+
def test_latex_escaping():
# correct escaping in normal mode
yield (verify, u'Γ\\\\∞$', None,
@@ -118,5 +125,5 @@ def test_latex_escaping():
u'@PYGZat[]@(@Gamma@)\\@(@infty@)@$@PYGZlb[]@PYGZrb[]\n'
u'\\end{Verbatim}')
# in URIs
- yield (verify, u'`test <http://example.com/~me/>`_', None,
- u'\\href{http://example.com/~me/}{test}')
+ yield (verify_re, u'`test <http://example.com/~me/>`_', None,
+ ur'\\href{http://example.com/~me/}{test}.*')
diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index a6b0e7f5..8fb6cb21 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -16,7 +16,6 @@ from util import *
from nose.tools import assert_equals
-from sphinx.environment import BuildEnvironment
app = env = None
warnings = []
@@ -25,9 +24,7 @@ def setup_module():
# Is there a better way of generating this doctree than manually iterating?
global app, env
app = TestApp(srcdir='(temp)')
- env = BuildEnvironment(app.srcdir, app.doctreedir, app.config)
- # Huh. Why do I need to do this?
- env.set_warnfunc(lambda *args: warnings.append(args))
+ env = app.env
msg, num, it = env.update(app.config, app.srcdir, app.doctreedir, app)
for docname in it:
pass
diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py
index 11782fb6..cb40d27c 100644
--- a/tests/test_quickstart.py
+++ b/tests/test_quickstart.py
@@ -126,8 +126,10 @@ def test_quickstart_all_answers(tempdir):
'pngmath': 'N',
'jsmath': 'no',
'ifconfig': 'no',
+ 'viewcode': 'no',
'Create Makefile': 'no',
'Create Windows command file': 'no',
+ 'Do you want to use the epub builder': 'yes',
}
qs.raw_input = mock_raw_input(answers, needanswer=True)
qs.TERM_ENCODING = 'utf-8'
@@ -150,6 +152,10 @@ def test_quickstart_all_answers(tempdir):
assert ns['latex_documents'] == [
('contents', 'STASI.tex', u'STASI™ Documentation',
u'Wolfgang Schäuble \\& G\'Beckstein', 'manual')]
+ assert ns['epub_author'] == u'Wolfgang Schäuble & G\'Beckstein'
+ assert ns['man_pages'] == [
+ ('contents', 'stasi', u'STASI™ Documentation',
+ [u'Wolfgang Schäuble & G\'Beckstein'], 1)]
assert (tempdir / 'build').isdir()
assert (tempdir / 'source' / '.static').isdir()
diff --git a/tests/test_search.py b/tests/test_search.py
index 15257aeb..0b5b158b 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -9,12 +9,14 @@
:license: BSD, see LICENSE for details.
"""
-from docutils import frontend, utils, nodes
+from docutils import frontend, utils
from docutils.parsers import rst
from sphinx.search import IndexBuilder
+settings = parser = None
+
def setup_module():
global settings, parser
optparser = frontend.OptionParser(components=(rst.Parser,))
diff --git a/tests/util.py b/tests/util.py
index 2b380722..1b24af0e 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -8,7 +8,6 @@
"""
import sys
-import os
import StringIO
import tempfile
import shutil
@@ -184,9 +183,9 @@ def gen_with_app(*args, **kwargs):
def with_tempdir(func):
- def new_func():
+ def new_func(*args, **kwds):
tempdir = path(tempfile.mkdtemp())
- func(tempdir)
+ func(tempdir, *args, **kwds)
tempdir.rmtree()
new_func.__name__ = func.__name__
return new_func
diff --git a/utils/check_sources.py b/utils/check_sources.py
index 6f78c26e..0571ab1e 100755
--- a/utils/check_sources.py
+++ b/utils/check_sources.py
@@ -189,9 +189,6 @@ def main(argv):
num = 0
out = cStringIO.StringIO()
- # TODO: replace os.walk run with iteration over output of
- # `svn list -R`.
-
for root, dirs, files in os.walk(path):
if '.svn' in dirs:
dirs.remove('.svn')
diff --git a/utils/pylintrc b/utils/pylintrc
index 2552a12c..cf71db59 100644
--- a/utils/pylintrc
+++ b/utils/pylintrc
@@ -273,7 +273,7 @@ ignore-docstrings=yes
# checks for:
-# * warning notes in the code like FIXME, XXX
+# * warning notes in the code
# * PEP 263: source code with non ascii character but no encoding declaration
#
[MISCELLANEOUS]