Patch from Stefan Seefeld: make local toctree collapsible.

This commit is contained in:
Georg Brandl 2009-02-07 13:32:47 +01:00
parent 2d76170b9c
commit 394282223b
5 changed files with 36 additions and 11 deletions

View File

@ -164,6 +164,10 @@ class StandaloneHTMLBuilder(Builder):
)
self.globalcontext.update(self.config.html_context)
def _get_local_toctree(self, docname):
return self.render_partial(self.env.get_toctree_for(
docname, self, self.config.html_collapse_toctree))['fragment']
def get_doc_context(self, docname, body, metatags):
"""Collect items for the template context of a page."""
# find out relations
@ -219,8 +223,6 @@ 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),
@ -474,6 +476,7 @@ class StandaloneHTMLBuilder(Builder):
ctx['pathto'] = pathto
ctx['hasdoc'] = lambda name: name in self.env.all_docs
ctx['customsidebar'] = self.config.html_sidebars.get(pagename)
ctx['toctree'] = self._get_local_toctree(pagename)
ctx.update(addctx)
self.app.emit('html-page-context', pagename, templatename, ctx, event_arg)

View File

@ -66,6 +66,7 @@ class Config(object):
html_use_smartypants = (True, False),
html_translator_class = (None, False),
html_sidebars = ({}, False),
html_collapse_toctree = (False, False),
html_additional_pages = ({}, False),
html_use_modindex = (True, False),
html_add_permalinks = (True, False),

View File

@ -14,7 +14,7 @@ from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.locale import pairindextypes
from sphinx.util import patfilter, ws_re, caption_ref_re, docname_join
from sphinx.util import patfilter, ws_re, caption_ref_re, url_re, docname_join
from sphinx.util.compat import make_admonition
@ -53,7 +53,7 @@ def toctree_directive(name, arguments, options, content, lineno,
docname = docname[:-len(suffix)]
# absolutize filenames
docname = docname_join(env.docname, docname)
if ref.startswith('http://'): # FIXME: generalize to arbitrary xrefs
if url_re.match(ref):
entries.append((title, ref))
elif docname not in env.found_docs:
ret.append(state.document.reporter.warning(

View File

@ -44,7 +44,7 @@ from docutils.transforms.parts import ContentsFilter
from sphinx import addnodes
from sphinx.util import movefile, get_matching_docs, SEP, ustrftime, \
docname_join, FilenameUniqDict
docname_join, FilenameUniqDict, url_re
from sphinx.directives import additional_xref_types
default_settings = {
@ -830,12 +830,12 @@ class BuildEnvironment:
node['refuri'] = node['anchorname']
return toc
def get_toctree_for(self, docname, builder):
def get_toctree_for(self, docname, builder, collapse):
"""Return the global TOC nodetree."""
doctree = self.get_doctree(self.config.master_doc)
for toctreenode in doctree.traverse(addnodes.toctree):
result = self.resolve_toctree(docname, builder, toctreenode,
prune=True)
prune=True, collapse=collapse)
if result is not None:
return result
@ -909,7 +909,7 @@ class BuildEnvironment:
return doctree
def resolve_toctree(self, docname, builder, toctree, prune=True, maxdepth=0,
titles_only=False):
titles_only=False, collapse=False):
"""
Resolve a *toctree* node into individual bullet lists with titles
as items, returning None (if no containing titles are found) or
@ -919,6 +919,8 @@ class BuildEnvironment:
to the value of the *maxdepth* option on the *toctree* node.
If *titles_only* is True, only toplevel document titles will be in the
resulting tree.
If *collapse* is True, all branches not containing docname will
be collapsed.
"""
if toctree.get('hidden', False):
return None
@ -935,13 +937,30 @@ class BuildEnvironment:
else:
_walk_depth(subnode, depth+1, maxdepth)
# cull sub-entries whose parents aren't 'current'
if (collapse and
depth > 1 and
'current' not in subnode.parent['classes']):
subnode.parent.remove(subnode)
elif isinstance(subnode, nodes.reference):
# Identify the toc entry pointing to the current document.
if subnode['refuri'] == docname and not subnode['anchorname']:
# tag the whole branch as 'current'
# (We can't use traverse here as 'ascend' un-intuitively
# implies 'siblings'.)
p = subnode
while p:
p['classes'].append('current')
p = p.parent
def _entries_from_toctree(toctreenode, separate=False, subtree=False):
"""Return TOC entries for a toctree node."""
refs = [(e[0], str(e[1])) for e in toctreenode['entries']]
entries = []
for (title, ref) in refs:
try:
if ref.startswith('http://'): # FIXME: (see directives/other.py)
if url_re.match(ref):
reference = nodes.reference('', '', refuri=ref, anchorname='',
*[nodes.Text(title)])
para = addnodes.compact_paragraph('', '', reference)
@ -1001,11 +1020,13 @@ 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)
# set the target paths in the toctrees (they are not known at TOC generation time)
for refnode in newnode.traverse(nodes.reference):
if not refnode['refuri'].startswith('http://'): # FIXME: see above
if not url_re.match(refnode['refuri']):
refnode['refuri'] = builder.get_relative_uri(
docname, refnode['refuri']) + refnode['anchorname']
return newnode

View File

@ -23,7 +23,7 @@ from os import path
# Generally useful regular expressions.
ws_re = re.compile(r'\s+')
caption_ref_re = re.compile(r'^([^<]+?)\s*<(.+)>$')
url_re = re.compile(r'(?P<schema>.+)://.*')
# SEP separates path elements in the canonical file names
#