Add versioned book on readthedocs.org

This PR adds the file `.readthedocs.yaml`, which is used by
readthedocs.org to generate the book on their servers. RTD can be used
easily host docs for every rinja version, so users can explore how to
use the current stable version, the current HEAD, and an older version.

For older versions than the current PR, the books won't be built,
because we did not provided the needed `.readthedocs.yaml`.

Also an `index.hbs` template skeleton is dynamically generated to made
mdbook and RTD work better together. (Only the left sidebar was changed,
but you have to override the whole file to make any changes.)
This commit is contained in:
René Kijewski 2024-05-10 13:37:22 +02:00
parent 621b1b69cf
commit a0f6ce530b
2 changed files with 103 additions and 0 deletions

1
book/theme/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*

102
book/update-theme.py Executable file
View File

@ -0,0 +1,102 @@
#!/usr/bin/env python3
from base64 import b64decode
from contextlib import closing
from http.client import HTTPSConnection
from io import StringIO
from json import load
INDEX_HBS_DOMAIN = "api.github.com"
INDEX_HBS_PORT = 443
INDEX_HBS_PROTO = "GET"
INDEX_HBS_PATH = "/repos/rust-lang/mdBook/contents/src/theme/index.hbs"
INDEX_HBS_HEADERS = {
"user-agent": "Update index.hbs for +https://github.com/rinja-rs/rinja",
}
SIDEBAR_STYLE = 'style="display:flex; flex-direction:column"'
SCROLLBOX_END = r"""
<div id="ethical-ad-placement" data-ea-publisher="readthedocs" data-ea-type="image"></div>
<readthedocs-flyout></readthedocs-flyout>
"""
TOC_START = '<div style="flex:1">'
TOC_END = "</div>"
SIDEBAR_END = r"""
<script>
document.addEventListener("DOMContentLoaded", function insertStyle () {
const elem = customElements.get("readthedocs-flyout");
if (elem) {
elem.styles.insertRule(`
.container {
position: unset !important;
max-width: unset !important;
width: unset !important;
height: unset !important;
max-height: unset !important;
}
`);
elem.styles.insertRule(`
dl:has(#flyout-search-form) {
display: none !important;
}
`);
} else {
setTimeout(insertStyle, 50);
}
});
</script>
"""
def main():
with closing(HTTPSConnection(INDEX_HBS_DOMAIN, INDEX_HBS_PORT)) as conn:
conn.request(INDEX_HBS_PROTO, INDEX_HBS_PATH, None, INDEX_HBS_HEADERS)
res = conn.getresponse()
if res.status != 200:
raise Exception(f"Status={res.status!r}")
data = load(res)
if data["encoding"] != "base64":
raise Exception(f'Encoding={data["encoding"]!r}')
input_f = StringIO(str(b64decode(data["content"]), "UTF-8"))
output_f = StringIO()
_, revision = data["git_url"].rsplit("/", 1)
print("{{!-- Source revision:", revision, "--}}", file=output_f)
state = "before-sidebar"
for line in input_f:
match state:
case "before-sidebar" if '<nav id="sidebar"' in line:
state = "before-scrollbox"
case "before-scrollbox" if '<div class="sidebar-scrollbox"' in line:
line = line[:-2] # remove '>\n'
line = f"{line} {SIDEBAR_STYLE}>\n"
state = "before-toc"
case "before-toc" if "{{#toc}}{{/toc}}" in line:
indent = line[: len(line) - len(line.lstrip())]
line = f"{indent}{TOC_START}{line.strip()}{TOC_END}\n"
state = "in-scrollbox"
case "in-scrollbox" if line.strip() == "</div>":
indent = line[: len(line) - len(line.lstrip())]
for s in SCROLLBOX_END.splitlines():
if s:
print(indent, s, sep=" ", file=output_f)
state = "in-sidebar"
case "in-sidebar" if line.strip() == "</nav>":
indent = line[: len(line) - len(line.lstrip())]
for s in SIDEBAR_END.splitlines():
if s:
print(indent, s, sep=" ", file=output_f)
state = "after-sidebar"
output_f.write(line)
output_f.seek(0, 0)
with open("./theme/index.hbs", "wt") as f:
print(output_f.read(), end="", file=f)
if __name__ == "__main__":
main()