Make the concept of "module index" generalized to domains. As a side-effect, the latex modindex is no longer generated by LaTeX.

This commit is contained in:
Georg Brandl
2010-02-20 01:13:23 +01:00
parent f440e08ffc
commit 454ecf80a4
21 changed files with 329 additions and 311 deletions

View File

@@ -277,8 +277,8 @@ The special files are located in the root output directory. They are:
``project``, ``copyright``, ``release``, ``version`` ``project``, ``copyright``, ``release``, ``version``
The same values as given in the configuration file. The same values as given in the configuration file.
``style``, ``use_modindex`` ``style``
:confval:`html_style` and :confval:`html_use_modindex`, respectively. :confval:`html_style`.
``last_updated`` ``last_updated``
Date of last build. Date of last build.

View File

@@ -162,8 +162,8 @@ The special document names (and pages generated for them) are:
* ``genindex``, ``modindex``, ``search`` * ``genindex``, ``modindex``, ``search``
These are used for the general index, the module index, and the search page, These are used for the general index, the Python module index, and the search
respectively. page, respectively.
The general index is populated with entries from modules, all index-generating The general index is populated with entries from modules, all index-generating
:ref:`object descriptions <desc-units>`, and from :dir:`index` directives. :ref:`object descriptions <desc-units>`, and from :dir:`index` directives.

View File

@@ -208,10 +208,11 @@ General configuration
.. confval:: modindex_common_prefix .. confval:: modindex_common_prefix
A list of prefixes that are ignored for sorting the module index (e.g., A list of prefixes that are ignored for sorting the Python module index
if this is set to ``['foo.']``, then ``foo.bar`` is shown under ``B``, not (e.g., if this is set to ``['foo.']``, then ``foo.bar`` is shown under ``B``,
``F``). This can be handy if you document a project that consists of a single not ``F``). This can be handy if you document a project that consists of a
package. Works only for the HTML builder currently. Default is ``[]``. single package. Works only for the HTML builder currently. Default is
``[]``.
.. versionadded:: 0.6 .. versionadded:: 0.6
@@ -528,10 +529,25 @@ that use Sphinx' HTMLWriter class.
... old template content ... ... old template content ...
{% endblock %} {% 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 .. confval:: html_use_modindex
If true, add a module index to the HTML documents. Default is ``True``. 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 .. confval:: html_use_index
If true, add an index to the HTML documents. Default is ``True``. If true, add an index to the HTML documents. Default is ``True``.
@@ -769,10 +785,24 @@ These options influence LaTeX output.
A list of document names to append as an appendix to all manuals. 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 .. confval:: latex_use_modindex
If true, add a module index to LaTeX documents. Default is ``True``. If true, add a module index to LaTeX documents. Default is ``True``.
.. deprecated:: 1.0
Use :confval:`latex_domain_indices`.
.. confval:: latex_elements .. confval:: latex_elements
.. versionadded:: 0.5 .. versionadded:: 0.5
@@ -839,9 +869,7 @@ These options influence LaTeX output.
``'logo'`` ``'logo'``
``'releasename'`` ``'releasename'``
``'makeindex'`` ``'makeindex'``
``'makemodindex'``
``'shorthandoff'`` ``'shorthandoff'``
``'printmodindex'``
.. confval:: latex_docclass .. confval:: latex_docclass

View File

@@ -318,9 +318,9 @@ in the future.
.. data:: rellinks .. data:: rellinks
A list of links to put at the left side of the relbar, next to "next" and 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 "prev". This usually contains links to the general index and other indices,
add something yourself, it must be a tuple ``(pagename, link title, such as the Python module index. If you add something yourself, it must be a
accesskey, link text)``. tuple ``(pagename, link title, accesskey, link text)``.
.. data:: shorttitle .. data:: shorttitle

View File

@@ -230,6 +230,20 @@ class StandaloneHTMLBuilder(Builder):
defaults=self.env.settings, defaults=self.env.settings,
components=(self.docwriter,)).get_default_values() 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 indexinfo in domain.indices:
indexname = '%s-%s' % (domain.name, indexinfo[0])
if isinstance(indices_config, list):
if indexname not in indices_config:
continue
if domain.has_index_entries(indexinfo[0]):
self.domain_indices.append((domain.name,) + indexinfo)
# format the "last updated on" string, only once is enough since it # format the "last updated on" string, only once is enough since it
# typically doesn't include the time of day # typically doesn't include the time of day
lufmt = self.config.html_last_updated_fmt lufmt = self.config.html_last_updated_fmt
@@ -254,11 +268,8 @@ class StandaloneHTMLBuilder(Builder):
rellinks = [] rellinks = []
if self.config.html_use_index: if self.config.html_use_index:
rellinks.append(('genindex', _('General Index'), 'I', _('index'))) rellinks.append(('genindex', _('General Index'), 'I', _('index')))
# XXX generalization of modindex? for index in self.domain_indices:
if self.config.html_use_modindex and \ rellinks.append(('%s-%s' % index[0:2], index[2], '', index[3]))
self.env.domaindata['py']['modules']:
rellinks.append(('modindex', _('Global Module Index'),
'M', _('modules')))
if self.config.html_style is not None: if self.config.html_style is not None:
stylename = self.config.html_style stylename = self.config.html_style
@@ -396,9 +407,8 @@ class StandaloneHTMLBuilder(Builder):
if self.config.html_use_index: if self.config.html_use_index:
self.write_genindex() self.write_genindex()
# the global module index # the global domain-specific indices
if self.config.html_use_modindex: self.write_domain_indices()
self.write_modindex()
# the search page # the search page
if self.name != 'htmlhelp': if self.name != 'htmlhelp':
@@ -454,98 +464,17 @@ class StandaloneHTMLBuilder(Builder):
else: else:
self.handle_page('genindex', genindexcontext, 'genindex.html') self.handle_page('genindex', genindexcontext, 'genindex.html')
def write_modindex(self): def write_domain_indices(self):
moduleindex = self.env.domaindata['py']['modules'] for index in self.domain_indices:
if not moduleindex: content, collapse = self.env.domains[index[0]].get_index(index[1])
return indexcontext = dict(
# the sorted list of all modules, for the global module index indextitle = index[2],
modules = sorted(((mn, (self.get_relative_uri('modindex', fn) + content = content,
'#module-' + mn, sy, pl, dep)) collapse_index = collapse,
for (mn, (fn, sy, pl, dep)) in )
moduleindex.iteritems()), indexname = '%s-%s' % index[0:2]
key=lambda x: x[0].lower()) self.info(' ' + indexname, nonl=1)
# collect all platforms self.handle_page(indexname, indexcontext, 'domainindex.html')
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 copy_image_files(self): def copy_image_files(self):
# copy image files # copy image files

View File

@@ -217,9 +217,9 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
# special books # special books
f.write('<LI> ' + object_sitemap % (self.config.html_short_title, f.write('<LI> ' + object_sitemap % (self.config.html_short_title,
'index.html')) 'index.html'))
if self.config.html_use_modindex: for index in self.domain_indices:
f.write('<LI> ' + object_sitemap % (_('Global Module Index'), f.write('<LI> ' + object_sitemap % (index[2],
'modindex.html')) '%s-%s.html' % index[0:2]))
# the TOC # the TOC
tocdoc = self.env.get_and_resolve_doctree( tocdoc = self.env.get_and_resolve_doctree(
self.config.master_doc, self, prune_toctrees=False) self.config.master_doc, self, prune_toctrees=False)

View File

@@ -130,9 +130,9 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
for node in tocdoc.traverse(istoctree): for node in tocdoc.traverse(istoctree):
sections.extend(self.write_toc(node)) sections.extend(self.write_toc(node))
if self.config.html_use_modindex: for index in self.domain_indices:
item = section_template % {'title': _('Global Module Index'), item = section_template % {'title': index[2],
'ref': 'modindex.html'} 'ref': '%s-%s.html' % index[0:2]}
sections.append(' '*4*4 + item) sections.append(' '*4*4 + item)
sections = '\n'.join(sections) sections = '\n'.join(sections)

View File

@@ -81,7 +81,8 @@ class Config(object):
html_translator_class = (None, 'html'), html_translator_class = (None, 'html'),
html_sidebars = ({}, 'html'), html_sidebars = ({}, 'html'),
html_additional_pages = ({}, '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_add_permalinks = (True, 'html'),
html_use_index = (True, 'html'), html_use_index = (True, 'html'),
html_split_index = (False, 'html'), html_split_index = (False, 'html'),
@@ -125,7 +126,8 @@ class Config(object):
latex_logo = (None, None), latex_logo = (None, None),
latex_appendices = ([], None), latex_appendices = ([], None),
latex_use_parts = (False, 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 # paper_size and font_size are still separate values
# so that you can give them easily on the command line # so that you can give them easily on the command line
latex_paper_size = ('letter', None), latex_paper_size = ('letter', None),

View File

@@ -70,6 +70,8 @@ class Domain(object):
directives = {} directives = {}
#: role name -> role callable #: role name -> role callable
roles = {} roles = {}
#: (index identifier, localized index name, localized short name) tuples
indices = []
#: data value for a fresh environment #: data value for a fresh environment
initial_data = {} initial_data = {}
@@ -175,6 +177,22 @@ class Domain(object):
""" """
return [] return []
def has_index_entries(self, name, docnames=None):
"""
Return True if there are entries for the index given by *name*. If
*docnames* is given, restrict to entries referring to these docnames.
"""
return False
def get_index(self, name, docnames=None):
"""
Return entries for the index given by *name*. If *docnames* is given,
restrict to entries referring to these docnames.
XXX document return format
"""
return [], False
from sphinx.domains.c import CDomain from sphinx.domains.c import CDomain
from sphinx.domains.std import StandardDomain from sphinx.domains.std import StandardDomain

View File

@@ -462,6 +462,9 @@ class PythonDomain(Domain):
'objects': {}, # fullname -> docname, objtype 'objects': {}, # fullname -> docname, objtype
'modules': {}, # modname -> docname, synopsis, platform, deprecated 'modules': {}, # modname -> docname, synopsis, platform, deprecated
} }
indices = [
('modindex', l_('Global Module Index'), l_('modules')),
]
def clear_doc(self, docname): def clear_doc(self, docname):
for fullname, (fn, _) in self.data['objects'].items(): for fullname, (fn, _) in self.data['objects'].items():
@@ -545,3 +548,80 @@ class PythonDomain(Domain):
yield (modname, 'module', info[0], 'module-' + modname, 0) yield (modname, 'module', info[0], 'module-' + modname, 0)
for refname, (docname, type) in self.data['objects'].iteritems(): for refname, (docname, type) in self.data['objects'].iteritems():
yield (refname, type, docname, refname, 1) yield (refname, type, docname, refname, 1)
def has_index_entries(self, name, docnames=None):
if name != 'modindex':
return False
if not docnames:
return bool(self.data['modules'])
else:
for modname, info in self.data['modules'].iteritems():
if info[0] in docnames:
return True
return False
def get_index(self, name, docnames=None):
if name != 'modindex':
return None, None
content = {}
# list of prefixes to ignore
ignores = self.env.config['modindex_common_prefix']
ignores = sorted(ignores, key=len, reverse=True)
# list of all modules, sorted by module name
modules = sorted(self.data['modules'].iteritems(),
key=lambda x: x[0].lower())
# sort out collapsable modules
prev_modname = ''
num_toplevels = 0
current_group = 0 # collapse group
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
current_group += 1
entries.append([stripped + package, 1, current_group,
'', '', '', '', ''])
grouptype = 2
else:
num_toplevels += 1
current_group += 1
grouptype = 0
qualifier = deprecated and _('Deprecated') or ''
entries.append([stripped + modname, grouptype, current_group,
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

View File

@@ -110,6 +110,8 @@ class DefaultSubstitutions(Transform):
class MoveModuleTargets(Transform): class MoveModuleTargets(Transform):
""" """
Move module targets to their nearest enclosing section title. Move module targets to their nearest enclosing section title.
XXX Python specific
""" """
default_priority = 210 default_priority = 210
@@ -318,11 +320,13 @@ class BuildEnvironment:
self.temp_data = {} self.temp_data = {}
# Some magically present labels # Some magically present labels
def add_magic_label(name, description): def add_magic_label(name, description, target=None):
self.labels[name] = (name, '', description) self.labels[name] = (target or name, '', description)
self.anonlabels[name] = (name, '') self.anonlabels[name] = (target or name, '')
add_magic_label('genindex', _('Index')) 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')) add_magic_label('search', _('Search Page'))
def set_warnfunc(self, func): def set_warnfunc(self, func):

View File

@@ -164,7 +164,7 @@ html_static_path = ['%(dot)sstatic']
#html_additional_pages = {} #html_additional_pages = {}
# If false, no module index is generated. # If false, no module index is generated.
#html_use_modindex = True #html_domain_indices = True
# If false, no index is generated. # If false, no index is generated.
#html_use_index = True #html_use_index = True
@@ -223,7 +223,7 @@ latex_documents = [
#latex_appendices = [] #latex_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
#latex_use_modindex = True #latex_domain_indices = True
# -- Options for Epub output --------------------------------------------------- # -- Options for Epub output ---------------------------------------------------

View File

@@ -37,7 +37,6 @@ bz2: tar
latex $(LATEXOPTS) '$<' latex $(LATEXOPTS) '$<'
latex $(LATEXOPTS) '$<' latex $(LATEXOPTS) '$<'
-makeindex -s python.ist '$(basename $<).idx' -makeindex -s python.ist '$(basename $<).idx'
-makeindex -s python.ist '$(basename mod$<).idx'
latex $(LATEXOPTS) '$<' latex $(LATEXOPTS) '$<'
latex $(LATEXOPTS) '$<' latex $(LATEXOPTS) '$<'
@@ -46,7 +45,6 @@ bz2: tar
pdflatex $(LATEXOPTS) '$<' pdflatex $(LATEXOPTS) '$<'
pdflatex $(LATEXOPTS) '$<' pdflatex $(LATEXOPTS) '$<'
-makeindex -s python.ist '$(basename $<).idx' -makeindex -s python.ist '$(basename $<).idx'
-makeindex -s python.ist '$(basename mod$<).idx'
pdflatex $(LATEXOPTS) '$<' pdflatex $(LATEXOPTS) '$<'
pdflatex $(LATEXOPTS) '$<' pdflatex $(LATEXOPTS) '$<'

View File

@@ -130,8 +130,6 @@
\newcommand{\samp}[1]{`\code{#1}'} \newcommand{\samp}[1]{`\code{#1}'}
\newcommand{\email}[1]{\textsf{#1}} \newcommand{\email}[1]{\textsf{#1}}
\newcommand{\py@modulebadkey}{{--just-some-junk--}}
% Redefine the Verbatim environment to allow border and background colors. % Redefine the Verbatim environment to allow border and background colors.
% The original environment is still used for verbatims within tables. % The original environment is still used for verbatims within tables.
\let\OriginalVerbatim=\Verbatim \let\OriginalVerbatim=\Verbatim
@@ -193,89 +191,12 @@
\index{#4!#1 #2 #3} \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@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} % \moduleauthor{name}{email}
\newcommand{\moduleauthor}[2]{} \newcommand{\moduleauthor}[2]{}
% \sectionauthor{name}{email} % \sectionauthor{name}{email}
\newcommand{\sectionauthor}[2]{} \newcommand{\sectionauthor}[2]{}
% Ignore module synopsis.
\newcommand{\modulesynopsis}[1]{}
% Reset "current" objects.
\newcommand{\resetcurrentobjects}{
\renewcommand{\py@thismodule}{}
\renewcommand{\py@thismodulekey}{}
\renewcommand{\py@thismoduletype}{}
}
% Augment the sectioning commands used to get our own font family in place, % Augment the sectioning commands used to get our own font family in place,
% and reset some internal data items: % and reset some internal data items:
\titleformat{\section}{\Large\py@HeaderFamily}% \titleformat{\section}{\Large\py@HeaderFamily}%
@@ -301,8 +222,6 @@
\let\makelabel=\py@itemnewline} \let\makelabel=\py@itemnewline}
}{\end{list}} }{\end{list}}
\let\py@badkey=\@undefined
% \optional is used for ``[, arg]``, i.e. desc_optional nodes. % \optional is used for ``[, arg]``, i.e. desc_optional nodes.
\newcommand{\optional}[1]{% \newcommand{\optional}[1]{%
{\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}} {\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}}
@@ -325,7 +244,7 @@
% the example completely. % the example completely.
% %
\newcommand{\grammartoken}[1]{\texttt{#1}} \newcommand{\grammartoken}[1]{\texttt{#1}}
\newenvironment{productionlist}[1][\py@badkey]{ \newenvironment{productionlist}[1][\@undefined]{
\def\optional##1{{\Large[}##1{\Large]}} \def\optional##1{{\Large[}##1{\Large]}}
\def\production##1##2{\hypertarget{grammar-token-##1}{}% \def\production##1##2{\hypertarget{grammar-token-##1}{}%
\code{##1}&::=&\code{##2}\\} \code{##1}&::=&\code{##2}\\}

View File

@@ -0,0 +1,54 @@
{#
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 %}
<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, group, page, anchor, extra, qualifier, description)
in entries %}
<tr{% if grouptype == 2 %} class="cg-{{ cgroup }}"{% endif %}>
<td>{% if grouptype == 1 -%}
<img src="{{ pathto('_static/minus.png', 1) }}" id="toggle-{{ 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 %}

View File

@@ -98,7 +98,7 @@
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT: '{{ pathto("", 1) }}', URL_ROOT: '{{ pathto("", 1) }}',
VERSION: '{{ release|e }}', VERSION: '{{ release|e }}',
COLLAPSE_MODINDEX: false, COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ file_suffix }}', FILE_SUFFIX: '{{ file_suffix }}',
HAS_SOURCE: {{ has_source|lower }} HAS_SOURCE: {{ has_source|lower }}
}; };

View File

@@ -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 %}

View File

@@ -111,7 +111,7 @@ var Documentation = {
init : function() { init : function() {
this.fixFirefoxAnchorBug(); this.fixFirefoxAnchorBug();
this.highlightSearchWords(); this.highlightSearchWords();
this.initModIndex(); this.initIndexTable();
}, },
/** /**
@@ -192,9 +192,9 @@ var Documentation = {
}, },
/** /**
* init the modindex toggle buttons * init the domain index toggle buttons
*/ */
initModIndex : function() { initIndexTable : function() {
var togglers = $('img.toggler').click(function() { var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src'); var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7); var idnum = $(this).attr('id').substr(7);
@@ -204,7 +204,7 @@ var Documentation = {
else else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', ''); }).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) { if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click(); togglers.click();
} }
}, },

View File

@@ -99,6 +99,7 @@ tex_replacements = [
] ]
tex_escape_map = {} tex_escape_map = {}
tex_replace_map = {}
tex_hl_escape_map_old = {} # replacement map for Pygments <= 1.1 tex_hl_escape_map_old = {} # replacement map for Pygments <= 1.1
tex_hl_escape_map_new = {} # replacement map for Pygments >= 1.2 tex_hl_escape_map_new = {} # replacement map for Pygments >= 1.2
_old_cmd_chars = {ord(u'\\'): u'@', ord(u'{'): u'[', ord(u'}'): u']'} _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(): def init():
for a, b in tex_replacements: for a, b in tex_replacements:
tex_escape_map[ord(a)] = b tex_escape_map[ord(a)] = b
tex_replace_map[ord(a)] = u'_'
for a, b in tex_replacements: for a, b in tex_replacements:
if a in u'[]{}\\': continue if a in u'[]{}\\': continue

View File

@@ -24,7 +24,7 @@ from sphinx import highlighting
from sphinx.errors import SphinxError 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.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 from sphinx.util.smartypants import educateQuotesLatex
HEADER = r'''%% Generated by Sphinx. HEADER = r'''%% Generated by Sphinx.
@@ -47,7 +47,6 @@ HEADER = r'''%% Generated by Sphinx.
\newcommand{\sphinxlogo}{%(logo)s} \newcommand{\sphinxlogo}{%(logo)s}
\renewcommand{\releasename}{%(releasename)s} \renewcommand{\releasename}{%(releasename)s}
%(makeindex)s %(makeindex)s
%(makemodindex)s
''' '''
BEGIN_DOC = r''' BEGIN_DOC = r'''
@@ -58,9 +57,6 @@ BEGIN_DOC = r'''
''' '''
FOOTER = r''' FOOTER = r'''
%(footer)s
\renewcommand{\indexname}{%(modindexname)s}
%(printmodindex)s
\renewcommand{\indexname}{%(indexname)s} \renewcommand{\indexname}{%(indexname)s}
%(printindex)s %(printindex)s
\end{document} \end{document}
@@ -146,12 +142,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
'logo': '', 'logo': '',
'releasename': 'Release', 'releasename': 'Release',
'makeindex': '\\makeindex', 'makeindex': '\\makeindex',
'makemodindex': '\\makemodindex',
'shorthandoff': '', 'shorthandoff': '',
'maketitle': '\\maketitle', 'maketitle': '\\maketitle',
'tableofcontents': '\\tableofcontents', 'tableofcontents': '\\tableofcontents',
'footer': '', 'footer': '',
'printmodindex': '\\printmodindex',
'printindex': '\\printindex', 'printindex': '\\printindex',
} }
@@ -176,7 +170,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
'author': document.settings.author, 'author': document.settings.author,
'releasename': _('Release'), 'releasename': _('Release'),
'preamble': builder.config.latex_preamble, 'preamble': builder.config.latex_preamble,
'modindexname': _('Module Index'),
'indexname': _('Index'), 'indexname': _('Index'),
}) })
if document.settings.docclass == 'howto': if document.settings.docclass == 'howto':
@@ -204,9 +197,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.elements['fncychap'] = '\\usepackage[Sonny]{fncychap}' self.elements['fncychap'] = '\\usepackage[Sonny]{fncychap}'
else: else:
self.elements['classoptions'] += ',english' self.elements['classoptions'] += ',english'
if not builder.config.latex_use_modindex:
self.elements['makemodindex'] = ''
self.elements['printmodindex'] = ''
# allow the user to override them all # allow the user to override them all
self.elements.update(builder.config.latex_elements) self.elements.update(builder.config.latex_elements)
@@ -243,11 +233,60 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.first_param = 0 self.first_param = 0
def astext(self): def astext(self):
return (HEADER % self.elements + self.highlighter.get_stylesheet() + return (HEADER % self.elements +
u''.join(self.body) + FOOTER % self.elements) self.highlighter.get_stylesheet() +
u''.join(self.body) +
'\n' + self.elements['footer'] + '\n' +
self.generate_indices() +
FOOTER % self.elements)
def hypertarget(self, target, text='', anchor=True):
#return '\\hypertarget{%s}{%s}' % (self.idescape(target), text)
return (anchor and '\\phantomsection' or '') + \
'\\label{%s}%s' % (self.idescape(target), text)
def hyperlink(self, target):
#return '\\hyperlink{%s}{' % (self.idescape(target))
return '\\hyperref[%s]{' % (self.idescape(target))
def idescape(self, 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[4]:
continue
ret.append('\\item {\\texttt{%s}}, \\pageref{%s}' %
(self.encode(entry[0]), entry[4]))
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 indexinfo in domain.indices:
indexname = '%s-%s' % (domain.name, indexinfo[0])
if isinstance(indices_config, list):
if indexname not in indices_config:
continue
if not domain.has_index_entries(indexinfo[0],
self.builder.docnames):
continue
ret.append('\\renewcommand{\\indexname}{%s}\n' %
indexinfo[1])
generate(*domain.get_index(indexinfo[0],
self.builder.docnames))
return ''.join(ret)
def visit_document(self, node): def visit_document(self, node):
self.footnotestack.append(self.collect_footnotes(node)) self.footnotestack.append(self.collect_footnotes(node))
@@ -261,8 +300,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\n\\appendix\n') self.body.append('\n\\appendix\n')
self.first_document = -1 self.first_document = -1
if node.has_key('docname'): if node.has_key('docname'):
self.body.append('\\hypertarget{--doc-%s}{}' % self.body.append(self.hypertarget('--doc-' + node['docname']))
self.idescape(node['docname']))
# "- 1" because the level is increased before the title is visited # "- 1" because the level is increased before the title is visited
self.sectionlevel = self.top_sectionlevel - 1 self.sectionlevel = self.top_sectionlevel - 1
def depart_document(self, node): def depart_document(self, node):
@@ -275,21 +313,17 @@ class LaTeXTranslator(nodes.NodeVisitor):
for bi in self.bibitems: for bi in self.bibitems:
# cite_key: underscores must not be escaped # cite_key: underscores must not be escaped
cite_key = bi[0].replace(r"\_", "_") cite_key = bi[0].replace(r"\_", "_")
self.body.append('\\bibitem[%s]{%s}{\hypertarget{%s}{} %s}\n' % self.body.append('\\bibitem[%s]{%s}{%s %s}\n' %
(bi[0], cite_key, (bi[0], cite_key,
self.idescape(cite_key.lower()), bi[1])) self.hypertarget(cite_key.lower()), bi[1]))
self.body.append('\\end{thebibliography}\n') self.body.append('\\end{thebibliography}\n')
self.bibitems = [] self.bibitems = []
def visit_start_of_file(self, node): def visit_start_of_file(self, node):
# This marks the begin of a new file; therefore the current module and # collect new footnotes
# class must be reset
self.body.append('\n\\resetcurrentobjects\n')
# and also, new footnotes
self.footnotestack.append(self.collect_footnotes(node)) self.footnotestack.append(self.collect_footnotes(node))
# also add a document target # also add a document target
self.body.append('\\hypertarget{--doc-%s}{}' % self.body.append(self.hypertarget('--doc-' + node['docname']))
self.idescape(node['docname']))
self.curfilestack.append(node['docname']) self.curfilestack.append(node['docname'])
def collect_footnotes(self, node): def collect_footnotes(self, node):
@@ -321,14 +355,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
if not self.this_is_the_title: if not self.this_is_the_title:
self.sectionlevel += 1 self.sectionlevel += 1
self.body.append('\n\n') 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'): #if node.get('ids'):
# for id in node['ids']: # for id in node['ids']:
# if id not in self.written_ids: # if id not in self.written_ids:
# self.body.append(r'\hypertarget{%s}{}' % id) # self.body.append(self.hypertarget(id))
# self.written_ids.add(id) # self.written_ids.add(id)
def depart_section(self, node): def depart_section(self, node):
self.sectionlevel = max(self.sectionlevel - 1, self.sectionlevel = max(self.sectionlevel - 1,
@@ -400,6 +430,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
# just use "subparagraph", it's not numbered anyway # just use "subparagraph", it's not numbered anyway
self.body.append(r'\%s{' % self.sectionnames[-1]) self.body.append(r'\%s{' % self.sectionnames[-1])
self.context.append('}\n') self.context.append('}\n')
if self.next_section_target:
self.context[-1] += self.hypertarget(self.next_section_target,
anchor=False)
self.next_section_target = None
elif isinstance(parent, (nodes.topic, nodes.sidebar)): elif isinstance(parent, (nodes.topic, nodes.sidebar)):
self.body.append(r'\textbf{') self.body.append(r'\textbf{')
self.context.append('}\n\n\medskip\n\n') self.context.append('}\n\n\medskip\n\n')
@@ -438,7 +474,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_desc_signature(self, node): def visit_desc_signature(self, node):
if node.parent['objtype'] != 'describe' and node['ids']: if node.parent['objtype'] != 'describe' and node['ids']:
hyper = '\\hypertarget{%s}{}' % self.idescape(node['ids'][0]) hyper = self.hypertarget(node['ids'][0])
else: else:
hyper = '' hyper = ''
self.body.append(hyper) self.body.append(hyper)
@@ -700,7 +736,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_term(self, node): def visit_term(self, node):
ctx = '] \\leavevmode' ctx = '] \\leavevmode'
if node.has_key('ids') and node['ids']: 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.body.append('\\item[')
self.context.append(ctx) self.context.append(ctx)
def depart_term(self, node): def depart_term(self, node):
@@ -759,14 +795,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_module(self, node): def visit_module(self, node):
modname = node['modname'] modname = node['modname']
self.body.append('\n\\hypertarget{module-%s}{}' % self.body.append('\n' +
self.idescape(modname.replace(' ',''))) self.hypertarget('module-' + modname.replace(' ','')))
self.body.append('\n\\declaremodule[%s]{}{%s}' % ( #self.body.append('\n\\declaremodule[%s]{}{%s}' % (
modname.replace('_', ''), self.encode(modname))) # modname.replace('_', ''), self.encode(modname)))
self.body.append('\n\\modulesynopsis{%s}' % #self.body.append('\n\\modulesynopsis{%s}' %
self.encode(node['synopsis'])) # self.encode(node['synopsis']))
if node.has_key('platform'): #if node.has_key('platform'):
self.body.append('\\platform{%s}' % self.encode(node['platform'])) # self.body.append('\\platform{%s}' % self.encode(node['platform']))
def depart_module(self, node): def depart_module(self, node):
pass pass
@@ -925,7 +961,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
# indexing uses standard LaTeX index markup, so the targets # indexing uses standard LaTeX index markup, so the targets
# will be generated differently # will be generated differently
if not id.startswith('index-'): 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: if node.has_key('refid') and node['refid'] not in self.written_ids:
parindex = node.parent.index(node) parindex = node.parent.index(node)
@@ -986,14 +1022,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append('}') self.context.append('}')
elif uri.startswith('#'): elif uri.startswith('#'):
# references to labels # references to labels
self.body.append('\\hyperlink{%s}{' % self.idescape(uri[1:])) self.body.append(self.hyperlink(uri[1:]))
self.context.append('}') self.context.append('}')
elif uri.startswith('%'): elif uri.startswith('%'):
# references to documents or labels inside documents # references to documents or labels inside documents
hashindex = uri.find('#') hashindex = uri.find('#')
targetname = (hashindex == -1) and '--doc-' + uri[1:] \ targetname = (hashindex == -1) and '--doc-' + uri[1:] \
or uri[hashindex+1:] or uri[hashindex+1:]
self.body.append('\\hyperlink{%s}{' % self.idescape(targetname)) self.body.append(self.hyperlink(targetname))
self.context.append('}') self.context.append('}')
elif uri.startswith('@token'): elif uri.startswith('@token'):
if self.in_production_list: if self.in_production_list:

View File

@@ -170,7 +170,7 @@ HTML_XPATH = {
".//div[@class='footer']": 'Georg Brandl & Team', ".//div[@class='footer']": 'Georg Brandl & Team',
".//a[@href='http://python.org/']": '', ".//a[@href='http://python.org/']": '',
".//li/a[@href='genindex.html']/em": 'Index', ".//li/a[@href='genindex.html']/em": 'Index',
".//li/a[@href='modindex.html']/em": 'Module Index', ".//li/a[@href='py-modindex.html']/em": 'Module Index',
".//li/a[@href='search.html']/em": 'Search Page', ".//li/a[@href='search.html']/em": 'Search Page',
# custom sidebar only for contents # custom sidebar only for contents
".//h4": 'Contents sidebar', ".//h4": 'Contents sidebar',