diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index 660e63ca6..0b2946ae5 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -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)
diff --git a/sphinx/config.py b/sphinx/config.py
index a3de68f5a..24c3e83f1 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -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),
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index a7cdd9047..ab98ee616 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -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(
diff --git a/sphinx/environment.py b/sphinx/environment.py
index 4aa32ed08..aa5eede6c 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -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
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index edfb31d8a..6b64483da 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -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.+)://.*')
# SEP separates path elements in the canonical file names
#