From 2f09d24472f03f5d170fa5b70903301d3614f27c Mon Sep 17 00:00:00 2001
From: Georg Brandl
Date: Thu, 7 Jan 2010 17:56:09 +0100
Subject: [PATCH] The ``html_sidebars`` config value can now contain patterns
as keys, and the values can be lists that explicitly select which sidebar
templates should be rendered.
That means that the builtin sidebar contents can be included only selectively.
---
CHANGES | 5 +++
doc/conf.py | 2 +-
doc/config.rst | 51 +++++++++++++++++++++++----
sphinx/builders/html.py | 40 +++++++++++++++++----
sphinx/themes/basic/globaltoc.html | 15 ++++++++
sphinx/themes/basic/layout.html | 50 ++------------------------
sphinx/themes/basic/localtoc.html | 15 ++++++++
sphinx/themes/basic/relations.html | 21 +++++++++++
sphinx/themes/basic/searchbox.html | 26 ++++++++++++++
sphinx/themes/basic/sourcelink.html | 18 ++++++++++
sphinx/util/__init__.py | 18 +++++++++-
tests/root/_templates/contentssb.html | 2 ++
tests/root/_templates/customsb.html | 2 ++
tests/root/conf.py | 2 +-
tests/test_build_html.py | 4 +++
15 files changed, 209 insertions(+), 62 deletions(-)
create mode 100644 sphinx/themes/basic/globaltoc.html
create mode 100644 sphinx/themes/basic/localtoc.html
create mode 100644 sphinx/themes/basic/relations.html
create mode 100644 sphinx/themes/basic/searchbox.html
create mode 100644 sphinx/themes/basic/sourcelink.html
create mode 100644 tests/root/_templates/contentssb.html
create mode 100644 tests/root/_templates/customsb.html
diff --git a/CHANGES b/CHANGES
index 5de227f2a..c69942243 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,11 @@
Release 1.0 (in development)
============================
+* The ``html_sidebars`` config value can now contain patterns as
+ keys, and the values can be lists that explicitly select which
+ sidebar templates should be rendered. That means that the builtin
+ sidebar contents can be included only selectively.
+
* ``html_static_path`` can now contain single file entries.
* The new universal config value ``exclude_patterns`` makes the
diff --git a/doc/conf.py b/doc/conf.py
index feda5fd16..836ad52eb 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -52,7 +52,7 @@ html_last_updated_fmt = '%b %d, %Y'
html_index = 'index.html'
# Custom sidebar templates, maps page names to templates.
-html_sidebars = {'index': 'indexsidebar.html'}
+html_sidebars = {'index': ['indexsidebar.html', 'searchbox.html']}
# Additional templates that should be rendered to pages, maps page names to
# templates.
diff --git a/doc/config.rst b/doc/config.rst
index 745638c8f..e4693d848 100644
--- a/doc/config.rst
+++ b/doc/config.rst
@@ -90,7 +90,7 @@ General configuration
.. confval:: exclude_patterns
A list of glob-style patterns that should be excluded when looking for source
- files. [#]_ They are matched against the source file names relative to the
+ files. [1]_ They are matched against the source file names relative to the
source directory, using slashes as directory separators on all platforms.
Example patterns:
@@ -445,14 +445,53 @@ that use Sphinx' HTMLWriter class.
.. confval:: html_sidebars
Custom sidebar templates, must be a dictionary that maps document names to
- template names. Example::
+ template names.
+
+ The keys can contain glob-style patterns [1]_, in which case all matching
+ documents will get the specified sidebars. (A warning is emitted when a
+ more than one glob-style pattern matches for any document.)
+
+ The values can be either lists or single strings.
+
+ * If a value is a list, it specifies the complete list of sidebar templates
+ to include. If all or some of the default sidebars are to be included,
+ they must be put into this list as well.
+
+ The default sidebars (for documents that don't match any pattern) are:
+ ``['localtoc.html', 'relations.html', 'sourcelink.html',
+ 'searchbox.html']``.
+
+ * If a value is a single string, it specifies a custom sidebar to be added
+ between the ``'sourcelink.html'`` and ``'searchbox.html'`` entries. This
+ is for compatibility with Sphinx versions before 1.0.
+
+ Builtin sidebar templates that can be rendered are:
+
+ * **localtoc.html** -- a fine-grained table of contents of the current document
+ * **globaltoc.html** -- a coarse-grained table of contents for the whole
+ documentation set, collapsed
+ * **relations.html** -- two links to the previous and next documents
+ * **sourcelink.html** -- a link to the source of the current document, if
+ enabled in :confval:`html_show_sourcelink`
+ * **searchbox.html** -- the "quick search" box
+
+ Example::
html_sidebars = {
- 'using/windows': 'windowssidebar.html'
+ '**': ['globaltoc.html', 'sourcelink.html', 'searchbox.html'],
+ 'using/windows': ['windowssidebar.html', 'searchbox.html'],
}
- This will render the template ``windowssidebar.html`` within the sidebar of
- the given document.
+ This will render the custom template ``windowssidebar.html`` and the quick
+ search box within the sidebar of the given document, and render the default
+ sidebars for all other pages (except that the local TOC is replaced by the
+ global TOC).
+
+ .. versionadded:: 1.0
+ The ability to use globbing keys and to specify multiple sidebars.
+
+ Note that this value only has no effect if the chosen theme does not possess
+ a sidebar, like the builtin **scrolls** and **haiku** themes.
.. confval:: html_additional_pages
@@ -835,7 +874,7 @@ These options influence LaTeX output.
.. rubric:: Footnotes
-.. [#] A note on available globbing syntax: you can use the standard shell
+.. [1] A note on available globbing syntax: you can use the standard shell
constructs ``*``, ``?``, ``[...]`` and ``[!...]`` with the feature that
these all don't match slashes. A double star ``**`` can be used to match
any sequence of characters *including* slashes.
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index 31af59033..09be64f21 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -28,8 +28,8 @@ from docutils.frontend import OptionParser
from docutils.readers.doctree import Reader as DoctreeReader
from sphinx import package_dir, __version__
-from sphinx.util import SEP, os_path, relative_uri, ensuredir, \
- movefile, ustrftime, copy_static_entry, copyfile, compile_matchers
+from sphinx.util import SEP, os_path, relative_uri, ensuredir, patmatch, \
+ movefile, ustrftime, copy_static_entry, copyfile, compile_matchers, any
from sphinx.errors import SphinxError
from sphinx.search import js_index
from sphinx.theming import Theme
@@ -74,6 +74,9 @@ class StandaloneHTMLBuilder(Builder):
# Dito for this one.
css_files = []
+ default_sidebars = ['localtoc.html', 'relations.html',
+ 'sourcelink.html', 'searchbox.html']
+
# cached publisher object for snippets
_publisher = None
@@ -654,6 +657,33 @@ class StandaloneHTMLBuilder(Builder):
def get_outfilename(self, pagename):
return path.join(self.outdir, os_path(pagename) + self.out_suffix)
+ def get_sidebars(self, pagename):
+ def has_wildcard(pattern):
+ return any(char in pattern for char in '*?[')
+ sidebars = None
+ matched = None
+ for pattern, patsidebars in self.config.html_sidebars.iteritems():
+ if patmatch(pagename, pattern):
+ if matched:
+ if has_wildcard(pattern):
+ # warn if both patterns contain wildcards
+ if has_wildcard(matched):
+ self.warn('page %s matches two patterns in '
+ 'html_sidebars: %r and %r' %
+ (pagename, matched, pattern))
+ # else the already matched pattern is more specific
+ # than the present one, because it contains no wildcard
+ continue
+ matched = pattern
+ sidebars = patsidebars
+ if sidebars is None:
+ sidebars = self.default_sidebars
+ elif isinstance(sidebars, basestring):
+ # 0.x compatible mode: insert custom sidebar before searchbox
+ sidebars = self.default_sidebars[:-1] + [sidebars] + \
+ self.default_sidebars[-1:]
+ return sidebars
+
# --------- these are overwritten by the serialization builder
def get_target_uri(self, docname, typ=None):
@@ -673,9 +703,9 @@ class StandaloneHTMLBuilder(Builder):
return uri
ctx['pathto'] = pathto
ctx['hasdoc'] = lambda name: name in self.env.all_docs
- ctx['customsidebar'] = self.config.html_sidebars.get(pagename)
ctx['encoding'] = encoding = self.config.html_output_encoding
ctx['toctree'] = lambda **kw: self._get_local_toctree(pagename, **kw)
+ ctx['sidebars'] = self.get_sidebars(pagename)
ctx.update(addctx)
self.app.emit('html-page-context', pagename, templatename,
@@ -790,9 +820,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
def handle_page(self, pagename, ctx, templatename='page.html',
outfilename=None, event_arg=None):
ctx['current_page_name'] = pagename
- sidebarfile = self.config.html_sidebars.get(pagename)
- if sidebarfile:
- ctx['customsidebar'] = sidebarfile
+ ctx['sidebars'] = self.get_sidebars(pagename)
if not outfilename:
outfilename = path.join(self.outdir,
diff --git a/sphinx/themes/basic/globaltoc.html b/sphinx/themes/basic/globaltoc.html
new file mode 100644
index 000000000..472af34f0
--- /dev/null
+++ b/sphinx/themes/basic/globaltoc.html
@@ -0,0 +1,15 @@
+{#
+ basic/globaltoc.html
+ ~~~~~~~~~~~~~~~~~~~~
+
+ Sphinx sidebar template: global table of contents.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{%- block sidebartoc %}
+{%- if display_toc %}
+
+ {{ toctree() }}
+{%- endif %}
+{%- endblock %}
diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html
index d86da2cb7..97b68f8a0 100644
--- a/sphinx/themes/basic/layout.html
+++ b/sphinx/themes/basic/layout.html
@@ -46,53 +46,9 @@
{%- endif %}
{%- endblock %}
- {%- block sidebartoc %}
- {%- if display_toc %}
-
- {{ toc }}
- {%- endif %}
- {%- endblock %}
- {%- block sidebarrel %}
- {%- if prev %}
- {{ _('Previous topic') }}
- {{ prev.title }}
- {%- endif %}
- {%- if next %}
- {{ _('Next topic') }}
- {{ next.title }}
- {%- endif %}
- {%- endblock %}
- {%- block sidebarsourcelink %}
- {%- if show_source and has_source and sourcename %}
- {{ _('This Page') }}
-
- {%- endif %}
- {%- endblock %}
- {%- if customsidebar %}
- {% include customsidebar %}
- {%- endif %}
- {%- block sidebarsearch %}
- {%- if pagename != "search" %}
-
-
{{ _('Quick search') }}
-
-
- {{ _('Enter search terms or a module, class or function name.') }}
-
-
-
- {%- endif %}
- {%- endblock %}
+ {%- for sidebar in sidebars %}
+ {%- include sidebar %}
+ {%- endfor %}
{%- endif %}{% endif %}
diff --git a/sphinx/themes/basic/localtoc.html b/sphinx/themes/basic/localtoc.html
new file mode 100644
index 000000000..dab70cd88
--- /dev/null
+++ b/sphinx/themes/basic/localtoc.html
@@ -0,0 +1,15 @@
+{#
+ basic/localtoc.html
+ ~~~~~~~~~~~~~~~~~~~
+
+ Sphinx sidebar template: local table of contents.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{%- block sidebartoc %}
+{%- if display_toc %}
+
+ {{ toc }}
+{%- endif %}
+{%- endblock %}
diff --git a/sphinx/themes/basic/relations.html b/sphinx/themes/basic/relations.html
new file mode 100644
index 000000000..18e7cc4c3
--- /dev/null
+++ b/sphinx/themes/basic/relations.html
@@ -0,0 +1,21 @@
+{#
+ basic/relations.html
+ ~~~~~~~~~~~~~~~~~~~~
+
+ Sphinx sidebar template: relation links.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{%- block sidebarrel %}
+{%- if prev %}
+ {{ _('Previous topic') }}
+ {{ prev.title }}
+{%- endif %}
+{%- if next %}
+ {{ _('Next topic') }}
+ {{ next.title }}
+{%- endif %}
+{%- endblock %}
diff --git a/sphinx/themes/basic/searchbox.html b/sphinx/themes/basic/searchbox.html
new file mode 100644
index 000000000..fb5e08896
--- /dev/null
+++ b/sphinx/themes/basic/searchbox.html
@@ -0,0 +1,26 @@
+{#
+ basic/searchbox.html
+ ~~~~~~~~~~~~~~~~~~~~
+
+ Sphinx sidebar template: quick search box.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{%- block sidebarsearch %}
+{%- if pagename != "search" %}
+
+
{{ _('Quick search') }}
+
+
+ {{ _('Enter search terms or a module, class or function name.') }}
+
+
+
+{%- endif %}
+{%- endblock %}
diff --git a/sphinx/themes/basic/sourcelink.html b/sphinx/themes/basic/sourcelink.html
new file mode 100644
index 000000000..665e12728
--- /dev/null
+++ b/sphinx/themes/basic/sourcelink.html
@@ -0,0 +1,18 @@
+{#
+ basic/sourcelink.html
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ Sphinx sidebar template: "show source" link.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{%- block sidebarsourcelink %}
+{%- if show_source and has_source and sourcename %}
+ {{ _('This Page') }}
+
+{%- endif %}
+{%- endblock %}
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index ab277f4a1..a7d9b67f6 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -12,7 +12,6 @@
import os
import re
import sys
-import stat
import time
import errno
import types
@@ -285,6 +284,14 @@ def compile_matchers(patterns):
_pat_cache = {}
+def patmatch(name, pat):
+ """
+ Return if name matches pat. Adapted from fnmatch module.
+ """
+ if pat not in _pat_cache:
+ _pat_cache[pat] = re.compile(_translate_pattern(pat))
+ return _pat_cache[pat].match(name)
+
def patfilter(names, pat):
"""
Return the subset of the list NAMES that match PAT.
@@ -483,6 +490,15 @@ def split_explicit_title(text):
return False, text, text
+try:
+ any = any
+except NameError:
+ def any(gen):
+ for i in gen:
+ if i:
+ return True
+ return False
+
# monkey-patch Node.traverse to get more speed
# traverse() is called so many times during a build that it saves
# on average 20-25% overall build time!
diff --git a/tests/root/_templates/contentssb.html b/tests/root/_templates/contentssb.html
new file mode 100644
index 000000000..9951d3c35
--- /dev/null
+++ b/tests/root/_templates/contentssb.html
@@ -0,0 +1,2 @@
+{# sidebar only for contents document #}
+Contents sidebar
\ No newline at end of file
diff --git a/tests/root/_templates/customsb.html b/tests/root/_templates/customsb.html
new file mode 100644
index 000000000..cc88b8cfb
--- /dev/null
+++ b/tests/root/_templates/customsb.html
@@ -0,0 +1,2 @@
+{# custom sidebar template #}
+Custom sidebar
diff --git a/tests/root/conf.py b/tests/root/conf.py
index 880918771..a3783511b 100644
--- a/tests/root/conf.py
+++ b/tests/root/conf.py
@@ -31,7 +31,7 @@ rst_epilog = '.. |subst| replace:: global substitution'
html_theme = 'testtheme'
html_theme_path = ['.']
html_theme_options = {'testopt': 'testoverride'}
-
+html_sidebars = {'**': 'customsb.html', 'contents': 'contentssb.html'}
html_style = 'default.css'
html_static_path = ['_static', 'templated.css_t']
html_last_updated_fmt = '%b %d, %Y'
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index 37d57dd5c..e8189e67b 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -86,6 +86,8 @@ HTML_XPATH = {
".//dl[@class='userdesc']": '',
".//dt[@id='userdescrole-myobj']": '',
".//a[@href='#userdescrole-myobj']": '',
+ # custom sidebar
+ ".//h4": 'Custom sidebar',
},
'contents.html': {
".//meta[@name='hc'][@content='hcval']": '',
@@ -98,6 +100,8 @@ HTML_XPATH = {
".//title": 'Sphinx ',
".//div[@class='footer']": 'Georg Brandl & Team',
".//a[@href='http://python.org/']": '',
+ # custom sidebar only for contents
+ ".//h4": 'Contents sidebar',
},
'bom.html': {
".//title": " File with UTF-8 BOM",