/
builders.py
160 lines (133 loc) · 5.88 KB
/
builders.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
"""Definition for sphinx custom builder."""
import copy
import logging
from typing import Any, Dict, List, Tuple
from sphinx import version_info as sphinx_versoin
from sphinx.application import Sphinx
from sphinx.builders.dirhtml import DirectoryHTMLBuilder
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.config import Config
from sphinx.environment import BuildEnvironment
from sphinx.locale import __
from sphinx_revealjs.directives import raw_json
from sphinx_revealjs.writers import RevealjsSlideTranslator
from .contexts import RevealjsPlugin, RevealjsProjectContext
from .utils import static_resource_uri
logger = logging.getLogger(__name__)
class RevealjsHTMLBuilder(StandaloneHTMLBuilder):
"""Sphinx builder class to generate Reveal.js presentation HTML.
This manage theme path and configure default options.
"""
name = "revealjs"
default_translator_class = RevealjsSlideTranslator
search = False
def __init__(self, app, env: BuildEnvironment = None): # noqa: D107
# TODO: Remove it if this not need support Sphinx 5.1.0 and older
if sphinx_versoin[0] <= 4 or sphinx_versoin[:2] == (5, 0):
super().__init__(app)
else:
super().__init__(app, env)
self.revealjs_slide = None
def init(self): # noqa
# Create RevealjsProjectContext
self.revealjs_context = RevealjsProjectContext(
4,
[ # noqa: W503
static_resource_uri(src)
for src in getattr(self.config, "revealjs_script_files", [])
],
getattr(self.config, "revealjs_script_conf", None),
[
RevealjsPlugin(
static_resource_uri(plugin["src"]),
plugin.get("name", ""),
plugin.get("options", "{}").strip(),
)
for plugin in getattr(self.config, "revealjs_script_plugins", [])
],
)
# Hand over builder configs to html builder.
setattr(self.config, "html_static_path", self.config.revealjs_static_path)
super().init()
self.use_index = self.get_builder_config("use_index", "revealjs")
def init_css_files(self) -> None: # noqa
self.add_css_file(self.revealjs_context.engine.css_path)
for filename in self.get_builder_config("css_files", "revealjs"):
self.add_css_file(filename)
def init_js_files(self) -> None: # noqa
for filename, attrs in self.app.registry.js_files:
self.add_js_file(filename, **attrs)
for filename, attrs in self.get_builder_config("js_files", "revealjs"):
self.add_js_file(filename, **attrs)
def get_theme_config(self) -> Tuple[str, Dict]:
"""Find and return configuration about theme (name and option params).
Find theme and merge options.
"""
theme_name = getattr(self.config, "revealjs_theme", "sphinx_revealjs")
theme_options = getattr(self.config, "revealjs_theme_options", {})
config = raw_json(theme_options.get("revealjs_config", ""))
theme_options["revealjs_config"] = config
return theme_name, theme_options
def get_doc_context(self, docname, body, metatags):
"""Return customized context.
if source has ``revealjs_slide`` property, add configures.
"""
ctx = super().get_doc_context(docname, body, metatags)
ctx["css_files"] = copy.copy(self.css_files)
ctx["revealjs"] = self.revealjs_context
return ctx
def update_page_context(
self, pagename: str, templatename: str, ctx: Dict, event_arg: Any
) -> None: # noqa
self.configure_theme(ctx)
ctx["revealjs_page_confs"] = self.configure_page_script_conf()
def configure_theme(self, ctx: Dict):
"""Find and add theme css from conf and directive."""
# Use directive or conf
if self.revealjs_slide and "theme" in self.revealjs_slide.attributes:
theme = self.revealjs_slide.attributes["theme"]
else:
theme = self.config.revealjs_style_theme
# Build path of stylesheet
if theme.startswith("http://") or theme.startswith("https://"):
pass
elif theme.endswith(".css"):
theme = f"_static/{theme}"
else:
theme = f"_static/{self.revealjs_context.engine.theme_dir}/{theme}.css"
# index 0: "_static/revealjs4/dist/reveal.css"
# index 1: theme css file path
# index 2 or later: other css files
ctx["css_files"].insert(1, theme)
def configure_page_script_conf(self) -> List[str]: # noqa
if not self.revealjs_slide:
return []
configs = []
if "conf" in self.revealjs_slide.attributes:
configs.append(self.revealjs_slide.attributes["conf"])
if self.revealjs_slide.content:
configs.append(self.revealjs_slide.content)
return configs
class DirectoryRevealjsHTMLBuilder(DirectoryHTMLBuilder, RevealjsHTMLBuilder):
"""
Custom RevealjsHTMLBuilder to generate all HTML pages as ``index.html``.
This does not have specific features, only inherit base builders.
"""
name = "dirrevealjs"
def convert_reveal_js_files(app: Sphinx, config: Config) -> None:
"""
Convert string styled html_js_files to tuple styled one.
Original is :py:func:`sphinx.builders.html.convert_html_js_files`.
"""
revealjs_js_files = [] # type: List[Tuple[str, Dict]]
for entry in config.revealjs_js_files:
if isinstance(entry, str):
revealjs_js_files.append((entry, {}))
else:
try:
filename, attrs = entry
revealjs_js_files.append((filename, attrs))
except Exception:
logger.warning(__("invalid js_file: %r, ignored"), entry)
continue
config.revealjs_js_files = revealjs_js_files # type: ignore