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``
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.

View File

@ -162,8 +162,8 @@ 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:`object descriptions <desc-units>`, and from :dir:`index` directives.

View File

@ -208,10 +208,11 @@ General configuration
.. 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 ``[]``.
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
@ -528,10 +529,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``.
@ -769,10 +785,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
@ -839,9 +869,7 @@ These options influence LaTeX output.
``'logo'``
``'releasename'``
``'makeindex'``
``'makemodindex'``
``'shorthandoff'``
``'printmodindex'``
.. confval:: latex_docclass

View File

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

View File

@ -230,6 +230,20 @@ 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 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
# typically doesn't include the time of day
lufmt = self.config.html_last_updated_fmt
@ -254,11 +268,8 @@ class StandaloneHTMLBuilder(Builder):
rellinks = []
if self.config.html_use_index:
rellinks.append(('genindex', _('General Index'), 'I', _('index')))
# XXX generalization of modindex?
if self.config.html_use_modindex and \
self.env.domaindata['py']['modules']:
rellinks.append(('modindex', _('Global Module Index'),
'M', _('modules')))
for index in self.domain_indices:
rellinks.append(('%s-%s' % index[0:2], index[2], '', index[3]))
if self.config.html_style is not None:
stylename = self.config.html_style
@ -396,9 +407,8 @@ class StandaloneHTMLBuilder(Builder):
if self.config.html_use_index:
self.write_genindex()
# the global module index
if self.config.html_use_modindex:
self.write_modindex()
# the global domain-specific indices
self.write_domain_indices()
# the search page
if self.name != 'htmlhelp':
@ -454,98 +464,17 @@ class StandaloneHTMLBuilder(Builder):
else:
self.handle_page('genindex', genindexcontext, 'genindex.html')
def write_modindex(self):
moduleindex = self.env.domaindata['py']['modules']
if not moduleindex:
return
# 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
moduleindex.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 index in self.domain_indices:
content, collapse = self.env.domains[index[0]].get_index(index[1])
indexcontext = dict(
indextitle = index[2],
content = content,
collapse_index = collapse,
)
indexname = '%s-%s' % index[0:2]
self.info(' ' + indexname, nonl=1)
self.handle_page(indexname, indexcontext, 'domainindex.html')
def copy_image_files(self):
# copy image files

View File

@ -217,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)

View File

@ -130,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)

View File

@ -81,7 +81,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'),
@ -125,7 +126,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),

View File

@ -70,6 +70,8 @@ class Domain(object):
directives = {}
#: role name -> role callable
roles = {}
#: (index identifier, localized index name, localized short name) tuples
indices = []
#: data value for a fresh environment
initial_data = {}
@ -175,6 +177,22 @@ class Domain(object):
"""
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.std import StandardDomain

View File

@ -462,6 +462,9 @@ class PythonDomain(Domain):
'objects': {}, # fullname -> docname, objtype
'modules': {}, # modname -> docname, synopsis, platform, deprecated
}
indices = [
('modindex', l_('Global Module Index'), l_('modules')),
]
def clear_doc(self, docname):
for fullname, (fn, _) in self.data['objects'].items():
@ -545,3 +548,80 @@ class PythonDomain(Domain):
yield (modname, 'module', info[0], 'module-' + modname, 0)
for refname, (docname, type) in self.data['objects'].iteritems():
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):
"""
Move module targets to their nearest enclosing section title.
XXX Python specific
"""
default_priority = 210
@ -318,11 +320,13 @@ class BuildEnvironment:
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):

View File

@ -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,7 +223,7 @@ latex_documents = [
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
#latex_domain_indices = True
# -- Options for Epub output ---------------------------------------------------

View File

@ -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) '$<'

View File

@ -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@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@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}%
@ -301,8 +222,6 @@
\let\makelabel=\py@itemnewline}
}{\end{list}}
\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]}}}
@ -325,7 +244,7 @@
% 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{\hypertarget{grammar-token-##1}{}%
\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 = {
URL_ROOT: '{{ pathto("", 1) }}',
VERSION: '{{ release|e }}',
COLLAPSE_MODINDEX: false,
COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ file_suffix }}',
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() {
this.fixFirefoxAnchorBug();
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 src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
@ -204,7 +204,7 @@ var Documentation = {
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();
}
},

View File

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

View File

@ -24,7 +24,7 @@ from sphinx import highlighting
from sphinx.errors import SphinxError
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}
@ -146,12 +142,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
'logo': '',
'releasename': 'Release',
'makeindex': '\\makeindex',
'makemodindex': '\\makemodindex',
'shorthandoff': '',
'maketitle': '\\maketitle',
'tableofcontents': '\\tableofcontents',
'footer': '',
'printmodindex': '\\printmodindex',
'printindex': '\\printindex',
}
@ -176,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':
@ -204,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)
@ -243,11 +233,60 @@ class LaTeXTranslator(nodes.NodeVisitor):
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, 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):
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):
self.footnotestack.append(self.collect_footnotes(node))
@ -261,8 +300,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-' + node['docname']))
# "- 1" because the level is increased before the title is visited
self.sectionlevel = self.top_sectionlevel - 1
def depart_document(self, node):
@ -275,21 +313,17 @@ class LaTeXTranslator(nodes.NodeVisitor):
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' %
self.body.append('\\bibitem[%s]{%s}{%s %s}\n' %
(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.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.body.append(self.hypertarget('--doc-' + node['docname']))
self.curfilestack.append(node['docname'])
def collect_footnotes(self, node):
@ -321,14 +355,10 @@ 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.body.append(self.hypertarget(id))
# self.written_ids.add(id)
def depart_section(self, node):
self.sectionlevel = max(self.sectionlevel - 1,
@ -400,6 +430,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_target:
self.context[-1] += self.hypertarget(self.next_section_target,
anchor=False)
self.next_section_target = None
elif isinstance(parent, (nodes.topic, nodes.sidebar)):
self.body.append(r'\textbf{')
self.context.append('}\n\n\medskip\n\n')
@ -438,7 +474,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_desc_signature(self, node):
if node.parent['objtype'] != 'describe' and node['ids']:
hyper = '\\hypertarget{%s}{}' % self.idescape(node['ids'][0])
hyper = self.hypertarget(node['ids'][0])
else:
hyper = ''
self.body.append(hyper)
@ -700,7 +736,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):
@ -759,14 +795,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
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']))
self.body.append('\n' +
self.hypertarget('module-' + 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
@ -925,7 +961,7 @@ 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)
@ -986,14 +1022,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append('}')
elif uri.startswith('#'):
# references to labels
self.body.append('\\hyperlink{%s}{' % self.idescape(uri[1:]))
self.body.append(self.hyperlink(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))
self.body.append(self.hyperlink(targetname))
self.context.append('}')
elif uri.startswith('@token'):
if self.in_production_list:

View File

@ -170,7 +170,7 @@ HTML_XPATH = {
".//div[@class='footer']": 'Georg Brandl & Team',
".//a[@href='http://python.org/']": '',
".//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',
# custom sidebar only for contents
".//h4": 'Contents sidebar',