celshast 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- celshast/__init__.py +377 -0
- celshast/_demo_module.py +54 -0
- celshast/assets/scripts/celshast.js +175 -0
- celshast/assets/scripts/gumshoe-patched.js +466 -0
- celshast/assets/styles/_scaffold.sass +460 -0
- celshast/assets/styles/_shame.sass +12 -0
- celshast/assets/styles/base/_index.sass +4 -0
- celshast/assets/styles/base/_print.sass +43 -0
- celshast/assets/styles/base/_screen-readers.sass +13 -0
- celshast/assets/styles/base/_theme.sass +55 -0
- celshast/assets/styles/base/_typography.sass +93 -0
- celshast/assets/styles/celshast-extensions.sass +1 -0
- celshast/assets/styles/celshast.sass +9 -0
- celshast/assets/styles/components/_footer.sass +109 -0
- celshast/assets/styles/components/_index.sass +4 -0
- celshast/assets/styles/components/_search.sass +17 -0
- celshast/assets/styles/components/_sidebar.sass +231 -0
- celshast/assets/styles/components/_table_of_contents.sass +65 -0
- celshast/assets/styles/content/_admonitions.sass +77 -0
- celshast/assets/styles/content/_api.sass +96 -0
- celshast/assets/styles/content/_blocks.sass +7 -0
- celshast/assets/styles/content/_captions.sass +19 -0
- celshast/assets/styles/content/_code.sass +137 -0
- celshast/assets/styles/content/_footnotes.sass +45 -0
- celshast/assets/styles/content/_gui-labels.sass +8 -0
- celshast/assets/styles/content/_images.sass +37 -0
- celshast/assets/styles/content/_index.sass +16 -0
- celshast/assets/styles/content/_indexes.sass +12 -0
- celshast/assets/styles/content/_lists.sass +67 -0
- celshast/assets/styles/content/_math.sass +21 -0
- celshast/assets/styles/content/_misc.sass +53 -0
- celshast/assets/styles/content/_rubrics.sass +13 -0
- celshast/assets/styles/content/_sidebar.sass +28 -0
- celshast/assets/styles/content/_tables.sass +42 -0
- celshast/assets/styles/content/_target.sass +81 -0
- celshast/assets/styles/extensions/_copybutton.sass +45 -0
- celshast/assets/styles/extensions/_farama.sass +714 -0
- celshast/assets/styles/extensions/_index.sass +6 -0
- celshast/assets/styles/extensions/_readthedocs.sass +76 -0
- celshast/assets/styles/extensions/_sphinx-design.sass +51 -0
- celshast/assets/styles/extensions/_sphinx-inline-tabs.sass +18 -0
- celshast/assets/styles/extensions/_sphinx-panels.sass +18 -0
- celshast/assets/styles/variables/_admonitions.scss +48 -0
- celshast/assets/styles/variables/_colors.scss +192 -0
- celshast/assets/styles/variables/_fonts.scss +41 -0
- celshast/assets/styles/variables/_icons.scss +32 -0
- celshast/assets/styles/variables/_index.sass +8 -0
- celshast/assets/styles/variables/_layout.scss +9 -0
- celshast/assets/styles/variables/_spacing.scss +43 -0
- celshast/farama_directives.py +42 -0
- celshast/gen_tutorials.py +64 -0
- celshast/navigation.py +87 -0
- celshast/sphinxext.py +95 -0
- celshast/theme/celshast/base.html +483 -0
- celshast/theme/celshast/components/edit-this-page.html +26 -0
- celshast/theme/celshast/domainindex.html +51 -0
- celshast/theme/celshast/genindex.html +58 -0
- celshast/theme/celshast/globaltoc.html +4 -0
- celshast/theme/celshast/layout.html +16 -0
- celshast/theme/celshast/localtoc.html +4 -0
- celshast/theme/celshast/page.html +262 -0
- celshast/theme/celshast/partials/_head_css_variables.html +28 -0
- celshast/theme/celshast/partials/icons.html +61 -0
- celshast/theme/celshast/search.html +29 -0
- celshast/theme/celshast/sidebar/brand.html +31 -0
- celshast/theme/celshast/sidebar/donate.html +7 -0
- celshast/theme/celshast/sidebar/ethical-ads.html +10 -0
- celshast/theme/celshast/sidebar/navigation.html +3 -0
- celshast/theme/celshast/sidebar/rtd-versions.html +34 -0
- celshast/theme/celshast/sidebar/scroll-end.html +1 -0
- celshast/theme/celshast/sidebar/scroll-start.html +1 -0
- celshast/theme/celshast/sidebar/search.html +6 -0
- celshast/theme/celshast/sidebar/title.html +7 -0
- celshast/theme/celshast/sidebar/variant-selector.html +33 -0
- celshast/theme/celshast/static/.gitignore +7 -0
- celshast/theme/celshast/static/img/MAgent2-white.svg +131 -0
- celshast/theme/celshast/static/img/autorom-white.svg +112 -0
- celshast/theme/celshast/static/img/d4rl-white.svg +107 -0
- celshast/theme/celshast/static/img/farama-logo-header.svg +115 -0
- celshast/theme/celshast/static/img/farama_solid_white.svg +95 -0
- celshast/theme/celshast/static/img/gymnasium-white.svg +89 -0
- celshast/theme/celshast/static/img/gymrobotics-white.svg +165 -0
- celshast/theme/celshast/static/img/jumpy-white.svg +156 -0
- celshast/theme/celshast/static/img/kabuki-white.svg +160 -0
- celshast/theme/celshast/static/img/microrts-white.svg +179 -0
- celshast/theme/celshast/static/img/minigrid-white.svg +136 -0
- celshast/theme/celshast/static/img/miniworld-white.svg +184 -0
- celshast/theme/celshast/static/img/pettingzoo-white.svg +169 -0
- celshast/theme/celshast/static/img/procgen2-white.svg +151 -0
- celshast/theme/celshast/static/img/supersuit-white.svg +80 -0
- celshast/theme/celshast/static/img/tinyscaler-white.svg +123 -0
- celshast/theme/celshast/static/scripts/celshast-extensions.js +0 -0
- celshast/theme/celshast/static/scripts/celshast.js +3 -0
- celshast/theme/celshast/static/scripts/celshast.js.LICENSE.txt +7 -0
- celshast/theme/celshast/static/scripts/celshast.js.map +1 -0
- celshast/theme/celshast/static/styles/celshast-extensions.css +2 -0
- celshast/theme/celshast/static/styles/celshast-extensions.css.map +1 -0
- celshast/theme/celshast/static/styles/celshast.css +2 -0
- celshast/theme/celshast/static/styles/celshast.css.map +1 -0
- celshast/theme/celshast/static/versioning/versioning_menu.html +222 -0
- celshast/theme/celshast/theme.conf +35 -0
- celshast-0.0.1.dist-info/METADATA +518 -0
- celshast-0.0.1.dist-info/RECORD +106 -0
- celshast-0.0.1.dist-info/WHEEL +4 -0
- celshast-0.0.1.dist-info/entry_points.txt +2 -0
- celshast-0.0.1.dist-info/licenses/LICENSE +19 -0
celshast/__init__.py
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
"""A Farama Foundation Sphinx documentation theme based on Furo."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.0.1"
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
from functools import lru_cache
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any, Dict, Iterator, List, Optional
|
|
11
|
+
|
|
12
|
+
import sphinx.application
|
|
13
|
+
from docutils import nodes
|
|
14
|
+
from pygments.formatters import HtmlFormatter
|
|
15
|
+
from pygments.style import Style
|
|
16
|
+
from pygments.token import Text
|
|
17
|
+
from sphinx.builders.html import StandaloneHTMLBuilder
|
|
18
|
+
from sphinx.environment.adapters.toctree import TocTree
|
|
19
|
+
from sphinx.errors import ConfigError
|
|
20
|
+
from sphinx.highlighting import PygmentsBridge
|
|
21
|
+
from sphinx.transforms.post_transforms import SphinxPostTransform
|
|
22
|
+
|
|
23
|
+
from .farama_directives import FaramaProjectHeadingDirective, FaramaProjectLogoDirective
|
|
24
|
+
from .navigation import get_navigation_tree
|
|
25
|
+
|
|
26
|
+
THEME_PATH = (Path(__file__).parent / "theme" / "celshast").resolve()
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
# GLOBAL STATE
|
|
31
|
+
_KNOWN_STYLES_IN_USE: Dict[str, Optional[Style]] = {
|
|
32
|
+
"light": None,
|
|
33
|
+
"dark": None,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class WrapTableAndMathInAContainerTransform(SphinxPostTransform):
|
|
38
|
+
"""A Sphinx post-transform that wraps `table` and `div.math` in a container `div`.
|
|
39
|
+
|
|
40
|
+
This makes it possible to handle these overflowing the content-width, which is
|
|
41
|
+
necessary in a responsive theme.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
formats = ("html",)
|
|
45
|
+
default_priority = 500
|
|
46
|
+
|
|
47
|
+
def run(self, **kwargs: Any) -> None:
|
|
48
|
+
"""Perform the post-transform on `self.document`."""
|
|
49
|
+
get_nodes = (
|
|
50
|
+
self.document.findall # docutils 0.18+
|
|
51
|
+
if hasattr(self.document, "findall")
|
|
52
|
+
else self.document.traverse # docutils <= 0.17.x
|
|
53
|
+
)
|
|
54
|
+
for node in list(get_nodes(nodes.table)):
|
|
55
|
+
new_node = nodes.container(classes=["table-wrapper"])
|
|
56
|
+
new_node.update_all_atts(node)
|
|
57
|
+
node.parent.replace(node, new_node)
|
|
58
|
+
new_node.append(node)
|
|
59
|
+
|
|
60
|
+
for node in list(get_nodes(nodes.math_block)):
|
|
61
|
+
new_node = nodes.container(classes=["math-wrapper"])
|
|
62
|
+
new_node.update_all_atts(node)
|
|
63
|
+
node.parent.replace(node, new_node)
|
|
64
|
+
new_node.append(node)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def has_not_enough_items_to_show_toc(
|
|
68
|
+
builder: StandaloneHTMLBuilder, docname: str
|
|
69
|
+
) -> bool:
|
|
70
|
+
"""Check if the toc has one or fewer items."""
|
|
71
|
+
assert builder.env
|
|
72
|
+
|
|
73
|
+
toctree = TocTree(builder.env).get_toc_for(docname, builder)
|
|
74
|
+
try:
|
|
75
|
+
self_toctree = toctree[0][1]
|
|
76
|
+
except IndexError:
|
|
77
|
+
val = True
|
|
78
|
+
else:
|
|
79
|
+
# There's only the page's own toctree in there.
|
|
80
|
+
val = len(self_toctree) == 1 and self_toctree[0].tagname == "toctree"
|
|
81
|
+
return val
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_pygments_style_colors(
|
|
85
|
+
style: Style, *, fallbacks: Dict[str, str]
|
|
86
|
+
) -> Dict[str, str]:
|
|
87
|
+
"""Get background/foreground colors for given pygments style."""
|
|
88
|
+
background = style.background_color
|
|
89
|
+
text_colors = style.style_for_token(Text)
|
|
90
|
+
foreground = text_colors["color"]
|
|
91
|
+
|
|
92
|
+
if not background:
|
|
93
|
+
background = fallbacks["background"]
|
|
94
|
+
|
|
95
|
+
if not foreground:
|
|
96
|
+
foreground = fallbacks["foreground"]
|
|
97
|
+
else:
|
|
98
|
+
foreground = f"#{foreground}"
|
|
99
|
+
|
|
100
|
+
return {"background": background, "foreground": foreground}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@lru_cache(maxsize=2)
|
|
104
|
+
def get_colors_for_codeblocks(
|
|
105
|
+
highlighter: PygmentsBridge, *, fg: str, bg: str
|
|
106
|
+
) -> Dict[str, str]:
|
|
107
|
+
"""Get background/foreground colors for given pygments style."""
|
|
108
|
+
return get_pygments_style_colors(
|
|
109
|
+
highlighter.formatter_args["style"],
|
|
110
|
+
fallbacks={
|
|
111
|
+
"foreground": fg,
|
|
112
|
+
"background": bg,
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _compute_navigation_tree(context: Dict[str, Any]) -> str:
|
|
118
|
+
# The navigation tree, generated from the sphinx-provided ToC tree.
|
|
119
|
+
if "toctree" in context:
|
|
120
|
+
toctree = context["toctree"]
|
|
121
|
+
toctree_html = toctree(
|
|
122
|
+
collapse=False,
|
|
123
|
+
titles_only=True,
|
|
124
|
+
maxdepth=-1,
|
|
125
|
+
includehidden=True,
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
toctree_html = ""
|
|
129
|
+
|
|
130
|
+
return get_navigation_tree(toctree_html)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _compute_hide_toc(
|
|
134
|
+
context: Dict[str, Any],
|
|
135
|
+
*,
|
|
136
|
+
builder: StandaloneHTMLBuilder,
|
|
137
|
+
docname: str,
|
|
138
|
+
) -> bool:
|
|
139
|
+
# Should the table of contents be hidden?
|
|
140
|
+
file_meta = context.get("meta", None) or {}
|
|
141
|
+
if "hide-toc" in file_meta:
|
|
142
|
+
return True
|
|
143
|
+
elif "toc" not in context:
|
|
144
|
+
return True
|
|
145
|
+
elif not context["toc"]:
|
|
146
|
+
return True
|
|
147
|
+
|
|
148
|
+
return has_not_enough_items_to_show_toc(builder, docname)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@lru_cache(maxsize=None)
|
|
152
|
+
def _asset_hash(path: str) -> str:
|
|
153
|
+
"""Append a `?digest=` to an url based on the file content."""
|
|
154
|
+
full_path = THEME_PATH / "static" / path
|
|
155
|
+
digest = hashlib.sha1(full_path.read_bytes()).hexdigest()
|
|
156
|
+
|
|
157
|
+
return f"_static/{path}?digest={digest}"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _add_asset_hashes(static: List[str], add_digest_to: List[str]) -> None:
|
|
161
|
+
if sphinx.version_info >= (7, 1):
|
|
162
|
+
# https://github.com/sphinx-doc/sphinx/pull/11415 added the relevant
|
|
163
|
+
# functionality to Sphinx, so we don't need to do anything.
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
for asset in add_digest_to:
|
|
167
|
+
index = static.index("_static/" + asset)
|
|
168
|
+
static[index].filename = _asset_hash(asset) # type: ignore
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _html_page_context(
|
|
172
|
+
app: sphinx.application.Sphinx,
|
|
173
|
+
pagename: str,
|
|
174
|
+
templatename: str,
|
|
175
|
+
context: Dict[str, Any],
|
|
176
|
+
doctree: Any,
|
|
177
|
+
) -> None:
|
|
178
|
+
if "css_files" in context:
|
|
179
|
+
if "_static/styles/celshast.css" not in [
|
|
180
|
+
c.filename.split("?")[0] for c in context["css_files"]
|
|
181
|
+
]:
|
|
182
|
+
raise ConfigError(
|
|
183
|
+
"This documentation is not using `celshast.css` as the stylesheet. "
|
|
184
|
+
"If you have set `html_style` in your conf.py file, remove it."
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
_add_asset_hashes(
|
|
188
|
+
context["css_files"],
|
|
189
|
+
["styles/celshast.css", "styles/celshast-extensions.css"],
|
|
190
|
+
)
|
|
191
|
+
if "scripts" in context:
|
|
192
|
+
_add_asset_hashes(
|
|
193
|
+
context["scripts"],
|
|
194
|
+
["scripts/celshast.js"],
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
# Basic constants
|
|
198
|
+
context["celshast_version"] = __version__
|
|
199
|
+
|
|
200
|
+
# Values computed from page-level context.
|
|
201
|
+
context["celshast_navigation_tree"] = _compute_navigation_tree(context)
|
|
202
|
+
context["celshast_hide_toc"] = _compute_hide_toc(
|
|
203
|
+
context, builder=app.builder, docname=pagename
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Inject information about styles
|
|
207
|
+
context["celshast_pygments"] = {
|
|
208
|
+
"light": get_pygments_style_colors(
|
|
209
|
+
_KNOWN_STYLES_IN_USE["light"],
|
|
210
|
+
fallbacks=dict(
|
|
211
|
+
foreground="black",
|
|
212
|
+
background="white",
|
|
213
|
+
),
|
|
214
|
+
),
|
|
215
|
+
"dark": get_pygments_style_colors(
|
|
216
|
+
_KNOWN_STYLES_IN_USE["dark"],
|
|
217
|
+
fallbacks=dict(
|
|
218
|
+
foreground="white",
|
|
219
|
+
background="black",
|
|
220
|
+
),
|
|
221
|
+
),
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
# Base url
|
|
225
|
+
context["html_baseurl"] = app.config.html_baseurl
|
|
226
|
+
|
|
227
|
+
# Projects Menu
|
|
228
|
+
context["farama_projects_api"] = "https://farama.org/api/projects.json"
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _builder_inited(app: sphinx.application.Sphinx) -> None:
|
|
232
|
+
if "celshast" in app.config.extensions:
|
|
233
|
+
raise ConfigError(
|
|
234
|
+
"Did you list 'celshast' in the `extensions` in conf.py? "
|
|
235
|
+
"If so, please remove it. Celshast does not work with non-HTML builders "
|
|
236
|
+
"and specifying it as an `html_theme` is sufficient."
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
if not isinstance(app.builder, StandaloneHTMLBuilder) or app.builder.name not in {
|
|
240
|
+
"html",
|
|
241
|
+
"dirhtml",
|
|
242
|
+
}:
|
|
243
|
+
raise ConfigError(
|
|
244
|
+
"Celshast is being used as an extension in a non-HTML build. "
|
|
245
|
+
"This should not happen."
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Our JS file needs to be loaded as soon as possible.
|
|
249
|
+
app.add_js_file("scripts/celshast.js", priority=200)
|
|
250
|
+
|
|
251
|
+
# 500 is the default priority for extensions, we want this after this.
|
|
252
|
+
app.add_css_file("styles/celshast-extensions.css", priority=600)
|
|
253
|
+
|
|
254
|
+
# Add custom directives
|
|
255
|
+
app.add_directive("project-logo", FaramaProjectLogoDirective)
|
|
256
|
+
app.add_directive("project-heading", FaramaProjectHeadingDirective)
|
|
257
|
+
|
|
258
|
+
builder = app.builder
|
|
259
|
+
assert (
|
|
260
|
+
builder.highlighter is not None
|
|
261
|
+
), "there should be a default style known to Sphinx"
|
|
262
|
+
assert (
|
|
263
|
+
builder.dark_highlighter is None
|
|
264
|
+
), "this shouldn't be a dark style known to Sphinx"
|
|
265
|
+
update_known_styles_state(app)
|
|
266
|
+
|
|
267
|
+
def _update_default(key: str, *, new_default: Any) -> None:
|
|
268
|
+
app.config.values[key] = (new_default, *app.config.values[key][1:])
|
|
269
|
+
|
|
270
|
+
# Change the default permalinks icon
|
|
271
|
+
_update_default("html_permalinks_icon", new_default="#")
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def update_known_styles_state(app: sphinx.application.Sphinx) -> None:
|
|
275
|
+
"""Update a global store of known styles of this application."""
|
|
276
|
+
global _KNOWN_STYLES_IN_USE
|
|
277
|
+
|
|
278
|
+
_KNOWN_STYLES_IN_USE = {
|
|
279
|
+
"light": _get_light_style(app),
|
|
280
|
+
"dark": _get_dark_style(app),
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _get_light_style(app: sphinx.application.Sphinx) -> Style:
|
|
285
|
+
return app.builder.highlighter.formatter_args["style"]
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _get_dark_style(app: sphinx.application.Sphinx) -> Style:
|
|
289
|
+
dark_style = app.config.pygments_dark_style
|
|
290
|
+
return PygmentsBridge("html", dark_style).formatter_args["style"]
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _get_styles(formatter: HtmlFormatter, *, prefix: str) -> Iterator[str]:
|
|
294
|
+
"""Get styles out of a formatter, where everything has the correct prefix."""
|
|
295
|
+
for line in formatter.get_linenos_style_defs():
|
|
296
|
+
yield f"{prefix} {line}"
|
|
297
|
+
yield from formatter.get_background_style_defs(prefix)
|
|
298
|
+
yield from formatter.get_token_style_defs(prefix)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def get_pygments_stylesheet() -> str:
|
|
302
|
+
"""Generate the theme-specific pygments.css.
|
|
303
|
+
|
|
304
|
+
There is no way to tell Sphinx how the theme handles dark mode; at this time.
|
|
305
|
+
"""
|
|
306
|
+
light_formatter = PygmentsBridge.html_formatter(style=_KNOWN_STYLES_IN_USE["light"])
|
|
307
|
+
dark_formatter = PygmentsBridge.html_formatter(style=_KNOWN_STYLES_IN_USE["dark"])
|
|
308
|
+
|
|
309
|
+
lines: List[str] = []
|
|
310
|
+
|
|
311
|
+
lines.extend(_get_styles(light_formatter, prefix=".highlight"))
|
|
312
|
+
|
|
313
|
+
lines.append("@media not print {")
|
|
314
|
+
|
|
315
|
+
dark_prefix = 'body[data-theme="dark"] .highlight'
|
|
316
|
+
lines.extend(_get_styles(dark_formatter, prefix=dark_prefix))
|
|
317
|
+
|
|
318
|
+
not_light_prefix = 'body:not([data-theme="light"]) .highlight'
|
|
319
|
+
lines.append("@media (prefers-color-scheme: dark) {")
|
|
320
|
+
lines.extend(_get_styles(dark_formatter, prefix=not_light_prefix))
|
|
321
|
+
lines.append("}")
|
|
322
|
+
|
|
323
|
+
lines.append("}")
|
|
324
|
+
|
|
325
|
+
return "\n".join(lines)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# Yup, we overwrite the default pygments.css file, because it can't possibly respect
|
|
329
|
+
# the needs of this theme.
|
|
330
|
+
def _overwrite_pygments_css(
|
|
331
|
+
app: sphinx.application.Sphinx,
|
|
332
|
+
exception: Optional[Exception],
|
|
333
|
+
) -> None:
|
|
334
|
+
if exception is not None:
|
|
335
|
+
return
|
|
336
|
+
|
|
337
|
+
assert app.builder
|
|
338
|
+
with open(
|
|
339
|
+
os.path.join(app.builder.outdir, "_static", "pygments.css"),
|
|
340
|
+
"w",
|
|
341
|
+
encoding="utf-8",
|
|
342
|
+
) as f:
|
|
343
|
+
f.write(get_pygments_stylesheet())
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def setup(app: sphinx.application.Sphinx) -> Dict[str, Any]:
|
|
347
|
+
"""Entry point for sphinx theming."""
|
|
348
|
+
app.require_sphinx("6.0")
|
|
349
|
+
|
|
350
|
+
app.add_config_value(
|
|
351
|
+
"pygments_dark_style", default="native", rebuild="env", types=[str]
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Add default MyST extensions
|
|
355
|
+
if "myst_enable_extensions" in app.config:
|
|
356
|
+
if isinstance(app.config.myst_enable_extensions, list):
|
|
357
|
+
app.config.myst_enable_extensions.append("dollarmath")
|
|
358
|
+
elif isinstance(app.config.myst_enable_extensions, set):
|
|
359
|
+
app.config.myst_enable_extensions.add("dollarmath")
|
|
360
|
+
else:
|
|
361
|
+
raise ConfigError(
|
|
362
|
+
"myst_enable_extensions should be a list or set of strings."
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
app.add_html_theme("celshast", str(THEME_PATH))
|
|
366
|
+
|
|
367
|
+
app.add_post_transform(WrapTableAndMathInAContainerTransform)
|
|
368
|
+
|
|
369
|
+
app.connect("html-page-context", _html_page_context)
|
|
370
|
+
app.connect("builder-inited", _builder_inited)
|
|
371
|
+
app.connect("build-finished", _overwrite_pygments_css)
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
"parallel_read_safe": True,
|
|
375
|
+
"parallel_write_safe": True,
|
|
376
|
+
"version": __version__,
|
|
377
|
+
}
|
celshast/_demo_module.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright (c) 2021 Pradyun Gedam
|
|
2
|
+
# Licensed under the Open Software License version 3.0
|
|
3
|
+
# SPDX-License-Identifier: OSL-3.0
|
|
4
|
+
|
|
5
|
+
"""This is a demo module included in the docs in order to exercise autodoc."""
|
|
6
|
+
|
|
7
|
+
from typing import Optional, TextIO, Type, Union
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def show_warning(
|
|
11
|
+
message: Union[Warning, str],
|
|
12
|
+
category: Type[Warning],
|
|
13
|
+
filename: str,
|
|
14
|
+
lineno: int,
|
|
15
|
+
file: Optional[TextIO] = None,
|
|
16
|
+
line: Optional[str] = None,
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Show a warning to the end user.
|
|
19
|
+
|
|
20
|
+
.. code:: python
|
|
21
|
+
|
|
22
|
+
warnings.showwarning = show_warning
|
|
23
|
+
|
|
24
|
+
:param message: What you want to tell the user.
|
|
25
|
+
:param category: The type of warning.
|
|
26
|
+
:param filename: The file that the warning is for.
|
|
27
|
+
:param lineno: The line that the warning is for.
|
|
28
|
+
:param file: Where to write the warning.
|
|
29
|
+
:param line: line of source code to be included in the warning message
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class RandomNumberGenerator:
|
|
34
|
+
"""A random number generator."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, *, seed: int = 4) -> None:
|
|
37
|
+
"""Initialize."""
|
|
38
|
+
self._seed = 4
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def seed(self) -> int:
|
|
42
|
+
"""Get seed for random number generation.
|
|
43
|
+
|
|
44
|
+
.. seealso:: https://xkcd.com/221/
|
|
45
|
+
"""
|
|
46
|
+
return self._seed
|
|
47
|
+
|
|
48
|
+
def get_random_integer(self) -> int:
|
|
49
|
+
"""Return a random integer."""
|
|
50
|
+
return self.seed
|
|
51
|
+
|
|
52
|
+
def get_random_float(self) -> float:
|
|
53
|
+
"""Return a random float."""
|
|
54
|
+
return float(self.seed)
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import Gumshoe from "./gumshoe-patched.js";
|
|
2
|
+
|
|
3
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
4
|
+
// Scroll Handling
|
|
5
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
6
|
+
var tocScroll = null;
|
|
7
|
+
var header = null;
|
|
8
|
+
var lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
9
|
+
const GO_TO_TOP_OFFSET = 64;
|
|
10
|
+
|
|
11
|
+
// function scrollHandlerForHeader() {
|
|
12
|
+
// if (Math.floor(header.getBoundingClientRect().top) == 0) {
|
|
13
|
+
// header.classList.add("scrolled");
|
|
14
|
+
// } else {
|
|
15
|
+
// header.classList.remove("scrolled");
|
|
16
|
+
// }
|
|
17
|
+
// }
|
|
18
|
+
|
|
19
|
+
function scrollHandlerForBackToTop(positionY) {
|
|
20
|
+
if (positionY < GO_TO_TOP_OFFSET) {
|
|
21
|
+
document.documentElement.classList.remove("show-back-to-top");
|
|
22
|
+
} else {
|
|
23
|
+
if (positionY < lastScrollTop) {
|
|
24
|
+
document.documentElement.classList.add("show-back-to-top");
|
|
25
|
+
} else if (positionY > lastScrollTop) {
|
|
26
|
+
document.documentElement.classList.remove("show-back-to-top");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
lastScrollTop = positionY;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function scrollHandlerForTOC(positionY) {
|
|
33
|
+
if (tocScroll === null) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// top of page.
|
|
38
|
+
if (positionY == 0) {
|
|
39
|
+
tocScroll.scrollTo(0, 0);
|
|
40
|
+
} else if (
|
|
41
|
+
// bottom of page.
|
|
42
|
+
Math.ceil(positionY) >=
|
|
43
|
+
Math.floor(document.documentElement.scrollHeight - window.innerHeight)
|
|
44
|
+
) {
|
|
45
|
+
tocScroll.scrollTo(0, tocScroll.scrollHeight);
|
|
46
|
+
} else {
|
|
47
|
+
// somewhere in the middle.
|
|
48
|
+
const current = document.querySelector(".scroll-current");
|
|
49
|
+
if (current == null) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// https://github.com/pypa/pip/issues/9159 This breaks scroll behaviours.
|
|
54
|
+
// // scroll the currently "active" heading in toc, into view.
|
|
55
|
+
// const rect = current.getBoundingClientRect();
|
|
56
|
+
// if (0 > rect.top) {
|
|
57
|
+
// current.scrollIntoView(true); // the argument is "alignTop"
|
|
58
|
+
// } else if (rect.bottom > window.innerHeight) {
|
|
59
|
+
// current.scrollIntoView(false);
|
|
60
|
+
// }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function scrollHandler(positionY) {
|
|
65
|
+
// scrollHandlerForHeader();
|
|
66
|
+
scrollHandlerForBackToTop(positionY);
|
|
67
|
+
scrollHandlerForTOC(positionY);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
71
|
+
// Theme Toggle
|
|
72
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
73
|
+
function setTheme(mode) {
|
|
74
|
+
if (mode !== "light" && mode !== "dark" && mode !== "auto") {
|
|
75
|
+
console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);
|
|
76
|
+
mode = "auto";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
document.body.dataset.theme = mode;
|
|
80
|
+
localStorage.setItem("theme", mode);
|
|
81
|
+
console.log(`Changed to ${mode} mode.`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function cycleThemeOnce() {
|
|
85
|
+
const currentTheme = localStorage.getItem("theme") || "auto";
|
|
86
|
+
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
87
|
+
|
|
88
|
+
if (prefersDark) {
|
|
89
|
+
// Auto (dark) -> Light -> Dark
|
|
90
|
+
if (currentTheme === "auto") {
|
|
91
|
+
setTheme("light");
|
|
92
|
+
} else if (currentTheme == "light") {
|
|
93
|
+
setTheme("dark");
|
|
94
|
+
} else {
|
|
95
|
+
setTheme("auto");
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
// Auto (light) -> Dark -> Light
|
|
99
|
+
if (currentTheme === "auto") {
|
|
100
|
+
setTheme("dark");
|
|
101
|
+
} else if (currentTheme == "dark") {
|
|
102
|
+
setTheme("light");
|
|
103
|
+
} else {
|
|
104
|
+
setTheme("auto");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
110
|
+
// Setup
|
|
111
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
112
|
+
function setupScrollHandler() {
|
|
113
|
+
// Taken from https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event
|
|
114
|
+
let last_known_scroll_position = 0;
|
|
115
|
+
let ticking = false;
|
|
116
|
+
|
|
117
|
+
window.addEventListener("scroll", function (e) {
|
|
118
|
+
last_known_scroll_position = window.scrollY;
|
|
119
|
+
|
|
120
|
+
if (!ticking) {
|
|
121
|
+
window.requestAnimationFrame(function () {
|
|
122
|
+
scrollHandler(last_known_scroll_position);
|
|
123
|
+
ticking = false;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
ticking = true;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
window.scroll();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function setupScrollSpy() {
|
|
133
|
+
if (tocScroll === null) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Scrollspy -- highlight table on contents, based on scroll
|
|
138
|
+
// new Gumshoe(".toc-tree a", {
|
|
139
|
+
// reflow: true,
|
|
140
|
+
// recursive: true,
|
|
141
|
+
// navClass: "scroll-current",
|
|
142
|
+
// offset: () => {
|
|
143
|
+
// let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
144
|
+
// return header.getBoundingClientRect().height + 0.5 * rem + 1;
|
|
145
|
+
// },
|
|
146
|
+
// });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function setupTheme() {
|
|
150
|
+
// Attach event handlers for toggling themes
|
|
151
|
+
const buttons = document.getElementsByClassName("theme-toggle");
|
|
152
|
+
Array.from(buttons).forEach((btn) => {
|
|
153
|
+
btn.addEventListener("click", cycleThemeOnce);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function setup() {
|
|
158
|
+
setupTheme();
|
|
159
|
+
setupScrollHandler();
|
|
160
|
+
setupScrollSpy();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
164
|
+
// Main entrypoint
|
|
165
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
166
|
+
function main() {
|
|
167
|
+
document.body.parentNode.classList.remove("no-js");
|
|
168
|
+
|
|
169
|
+
// header = document.querySelectorAll("header")[1];
|
|
170
|
+
tocScroll = document.querySelector(".toc-scroll");
|
|
171
|
+
|
|
172
|
+
setup();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
document.addEventListener("DOMContentLoaded", main);
|