Coverage for pyquickhelper/sphinxext/sphinx_quote_extension.py: 93%
182 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-03 02:21 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-03 02:21 +0200
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief Defines a :epkg:`sphinx` extension for a quote.
5"""
6from docutils import nodes
7from docutils.parsers.rst import directives
9import sphinx
10from sphinx.locale import _
11from docutils.parsers.rst.directives.admonitions import BaseAdmonition
12from docutils.statemachine import StringList
13from sphinx.util.nodes import nested_parse_with_titles
14from ..texthelper.texts_language import TITLES
17class quote_node(nodes.admonition):
18 """
19 Defines ``quote`` node.
20 """
21 pass
24class QuoteNode(BaseAdmonition):
25 """
26 A ``quotedef`` entry, displayed in the form of an admonition.
27 It takes the following options:
29 * *author*
30 * *book* or *manga* or *film* or *show* or *disc* or
31 *comic* or *child* or *ado*
32 * *year*
33 * *pages*
34 * *tag*
35 * *source*
36 * *lid* or *label*
37 * *index*, additional index words beside the title and the author
38 * *date*, if the text was written or declared at specific date
39 * *title1*, by default, the author comes first, if True, the title is
41 Example::
43 .. quote::
44 :author: author
45 :book: book
46 :year: year
47 :pages: pages (optional)
48 :tag: something
49 :lid: id (used for further reference)
50 :source: optional
51 :index: word
53 A monkey could...
54 """
56 node_class = quote_node
57 has_content = True
58 required_arguments = 0
59 optional_arguments = 0
60 final_argument_whitespace = False
61 option_spec = {
62 'author': directives.unchanged,
63 'book': directives.unchanged,
64 'manga': directives.unchanged,
65 'disc': directives.unchanged,
66 'ado': directives.unchanged,
67 'child': directives.unchanged,
68 'comic': directives.unchanged,
69 'show': directives.unchanged,
70 'film': directives.unchanged,
71 'year': directives.unchanged,
72 'pages': directives.unchanged,
73 'tag': directives.unchanged,
74 'lid': directives.unchanged,
75 'label': directives.unchanged,
76 'source': directives.unchanged,
77 'class': directives.class_option,
78 'index': directives.unchanged,
79 'date': directives.unchanged,
80 'title1': directives.unchanged,
81 }
83 def run(self):
84 """
85 Builds the mathdef text.
86 """
87 env = self.state.document.settings.env if hasattr(
88 self.state.document.settings, "env") else None
89 docname = None if env is None else env.docname
90 if docname is not None:
91 docname = docname.replace("\\", "/").split("/")[-1]
92 language_code = self.state.document.settings.language_code if hasattr(
93 self.state.document.settings, "language_code") else "en"
95 if not self.options.get('class'):
96 self.options['class'] = ['admonition-quote']
98 # body
99 (quote,) = super(QuoteNode, self).run()
100 if isinstance(quote, nodes.system_message):
101 return [quote] # pragma: no cover
103 # mid
104 tag = self.options.get('tag', 'quotetag').strip()
105 if len(tag) == 0:
106 raise ValueError("tag is empty") # pragma: no cover
108 def __(text):
109 if text:
110 return _(text)
111 return ""
113 # book
114 author = __(self.options.get('author', "").strip())
115 book = __(self.options.get('book', "").strip())
116 manga = __(self.options.get('manga', "").strip())
117 comic = __(self.options.get('comic', "").strip())
118 ado = __(self.options.get('ado', "").strip())
119 child = __(self.options.get('child', "").strip())
120 disc = __(self.options.get('disc', "").strip())
121 film = __(self.options.get('film', "").strip())
122 show = __(self.options.get('show', "").strip())
123 pages = __(self.options.get('pages', "").strip())
124 year = __(self.options.get('year', "").strip())
125 source = __(self.options.get('source', "").strip())
126 index = __(self.options.get('index', "").strip())
127 date = __(self.options.get('date', "").strip())
128 title1 = __(self.options.get('title1', "").strip()
129 ) in ('1', 1, 'True', True, 'true')
131 indexes = []
132 if index:
133 indexes.append(index) # pragma: no cover
135 # add a label
136 lid = self.options.get('lid', self.options.get('label', None))
137 if lid:
138 tnl = ['', f".. _{lid}:", ""]
139 else:
140 tnl = [] # pragma: no cover
142 if title1:
143 if ado:
144 tnl.append(f"**{ado}**")
145 if child:
146 tnl.append(f"**{child}**")
147 if comic:
148 tnl.append(f"**{comic}**")
149 if disc:
150 tnl.append(f"**{disc}**")
151 if book:
152 tnl.append(f"**{book}**")
153 if manga:
154 tnl.append(f"**{manga}**")
155 if show:
156 tnl.append(f"**{show}**")
157 if film:
158 tnl.append(f"**{film}**")
159 if author:
160 tnl.append(f"*{author}*, ")
161 else:
162 if author:
163 tnl.append(f"**{author}**, ")
164 if ado:
165 tnl.append(f"*{ado}*")
166 if child:
167 tnl.append(f"*{child}*")
168 if comic:
169 tnl.append(f"*{comic}*")
170 if disc:
171 tnl.append(f"*{disc}*")
172 if book:
173 tnl.append(f"*{book}*")
174 if manga:
175 tnl.append(f"*{manga}*")
176 if show:
177 tnl.append(f"*{show}*")
178 if film:
179 tnl.append(f"*{film}*")
181 if author:
182 indexes.append(author)
183 indexes.append(TITLES[language_code]['author'] + "; " + author)
184 if ado:
185 indexes.append(ado)
186 indexes.append(TITLES[language_code]['ado'] + "; " + ado)
187 if child:
188 indexes.append(child)
189 indexes.append(TITLES[language_code]['child'] + "; " + child)
190 if comic:
191 indexes.append(comic)
192 indexes.append(TITLES[language_code]['comic'] + "; " + comic)
193 if disc:
194 indexes.append(disc)
195 indexes.append(TITLES[language_code]['disc'] + "; " + disc)
196 if book:
197 indexes.append(book)
198 indexes.append(TITLES[language_code]['book'] + "; " + book)
199 if manga:
200 indexes.append(manga)
201 indexes.append(TITLES[language_code]['manga'] + "; " + manga)
202 if show:
203 indexes.append(show)
204 indexes.append(TITLES[language_code]['show'] + "; " + show)
205 if film:
206 indexes.append(film)
207 indexes.append(TITLES[language_code]['film'] + "; " + film)
209 if pages:
210 tnl.append(f", {pages}")
211 if date:
212 tnl.append(f" ({date})")
213 if year:
214 tnl.append(f" ({year})")
215 if source:
216 if source.startswith("http"):
217 tnl.append(f", `source <{source}>`_")
218 else:
219 tnl.append(f", {source}")
220 tnl.append('')
221 tnl.append(".. index:: " + ", ".join(indexes))
222 tnl.append('')
224 content = StringList(tnl)
225 content = content + self.content
226 node = quote_node()
228 try:
229 nested_parse_with_titles(self.state, content, node)
230 except Exception as e: # pragma: no cover
231 from sphinx.util import logging
232 logger = logging.getLogger("blogpost")
233 logger.warning(
234 "[blogpost] unable to parse %r - %r - %r", author, book or manga, e)
235 raise e
237 node['tag'] = tag
238 node['author'] = author
239 node['pages'] = pages
240 node['year'] = year
241 node['label'] = lid
242 node['source'] = source
243 node['book'] = book
244 node['manga'] = manga
245 node['disc'] = disc
246 node['comic'] = comic
247 node['ado'] = ado
248 node['child'] = child
249 node['film'] = film
250 node['show'] = show
251 node['index'] = index
252 node['content'] = '\n'.join(self.content)
253 node['classes'] += ["quote"]
255 return [node]
258def visit_quote_node(self, node):
259 """
260 visit_quote_node
261 """
262 self.visit_admonition(node)
265def depart_quote_node(self, node):
266 """
267 depart_quote_node,
268 see https://github.com/sphinx-doc/sphinx/blob/master/sphinx/writers/html.py
269 """
270 self.depart_admonition(node)
273def visit_quote_node_rst(self, node):
274 """
275 visit_quote_node
276 """
277 self.new_state(0)
278 self.add_text(".. quote::")
279 for k, v in sorted(node.attributes.items()):
280 if k in ("content", 'classes'):
281 continue
282 if v:
283 self.new_state(4)
284 self.add_text(f":{k}: {v}")
285 self.end_state(wrap=False, end=None)
286 self.add_text(self.nl)
287 self.new_state(4)
288 self.add_text(node['content'])
289 self.end_state()
290 self.end_state()
291 raise nodes.SkipNode
294def depart_quote_node_rst(self, node):
295 """
296 depart_quote_node,
297 see https://github.com/sphinx-doc/sphinx/blob/master/sphinx/writers/html.py
298 """
299 pass
302def setup(app):
303 """
304 setup for ``mathdef`` (sphinx)
305 """
306 if hasattr(app, "add_mapping"):
307 app.add_mapping('quote', quote_node)
309 app.add_node(quote_node,
310 html=(visit_quote_node, depart_quote_node),
311 epub=(visit_quote_node, depart_quote_node),
312 elatex=(visit_quote_node, depart_quote_node),
313 latex=(visit_quote_node, depart_quote_node),
314 text=(visit_quote_node, depart_quote_node),
315 md=(visit_quote_node, depart_quote_node),
316 rst=(visit_quote_node_rst, depart_quote_node_rst))
318 app.add_directive('quote', QuoteNode)
319 return {'version': sphinx.__display_version__, 'parallel_read_safe': True}