Skip to content
This repository was archived by the owner on Jan 27, 2025. It is now read-only.

Commit 58fc695

Browse files
committed
import the appendices extension into the repo
1 parent 44dc5f9 commit 58fc695

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

exts/ferrocene_appendices.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# SPDX-License-Identifier: MIT OR Apache-2.0
2+
# SPDX-FileCopyrightText: Ferrous Systems and AdaCore
3+
4+
from docutils import nodes
5+
from sphinx import addnodes as sphinxnodes
6+
from sphinx.directives.other import TocTree
7+
from sphinx.environment.collectors.toctree import TocTreeCollector
8+
import gc
9+
10+
11+
class AppendicesDirective(TocTree):
12+
def run(self):
13+
result = super().run()
14+
15+
def compat_check(condition):
16+
if not condition:
17+
raise RuntimeError(
18+
"bug: the toctree Sphinx directive used by appendix emitted "
19+
"unexpected nodes, please update the extension to handle that"
20+
)
21+
22+
# We're modifying the result of Sphinx's builtin TocTree directive, so
23+
# ensure it contains what we expect.
24+
compat_check(isinstance(result, list))
25+
compat_check(len(result) == 1)
26+
compat_check(isinstance(result[0], nodes.compound))
27+
compat_check(len(result[0].children) == 1)
28+
compat_check(isinstance(result[0].children[0], sphinxnodes.toctree))
29+
30+
# Mark this toctree as containing appendices, so that the environment
31+
# collector can distinguish it from normal toctrees.
32+
result[0].children[0]["are_appendices"] = True
33+
34+
return result
35+
36+
37+
# To ensure the minimum disruption possible, to update section numbers we're
38+
# replacing the EnvironmentCollector responsible for assigning section numbers.
39+
#
40+
# We let the builtin Sphinx logic assign section numbers, and as soon as it
41+
# finishes we go over the sections and replace the first number with a letter.
42+
# This ensures the rest of the build always sees the correct ID for sections.
43+
class TocTreeCollectorWithAppendices(TocTreeCollector):
44+
def assign_section_numbers(self, env):
45+
result = super().assign_section_numbers(env)
46+
47+
for docname in env.numbered_toctrees:
48+
doctree = env.get_doctree(docname)
49+
for toctree in doctree.findall(sphinxnodes.toctree):
50+
self.__replace_toctree(env, toctree)
51+
52+
return result
53+
54+
def __replace_toctree(self, env, toctree):
55+
within_appendices = "are_appendices" in toctree
56+
for _, ref in toctree["entries"]:
57+
if within_appendices:
58+
env.titles[ref]["secnumber"] = make_letter(env.titles[ref]["secnumber"])
59+
if ref in env.tocs:
60+
self.__replace_toc(env, ref, env.tocs[ref], within_appendices)
61+
62+
def __replace_toc(self, env, ref, node, within_appendices):
63+
if within_appendices and isinstance(node, nodes.reference):
64+
fixed_number = make_letter(node["secnumber"])
65+
node["secnumber"] = fixed_number
66+
env.toc_secnumbers[ref][node["anchorname"]] = fixed_number
67+
68+
elif isinstance(node, sphinxnodes.toctree):
69+
self.__replace_toctree(env, node)
70+
71+
else:
72+
for child in node.children:
73+
self.__replace_toc(env, ref, child, within_appendices)
74+
75+
76+
def make_letter(section_number):
77+
if not section_number:
78+
return section_number
79+
if section_number[0] > 26:
80+
raise RuntimeError("more than 26 appendices are not supported")
81+
82+
return (chr(ord("A") - 1 + section_number[0]), *section_number[1:])
83+
84+
85+
# This extension needs to replace the builtin TocTreeCollector, so it's safer
86+
# to disable it. That'll avoid two TocTreeCollectors running in the build.
87+
def disable_builtin_toctree_collector(app):
88+
for obj in gc.get_objects():
89+
if isinstance(obj, TocTreeCollector):
90+
obj.disable(app)
91+
92+
93+
def setup(app):
94+
app.add_directive("appendices", AppendicesDirective)
95+
96+
disable_builtin_toctree_collector(app)
97+
app.add_env_collector(TocTreeCollectorWithAppendices)
98+
99+
return {
100+
"version": "0",
101+
"parallel_read_safe": True,
102+
"parallel_write_safe": True,
103+
}

0 commit comments

Comments
 (0)