docs: add bootstrap extension

To get Sphinx and Bootstrap to work well together, we need to massage
the output from Sphinx a bit. This adds an extension to do such changes,
based on work from here:

https://github.com/pydata/pydata-sphinx-theme

...However, because we don't ship as an external theme, we can't just do
things as a part of __init__.py, so instead we register an extension
that does the heavy lifting for us.

Reviewed-by: Eric Engestrom <eric@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8399>
This commit is contained in:
Erik Faye-Lund 2021-01-06 14:00:52 +01:00 committed by Marge Bot
parent 7da0482636
commit f72033bb70

108
docs/_exts/bootstrap.py Normal file
View file

@ -0,0 +1,108 @@
# BSD 3-Clause License
#
# Copyright (c) 2018, pandas
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Based on https://github.com/pydata/pydata-sphinx-theme
from packaging.version import Version
from docutils import nodes
import sphinx
from sphinx.ext.autosummary import autosummary_table
import types
class BootstrapHTML5TranslatorMixin:
def __init__(self, *args, **kwds):
super().__init__(*args, **kwds)
self.settings.table_style = "table"
def starttag(self, *args, **kwargs):
"""ensure an aria-level is set for any heading role"""
if kwargs.get("ROLE") == "heading" and "ARIA-LEVEL" not in kwargs:
kwargs["ARIA-LEVEL"] = "2"
return super().starttag(*args, **kwargs)
def visit_table(self, node):
# init the attributes
atts = {}
if Version(sphinx.__version__) < Version("4.3"):
self._table_row_index = 0
else:
self._table_row_indices.append(0)
# get the classes
classes = [cls.strip(" \t\n") for cls in self.settings.table_style.split(",")]
# we're looking at the 'real_table', which is wrapped by an autosummary
if isinstance(node.parent, autosummary_table):
classes += ["autosummary"]
# add the width if set in a style attribute
if "width" in node:
atts["style"] = f'width: {node["width"]}'
# add specific class if align is set
if "align" in node:
classes.append(f'table-{node["align"]}')
tag = self.starttag(node, "table", CLASS=" ".join(classes), **atts)
self.body.append(tag)
def setup_translators(app):
if not app.registry.translators.items():
translator = types.new_class(
"BootstrapHTML5Translator",
(
BootstrapHTML5TranslatorMixin,
app.builder.default_translator_class,
),
{},
)
app.set_translator(app.builder.name, translator, override=True)
else:
for name, klass in app.registry.translators.items():
if app.builder.format != "html":
# Skip translators that are not HTML
continue
translator = types.new_class(
"BootstrapHTML5Translator",
(
BootstrapHTML5TranslatorMixin,
klass,
),
{},
)
app.set_translator(name, translator, override=True)
def setup(app):
app.connect("builder-inited", setup_translators)