Added a toctree variable to the templates, and the ability to

include external links in toctrees.

Patch by Stefan Seefeld.
This commit is contained in:
Georg Brandl 2009-01-26 21:57:15 +01:00
parent 62222ca5a1
commit e974741c74
7 changed files with 78 additions and 25 deletions

View File

@ -12,6 +12,7 @@ Other contributors, listed alphabetically, are:
* Dave Kuhlman -- original LaTeX writer
* Thomas Lamb -- linkcheck builder
* Benjamin Peterson -- unittests
* Stefan Seefeld -- toctree improvements
* Antonio Valentino -- qthelp builder
* Pauli Virtanen -- autodoc improvements
* Sebastian Wiesner -- image handling, distutils support

View File

@ -49,6 +49,9 @@ New features added
- #23: Added a ``classmethod`` directive along with ``method``
and ``staticmethod``.
- Added a toctree variable to the templates, and the ability to
include external links in toctrees.
* Configuration:
- The new ``html_add_permalinks`` config value can be used to

View File

@ -71,6 +71,9 @@ tables of contents. The ``toctree`` directive is the central element.
The second line above will link to the ``strings`` document, but will use the
title "All about strings" instead of the title of the ``strings`` document.
You can also add external links, by giving an HTTP URL instead of a document
name.
You can use "globbing" in toctree directives, by giving the ``glob`` flag
option. All entries are then matched against the list of available
documents, and matches are inserted into the list alphabetically. Example::
@ -113,7 +116,7 @@ tables of contents. The ``toctree`` directive is the central element.
Added "globbing" option.
.. versionchanged:: 0.6
Added "hidden" option.
Added "hidden" option and external links.
Special names

View File

@ -221,8 +221,12 @@ in the future.
.. data:: builder
The name of the builder (for builtin builders, ``html``, ``htmlhelp``, or
``web``).
The name of the builder (e.g. ``html`` or ``htmlhelp``).
.. data:: embedded
True if the built HTML is supposed to be embedded in some application that
handles navigation, e.g. HTML Help or Qt Help.
.. data:: next
@ -239,3 +243,18 @@ in the future.
.. data:: prev
Like :data:`next`, but for the previous page.
In documents that are created from source files (as opposed to
automatically-generated files like the module index, or documents that already
are in HTML form), these variables are also available:
.. data:: toc
The local table of contents for the current page, rendered as HTML bullet
lists.
.. data:: toctree
The global TOC tree containing the current page, rendered as HTML bullet
lists.

View File

@ -219,6 +219,8 @@ class StandaloneHTMLBuilder(Builder):
metatags = metatags,
rellinks = rellinks,
sourcename = sourcename,
toctree = self.render_partial(self.env.get_toctree_for(
docname, self))['fragment'],
toc = self.render_partial(self.env.get_toc_for(docname))['fragment'],
# only display a TOC if there's more than one item to show
display_toc = (self.env.toc_num_entries[docname] > 1),

View File

@ -27,6 +27,9 @@ def toctree_directive(name, arguments, options, content, lineno,
glob = 'glob' in options
ret = []
# (title, ref) pairs, where ref may be a document, or an external link,
# and title may be None if the document's title is to be used
entries = []
includefiles = []
includetitles = {}
all_docnames = env.found_docs.copy()
@ -39,33 +42,39 @@ def toctree_directive(name, arguments, options, content, lineno,
# look for explicit titles and documents ("Some Title <document>").
m = caption_ref_re.match(entry)
if m:
docname = m.group(2)
includetitles[docname] = m.group(1)
ref = m.group(2)
title = m.group(1)
docname = ref
else:
docname = entry
ref = docname = entry
title = None
# remove suffixes (backwards compatibility)
if docname.endswith(suffix):
docname = docname[:-len(suffix)]
# absolutize filenames
docname = docname_join(env.docname, docname)
if docname not in env.found_docs:
if ref.startswith('http://'): # FIXME: generalize to arbitrary xrefs
entries.append((title, ref))
elif docname not in env.found_docs:
ret.append(state.document.reporter.warning(
'toctree references unknown document %r' % docname, line=lineno))
else:
entries.append((title, ref))
includefiles.append(docname)
else:
patname = docname_join(env.docname, entry)
docnames = sorted(patfilter(all_docnames, patname))
for docname in docnames:
all_docnames.remove(docname) # don't include it again
entries.append((None, docname))
includefiles.append(docname)
if not docnames:
ret.append(state.document.reporter.warning(
'toctree glob pattern %r didn\'t match any documents' % entry,
line=lineno))
subnode = addnodes.toctree()
subnode['entries'] = entries
subnode['includefiles'] = includefiles
subnode['includetitles'] = includetitles
subnode['maxdepth'] = options.get('maxdepth', -1)
subnode['glob'] = glob
subnode['hidden'] = 'hidden' in options

View File

@ -828,6 +828,17 @@ class BuildEnvironment:
node['refuri'] = node['anchorname']
return toc
def get_toctree_for(self, docname, builder):
"""Return the global TOC nodetree."""
# XXX why master_doc?
doctree = self.get_doctree(self.config.master_doc)
for toctreenode in doctree.traverse(addnodes.toctree):
result = self.resolve_toctree(docname, builder, toctreenode,
prune=True)
if result is not None:
return result
# -------
# these are called from docutils directives and therefore use self.docname
#
@ -912,35 +923,46 @@ class BuildEnvironment:
if toctree.get('hidden', False):
return None
def _walk_depth(node, depth, maxdepth, titleoverrides):
def _walk_depth(node, depth, maxdepth):
"""Utility: Cut a TOC at a specified depth."""
for subnode in node.children[:]:
if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)):
subnode['classes'].append('toctree-l%d' % (depth-1))
_walk_depth(subnode, depth, maxdepth, titleoverrides)
_walk_depth(subnode, depth, maxdepth)
elif isinstance(subnode, nodes.bullet_list):
if maxdepth > 0 and depth > maxdepth:
subnode.parent.replace(subnode, [])
else:
_walk_depth(subnode, depth+1, maxdepth, titleoverrides)
_walk_depth(subnode, depth+1, maxdepth)
def _entries_from_toctree(toctreenode, separate=False, subtree=False):
"""Return TOC entries for a toctree node."""
includefiles = map(str, toctreenode['includefiles'])
refs = [(e[0], str(e[1])) for e in toctreenode['entries']]
entries = []
for includefile in includefiles:
for (title, ref) in refs:
try:
toc = self.tocs[includefile].deepcopy()
if ref.startswith('http://'): # FIXME: (see directives/other.py)
reference = nodes.reference('', '', refuri=ref, anchorname='',
*[nodes.Text(title)])
para = addnodes.compact_paragraph('', '', reference)
item = nodes.list_item('', para)
toc = nodes.bullet_list('', item)
else:
toc = self.tocs[ref].deepcopy()
if title and toc.children and len(toc.children) == 1:
for refnode in toc.children[0].traverse(nodes.reference):
if refnode['refuri'] == ref and not refnode['anchorname']:
refnode.children = [nodes.Text(title)]
if not toc.children:
# empty toc means: no titles will show up in the toctree
self.warn(docname, 'toctree contains reference to document '
'%r that doesn\'t have a title: no link will be '
'generated' % includefile)
'generated' % ref)
except KeyError:
# this is raised if the included file does not exist
self.warn(docname, 'toctree contains reference to nonexisting '
'document %r' % includefile)
'document %r' % ref)
else:
# if titles_only is given, only keep the main title and
# sub-toctrees
@ -969,7 +991,6 @@ class BuildEnvironment:
return entries
maxdepth = maxdepth or toctree.get('maxdepth', -1)
titleoverrides = toctree.get('includetitles', {})
# NOTE: previously, this was separate=True, but that leads to artificial
# separation when two or more toctree entries form a logical unit, so
@ -981,14 +1002,9 @@ class BuildEnvironment:
newnode = addnodes.compact_paragraph('', '', *tocentries)
newnode['toctree'] = True
# prune the tree to maxdepth and replace titles, also set level classes
_walk_depth(newnode, 1, prune and maxdepth or 0, titleoverrides)
# replace titles, if needed, and set the target paths in the
# toctrees (they are not known at TOC generation time)
_walk_depth(newnode, 1, prune and maxdepth or 0)
# set the target paths in the toctrees (they are not known at TOC generation time)
for refnode in newnode.traverse(nodes.reference):
if titleoverrides and not refnode['anchorname'] \
and refnode['refuri'] in titleoverrides:
newtitle = titleoverrides[refnode['refuri']]
refnode.children = [nodes.Text(newtitle)]
refnode['refuri'] = builder.get_relative_uri(
docname, refnode['refuri']) + refnode['anchorname']
return newnode