Theming

This collection of pages uses a modified version of the Sphinx haiku theme. Thankfully, it was relatively easy to modify and does not involve copying the whole theme.

Extensions

Disabling Searching for Particular Directories

Sometimes we don’t want to leak data via search pages. This is a very hackish extension that directly modifies the HTML builder object, since there does not appear to be a better way.

import sphinx
import types

def modBuilder(app):
  try:
    old_index_page = app.builder.index_page
    def new_index_page(self, pagename, doctree, title):
      if (not pagename.startswith("secret/")) :
         old_index_page(pagename, doctree, title)
    app.builder.index_page  = types.MethodType(new_index_page, app.builder)
  except Exception:
    # Alternatively, don't do that and do this instead to disable
    # search functionality altogether.
    app.builder.search = False

def setup(app):
  app.connect('builder-inited', modBuilder)
  return {'version': "1", 'parallel_read_safe': True}

Separately, the secret/ path and _source/secret/ paths are protected by the web server itself so that unauthenticated clients may not read them; otherwise, there’d be little point!

Removing Document Title From Markup

The theme I am using places the title up top specially, but it also remains in the document tree and so gets rendered first thing. That looks bad. This extension surgically removes the document title from pages without altering the sphinx metadata and then promotes the title’s sibling nodes to take the place of the former page container.

import sphinx
from docutils import nodes

def munge_doc_tree(app, doctree, docname):
    sec1i = doctree.first_child_matching_class(nodes.section)
    if sec1i is None: return

    sec1n = doctree[sec1i]
    if sec1n is None: return

    ts1i = sec1n.first_child_matching_class(nodes.title)
    if ts1i is None: return

    sec1n.pop(ts1i)

    sec1n.replace_self(sec1n.children)

def setup(app):
    app.connect('doctree-resolved', munge_doc_tree)
    return {'version': "1", 'parallel_read_safe': True}

Hacking Generality Into Toctrees

Despite it being a long-standing feature request (https://github.com/sphinx-doc/sphinx/issues/701) with a few PRs taking a stab at it (some from yours truly), sphinx core is hesitant to extend the semantics of toctrees or muck about in their core. So, instead, I present the following truly terrible workaround.

This is an extension which adds a toctreeish directive that manually parses the toctree entries and fakes the references that sphinx would otherwise generate. (It then causes Sphinx to perceive a hidden toctree so that the rest of the deep, internal document cluster and toctree resolution magic happens.) The key feature is that entries that begin with an underscore followed by space will have the rest of their literal text parsed by docutils and then inserted into the list. It is in use on this site in Formal Writings, which contains (roughly)

.. toctreeish::

   foo
   bar
   _ :ref:`baz title <baz#ref>`

It’s gross, it’s terrible, but it means I don’t have to carry around a patched Sphinx or link to the wrong place in my list of publications. Hooray?

import re
from typing import List

from docutils import nodes
from docutils.nodes import Node
from docutils.statemachine import StringList, ViewList

import sphinx
from sphinx import addnodes
from sphinx.directives.other import TocTree

class TocTreeish(TocTree) :

    def run(self) -> List[Node]:
        assert self.options.get("hidden",False) == False
        assert self.options.get("maxdepth",1) == 1

        rootln = nodes.bullet_list()

        delme = []
        for entry in self.content:
            node = addnodes.compact_paragraph()

            if re.search(r"\s", entry):
              if entry.startswith("_ "):
                # Raw syntax: parse...
                tmp = nodes.paragraph()
                self.state.nested_parse(ViewList([entry[2:]]), 0, tmp)

                # ... rip out the parsed thing into a compact paragraph...
                node += tmp.children[0].children

                # ... and prevent the real toctree from seeing it
                delme += [ entry ]
              else:
                assert False, "TocTreeish doesn't understand spaced things"
            elif entry == "self":
                assert False, "TocTreeish doesn't do 'self'"
            else:
                # Single word, must be a doc xref.  Fake one up!
                pxr = addnodes.pending_xref(entry, reftype='doc',
                        refdomain='std', refexplicit=False, reftarget=entry)
                pxr += nodes.inline('', entry, classes="xref std std-doc")
                node += pxr

            rootln.children += nodes.bullet_list('', nodes.list_item('', node))

        for d in delme:
            self.content.remove(d)

        self.options["hidden"] = True
        res = super().run()

        # Push our list into the wrapper that still gets generated despite
        # setting the toctree to hidden.
        wrappernode = res[-1]
        wrappernode.append(rootln)

        return res

def setup(app):
    app.add_directive("toctreeish", TocTreeish)
    return {'version': "1", 'parallel_read_safe': True}

Bibliographic Management

The entire Formal Writings section of this site is generated from a bib file, a series of small ReStructredText inputs, and the downloads themselves. The bulk of the work is done by this TCL script. The two parameter files for bibtool are: