Files
openmm/docs-source/sphinx/continuous.py
Josh A. Mitchell f5166695cb Reorganise documentation (#3165)
* Break user guide into parts

* Break up file I missed

* Add basic .gitignore to suit out-of-tree builds in build, build1, build2 ... build9

* Small changes to autonumber.py for doc compilation

This is a small change designed not to fix the incorrect logic of
autonumber.py, but just to get the docs compiling. While assigning
numbers, the code now just ignores the autonumber_by_chapter
setting for a particular object if it can't find the appropriate
section in section_numbers. This is a temporary fix!

* Include part and chapter in autonumbered objects

* Fix autonumber.py to correctly reference autonumber roles in file-level sections

* Unify and simplify styling across documentation

* Break dev docs down into individual chapter-files

* Correct absolute links to relative

* Disable browser suggestions for lunrsearch box in API docs

* Remove part name from chapter 2.1

* Rename ambiguous 'Home' link to OpenMM.org

* Typo

* Minor fixes and reversions

Reverts some changes I had made and later thought better of,
and fixes some recurring typos across the documentation.

* Number developers guide chapters

* Fix responsiveness

* Remove header.rst and center captions

* Add a level of depth to main TOC and styling to accomodate

* Add third level to Part-level TOCs

* Use :numref: instead of :ref: to number links to sections

* Continuously number chapters in user guide

* navbar links to other docs relative, not absolute

* Improve navbar spacing with new template

* Fix sidebar while allowing it to scroll

* Hard -> Soft links for navigation.html template

* Add navigation.html template to cmakelists

* Add another level of .. to relative links

* Fix flex on C++ and remove layer of ..
2021-07-15 17:34:23 -07:00

158 lines
6.1 KiB
Python

""" continuous.py
A Sphinx extension to number chapters continuously across toctrees
Derived from sphinx-multitoc-numbering with thanks
https://github.com/executablebooks/sphinx-multitoc-numbering"""
from typing import Dict, Iterable, List, Set, Tuple, cast
from docutils import nodes
from docutils.nodes import Element
from sphinx import addnodes
from sphinx.environment import BuildEnvironment
from sphinx.environment.collectors.toctree import TocTreeCollector
from sphinx.locale import __
from sphinx.util import logging, url_re
logger = logging.getLogger(__name__)
def find_numbered_toctree_nodes(
env, iterable: Iterable[addnodes.toctree]
) -> Tuple[Set[str], List[addnodes.toctree]]:
"""Recursively walk the toctree, recording docnames and numbered nodes"""
toctree_nodes = []
assigned = set([])
for node in iterable:
if node["numbered"]:
toctree_nodes.append(node)
else:
for _, ref in node["entries"]:
assigned.add(ref)
doctree = env.get_doctree(ref)
inner_toctree_nodes = doctree.traverse(addnodes.toctree)
# RECURSION
# Base case: All nodes in inner_toctree_nodes are numbered,
# or inner_toctree_nodes is empty
# This'll happen eventually as long as the toctree is acyclic,
# as we are guaranteed to get a level deeper with every call.
# Sphinx already requires an acyclic toctree, so we're fine.
inner_assigned, inner_toctree_nodes = find_numbered_toctree_nodes(
env, inner_toctree_nodes
)
assigned.update(inner_assigned)
toctree_nodes.extend(inner_toctree_nodes)
return assigned, toctree_nodes
def get_toctree_nodes(env: BuildEnvironment) -> Tuple[Set[str], List[addnodes.toctree]]:
"""Get all numbered toctrees, in the order they appear in the document
Walks the entire toctree, starting with the index, and records numbered
toctrees as it finds them."""
## Get the toctrees in the correct order
# Sphinx toctrees always start at index
index_doctree = env.get_doctree("index")
index_toctree_nodes = index_doctree.traverse(addnodes.toctree)
assigned, toctree_nodes = find_numbered_toctree_nodes(env, index_toctree_nodes)
assigned.add("index")
if assigned != env.numbered_toctrees:
logger.warning(
"Couldn't number some toctrees: {env.numbered_toctrees - assigned}",
type="toc",
)
return assigned, toctree_nodes
def assign_section_numbers(self, env: BuildEnvironment) -> List[str]:
"""Assign a section number to each heading under a numbered toctree."""
# a list of all docnames whose section numbers changed
rewrite_needed = []
old_secnumbers = env.toc_secnumbers
env.toc_secnumbers = {}
self.last_chapter_number = 0
assigned, toctree_nodes = get_toctree_nodes(env)
def _walk_toc(
node: Element, secnums: Dict, depth: int, titlenode: nodes.title = None
) -> None:
# titlenode is the title of the document, it will get assigned a
# secnumber too, so that it shows up in next/prev/parent rellinks
for subnode in node.children:
if isinstance(subnode, nodes.bullet_list):
numstack.append(0)
_walk_toc(subnode, secnums, depth - 1, titlenode)
numstack.pop()
titlenode = None
elif isinstance(subnode, nodes.list_item):
_walk_toc(subnode, secnums, depth, titlenode)
titlenode = None
elif isinstance(subnode, addnodes.only):
# at this stage we don't know yet which sections are going
# to be included; just include all of them, even if it leads
# to gaps in the numbering
_walk_toc(subnode, secnums, depth, titlenode)
titlenode = None
elif isinstance(subnode, addnodes.compact_paragraph):
numstack[-1] += 1
reference = cast(nodes.reference, subnode[0])
# if a new chapter is encountered increment the chapter number
if len(numstack) == 1:
self.last_chapter_number += 1
if depth > 0:
number = list(numstack)
secnums[reference["anchorname"]] = tuple(numstack)
else:
number = None
secnums[reference["anchorname"]] = None
reference["secnumber"] = number
if titlenode:
titlenode["secnumber"] = number
titlenode = None
elif isinstance(subnode, addnodes.toctree):
_walk_toctree(subnode, depth)
def _walk_toctree(toctreenode: addnodes.toctree, depth: int) -> None:
if depth == 0:
return
for _, ref in toctreenode["entries"]:
if url_re.match(ref) or ref == "self":
# don't mess with those
continue
elif ref in assigned:
logger.warning(
__(
"%s is already assigned section numbers (nested numbered toctree?)"
),
ref,
location=toctreenode,
type="toc",
subtype="secnum",
)
elif ref in env.tocs:
secnums = {} # type: Dict[str, Tuple[int, ...]]
env.toc_secnumbers[ref] = secnums
assigned.add(ref)
_walk_toc(env.tocs[ref], secnums, depth, env.titles.get(ref))
if secnums != old_secnumbers.get(ref):
rewrite_needed.append(ref)
for toctreenode in toctree_nodes:
depth = toctreenode.get("numbered", 0)
if depth:
# every numbered toctree continues the numbering
numstack = [self.last_chapter_number]
_walk_toctree(toctreenode, depth)
return rewrite_needed
def setup(app):
TocTreeCollector.assign_section_numbers = assign_section_numbers