From b2c76f44b6f0a8ed8a7832804f993aab7037532d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 10 Jan 2017 02:36:37 +0900 Subject: [PATCH] Add TocTree adapter --- sphinx/builders/html.py | 10 +- sphinx/environment/__init__.py | 30 ++- sphinx/environment/adapters/__init__.py | 10 + sphinx/environment/adapters/toctree.py | 324 ++++++++++++++++++++++++ sphinx/environment/managers/toctree.py | 284 +-------------------- sphinx/ext/autosummary/__init__.py | 3 +- 6 files changed, 369 insertions(+), 292 deletions(-) create mode 100644 sphinx/environment/adapters/__init__.py create mode 100644 sphinx/environment/adapters/toctree.py diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 3a074a1cc..5c3d9601e 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -45,6 +45,7 @@ from sphinx.highlighting import PygmentsBridge from sphinx.util.console import bold, darkgreen # type: ignore from sphinx.writers.html import HTMLWriter, HTMLTranslator, \ SmartyPantsHTMLTranslator +from sphinx.environment.adapters.toctree import TocTree if False: # For type annotation @@ -439,7 +440,7 @@ class StandaloneHTMLBuilder(Builder): meta = self.env.metadata.get(docname) # local TOC and global TOC tree - self_toc = self.env.get_toc_for(docname, self) + self_toc = TocTree(self.env).get_toc_for(docname, self) toc = self.render_partial(self_toc)['fragment'] return dict( @@ -763,7 +764,7 @@ class StandaloneHTMLBuilder(Builder): # type: (unicode, bool, Any) -> unicode if 'includehidden' not in kwds: kwds['includehidden'] = False - return self.render_partial(self.env.get_toctree_for( + return self.render_partial(TocTree(self.env).get_toctree_for( docname, self, collapse, **kwds))['fragment'] def get_outfilename(self, pagename): @@ -1010,7 +1011,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): # type: (unicode, bool, Any) -> unicode if 'includehidden' not in kwds: kwds['includehidden'] = False - toctree = self.env.get_toctree_for(docname, self, collapse, **kwds) + toctree = TocTree(self.env).get_toctree_for(docname, self, collapse, **kwds) self.fix_refuris(toctree) return self.render_partial(toctree)['fragment'] @@ -1066,7 +1067,8 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): def get_doc_context(self, docname, body, metatags): # type: (unicode, unicode, Dict) -> Dict # no relation links... - toc = self.env.get_toctree_for(self.config.master_doc, self, False) # type: Any + toc = TocTree(self.env).get_toctree_for(self.config.master_doc, + self, False) # if there is no toctree, toc is None if toc: self.fix_refuris(toc) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index fd975c4ea..92a722aae 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -47,6 +47,7 @@ from sphinx.util.websupport import is_commentable from sphinx.errors import SphinxError, ExtensionError from sphinx.versioning import add_uids, merge_doctrees from sphinx.deprecation import RemovedInSphinx20Warning +from sphinx.environment.adapters.toctree import TocTree from sphinx.environment.managers.indexentries import IndexEntries from sphinx.environment.managers.toctree import Toctree @@ -847,17 +848,26 @@ class BuildEnvironment(object): """Note a TOC tree directive in a document and gather information about file relations from it. """ - self.toctree.note_toctree(docname, toctreenode) # type: ignore + warnings.warn('env.note_toctree() is deprecated. ' + 'Use sphinx.environment.adapters.toctre.TocTree instead.', + RemovedInSphinx20Warning) + TocTree(self).note(docname, toctreenode) def get_toc_for(self, docname, builder): - # type: (unicode, Builder) -> addnodes.toctree + # type: (unicode, Builder) -> Dict[unicode, nodes.Node] """Return a TOC nodetree -- for use on the same page only!""" - return self.toctree.get_toc_for(docname, builder) # type: ignore + warnings.warn('env.get_toc_for() is deprecated. ' + 'Use sphinx.environment.adapters.toctre.TocTree instead.', + RemovedInSphinx20Warning) + return TocTree(self).get_toc_for(docname, builder) def get_toctree_for(self, docname, builder, collapse, **kwds): # type: (unicode, Builder, bool, Any) -> addnodes.toctree """Return the global TOC nodetree.""" - return self.toctree.get_toctree_for(docname, builder, collapse, **kwds) # type: ignore + warnings.warn('env.get_toctree_for() is deprecated. ' + 'Use sphinx.environment.adapters.toctre.TocTree instead.', + RemovedInSphinx20Warning) + return TocTree(self).get_toctree_for(docname, builder, collapse, **kwds) def get_domain(self, domainname): # type: (unicode) -> Domain @@ -897,9 +907,9 @@ class BuildEnvironment(object): # now, resolve all toctree nodes for toctreenode in doctree.traverse(addnodes.toctree): - result = self.resolve_toctree(docname, builder, toctreenode, - prune=prune_toctrees, - includehidden=includehidden) + result = TocTree(self).resolve(docname, builder, toctreenode, + prune=prune_toctrees, + includehidden=includehidden) if result is None: toctreenode.replace_self([]) else: @@ -921,9 +931,9 @@ class BuildEnvironment(object): If *collapse* is True, all branches not containing docname will be collapsed. """ - return self.toctree.resolve_toctree(docname, builder, toctree, prune, # type: ignore - maxdepth, titles_only, collapse, - includehidden) + return TocTree(self).resolve(docname, builder, toctree, prune, + maxdepth, titles_only, collapse, + includehidden) def resolve_references(self, doctree, fromdocname, builder): # type: (nodes.Node, unicode, Builder) -> None diff --git a/sphinx/environment/adapters/__init__.py b/sphinx/environment/adapters/__init__.py new file mode 100644 index 000000000..12a6fa490 --- /dev/null +++ b/sphinx/environment/adapters/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" + sphinx.environment.adapters + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Sphinx environment adapters + + :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py new file mode 100644 index 000000000..1ab3e229f --- /dev/null +++ b/sphinx/environment/adapters/toctree.py @@ -0,0 +1,324 @@ +# -*- coding: utf-8 -*- +""" + sphinx.environment.adapters.toctree + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Toctree adapter for sphinx.environment. + + :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +from six import iteritems + +from docutils import nodes + +from sphinx import addnodes +from sphinx.util import url_re, logging +from sphinx.util.nodes import clean_astext, process_only_nodes + +if False: + # For type annotation + from typing import Any # NOQA + from sphinx.builders import Builder # NOQA + from sphinx.environment import BuildEnvironment # NOQA + +logger = logging.getLogger(__name__) + + +class TocTree(object): + def __init__(self, env): + # type: (BuildEnvironment) -> None + self.env = env + + def note(self, docname, toctreenode): + # type: (unicode, addnodes.toctree) -> None + """Note a TOC tree directive in a document and gather information about + file relations from it. + """ + if toctreenode['glob']: + self.env.glob_toctrees.add(docname) + if toctreenode.get('numbered'): + self.env.numbered_toctrees.add(docname) + includefiles = toctreenode['includefiles'] + for includefile in includefiles: + # note that if the included file is rebuilt, this one must be + # too (since the TOC of the included file could have changed) + self.env.files_to_rebuild.setdefault(includefile, set()).add(docname) + self.env.toctree_includes.setdefault(docname, []).extend(includefiles) + + def resolve(self, docname, builder, toctree, prune=True, maxdepth=0, + titles_only=False, collapse=False, includehidden=False): + # type: (unicode, Builder, addnodes.toctree, bool, int, bool, bool, bool) -> nodes.Node + """Resolve a *toctree* node into individual bullet lists with titles + as items, returning None (if no containing titles are found) or + a new node. + + If *prune* is True, the tree is pruned to *maxdepth*, or if that is 0, + 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) and not includehidden: + return None + + # For reading the following two helper function, it is useful to keep + # in mind the node structure of a toctree (using HTML-like node names + # for brevity): + # + # + # + # The transformation is made in two passes in order to avoid + # interactions between marking and pruning the tree (see bug #1046). + + toctree_ancestors = self.get_toctree_ancestors(docname) + + def _toctree_add_classes(node, depth): + """Add 'toctree-l%d' and 'current' classes to the toctree.""" + for subnode in node.children: + if isinstance(subnode, (addnodes.compact_paragraph, + nodes.list_item)): + # for

and

  • , indicate the depth level and recurse + subnode['classes'].append('toctree-l%d' % (depth - 1)) + _toctree_add_classes(subnode, depth) + elif isinstance(subnode, nodes.bullet_list): + # for