comparison env/lib/python3.9/site-packages/docutils/parsers/rst/directives/body.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # $Id: body.py 8347 2019-08-26 12:12:02Z milde $
2 # Author: David Goodger <goodger@python.org>
3 # Copyright: This module has been placed in the public domain.
4
5 """
6 Directives for additional body elements.
7
8 See `docutils.parsers.rst.directives` for API details.
9 """
10
11 __docformat__ = 'reStructuredText'
12
13
14 from docutils import nodes
15 from docutils.parsers.rst import Directive
16 from docutils.parsers.rst import directives
17 from docutils.parsers.rst.roles import set_classes
18 from docutils.utils.code_analyzer import Lexer, LexerError, NumberLines
19
20
21 class BasePseudoSection(Directive):
22
23 required_arguments = 1
24 optional_arguments = 0
25 final_argument_whitespace = True
26 option_spec = {'class': directives.class_option,
27 'name': directives.unchanged}
28 has_content = True
29
30 node_class = None
31 """Node class to be used (must be set in subclasses)."""
32
33 def run(self):
34 if not (self.state_machine.match_titles
35 or isinstance(self.state_machine.node, nodes.sidebar)):
36 raise self.error('The "%s" directive may not be used within '
37 'topics or body elements.' % self.name)
38 self.assert_has_content()
39 title_text = self.arguments[0]
40 textnodes, messages = self.state.inline_text(title_text, self.lineno)
41 titles = [nodes.title(title_text, '', *textnodes)]
42 # Sidebar uses this code.
43 if 'subtitle' in self.options:
44 textnodes, more_messages = self.state.inline_text(
45 self.options['subtitle'], self.lineno)
46 titles.append(nodes.subtitle(self.options['subtitle'], '',
47 *textnodes))
48 messages.extend(more_messages)
49 text = '\n'.join(self.content)
50 node = self.node_class(text, *(titles + messages))
51 node['classes'] += self.options.get('class', [])
52 self.add_name(node)
53 if text:
54 self.state.nested_parse(self.content, self.content_offset, node)
55 return [node]
56
57
58 class Topic(BasePseudoSection):
59
60 node_class = nodes.topic
61
62
63 class Sidebar(BasePseudoSection):
64
65 node_class = nodes.sidebar
66
67 option_spec = BasePseudoSection.option_spec.copy()
68 option_spec['subtitle'] = directives.unchanged_required
69
70 def run(self):
71 if isinstance(self.state_machine.node, nodes.sidebar):
72 raise self.error('The "%s" directive may not be used within a '
73 'sidebar element.' % self.name)
74 return BasePseudoSection.run(self)
75
76
77 class LineBlock(Directive):
78
79 option_spec = {'class': directives.class_option,
80 'name': directives.unchanged}
81 has_content = True
82
83 def run(self):
84 self.assert_has_content()
85 block = nodes.line_block(classes=self.options.get('class', []))
86 self.add_name(block)
87 node_list = [block]
88 for line_text in self.content:
89 text_nodes, messages = self.state.inline_text(
90 line_text.strip(), self.lineno + self.content_offset)
91 line = nodes.line(line_text, '', *text_nodes)
92 if line_text.strip():
93 line.indent = len(line_text) - len(line_text.lstrip())
94 block += line
95 node_list.extend(messages)
96 self.content_offset += 1
97 self.state.nest_line_block_lines(block)
98 return node_list
99
100
101 class ParsedLiteral(Directive):
102
103 option_spec = {'class': directives.class_option,
104 'name': directives.unchanged}
105 has_content = True
106
107 def run(self):
108 set_classes(self.options)
109 self.assert_has_content()
110 text = '\n'.join(self.content)
111 text_nodes, messages = self.state.inline_text(text, self.lineno)
112 node = nodes.literal_block(text, '', *text_nodes, **self.options)
113 node.line = self.content_offset + 1
114 self.add_name(node)
115 return [node] + messages
116
117
118 class CodeBlock(Directive):
119 """Parse and mark up content of a code block.
120
121 Configuration setting: syntax_highlight
122 Highlight Code content with Pygments?
123 Possible values: ('long', 'short', 'none')
124
125 """
126 optional_arguments = 1
127 option_spec = {'class': directives.class_option,
128 'name': directives.unchanged,
129 'number-lines': directives.unchanged # integer or None
130 }
131 has_content = True
132
133 def run(self):
134 self.assert_has_content()
135 if self.arguments:
136 language = self.arguments[0]
137 else:
138 language = ''
139 set_classes(self.options)
140 classes = ['code']
141 if language:
142 classes.append(language)
143 if 'classes' in self.options:
144 classes.extend(self.options['classes'])
145
146 # set up lexical analyzer
147 try:
148 tokens = Lexer(u'\n'.join(self.content), language,
149 self.state.document.settings.syntax_highlight)
150 except LexerError as error:
151 raise self.warning(error)
152
153 if 'number-lines' in self.options:
154 # optional argument `startline`, defaults to 1
155 try:
156 startline = int(self.options['number-lines'] or 1)
157 except ValueError:
158 raise self.error(':number-lines: with non-integer start value')
159 endline = startline + len(self.content)
160 # add linenumber filter:
161 tokens = NumberLines(tokens, startline, endline)
162
163 node = nodes.literal_block('\n'.join(self.content), classes=classes)
164 self.add_name(node)
165 # if called from "include", set the source
166 if 'source' in self.options:
167 node.attributes['source'] = self.options['source']
168 # analyze content and add nodes for every token
169 for classes, value in tokens:
170 if classes:
171 node += nodes.inline(value, value, classes=classes)
172 else:
173 # insert as Text to decrease the verbosity of the output
174 node += nodes.Text(value)
175
176 return [node]
177
178
179 class MathBlock(Directive):
180
181 option_spec = {'class': directives.class_option,
182 'name': directives.unchanged}
183 ## TODO: Add Sphinx' ``mathbase.py`` option 'nowrap'?
184 # 'nowrap': directives.flag,
185 has_content = True
186
187 def run(self):
188 set_classes(self.options)
189 self.assert_has_content()
190 # join lines, separate blocks
191 content = '\n'.join(self.content).split('\n\n')
192 _nodes = []
193 for block in content:
194 if not block:
195 continue
196 node = nodes.math_block(self.block_text, block, **self.options)
197 node.line = self.content_offset + 1
198 self.add_name(node)
199 _nodes.append(node)
200 return _nodes
201
202
203 class Rubric(Directive):
204
205 required_arguments = 1
206 optional_arguments = 0
207 final_argument_whitespace = True
208 option_spec = {'class': directives.class_option,
209 'name': directives.unchanged}
210
211 def run(self):
212 set_classes(self.options)
213 rubric_text = self.arguments[0]
214 textnodes, messages = self.state.inline_text(rubric_text, self.lineno)
215 rubric = nodes.rubric(rubric_text, '', *textnodes, **self.options)
216 self.add_name(rubric)
217 return [rubric] + messages
218
219
220 class BlockQuote(Directive):
221
222 has_content = True
223 classes = []
224
225 def run(self):
226 self.assert_has_content()
227 elements = self.state.block_quote(self.content, self.content_offset)
228 for element in elements:
229 if isinstance(element, nodes.block_quote):
230 element['classes'] += self.classes
231 return elements
232
233
234 class Epigraph(BlockQuote):
235
236 classes = ['epigraph']
237
238
239 class Highlights(BlockQuote):
240
241 classes = ['highlights']
242
243
244 class PullQuote(BlockQuote):
245
246 classes = ['pull-quote']
247
248
249 class Compound(Directive):
250
251 option_spec = {'class': directives.class_option,
252 'name': directives.unchanged}
253 has_content = True
254
255 def run(self):
256 self.assert_has_content()
257 text = '\n'.join(self.content)
258 node = nodes.compound(text)
259 node['classes'] += self.options.get('class', [])
260 self.add_name(node)
261 self.state.nested_parse(self.content, self.content_offset, node)
262 return [node]
263
264
265 class Container(Directive):
266
267 optional_arguments = 1
268 final_argument_whitespace = True
269 option_spec = {'name': directives.unchanged}
270 has_content = True
271
272 def run(self):
273 self.assert_has_content()
274 text = '\n'.join(self.content)
275 try:
276 if self.arguments:
277 classes = directives.class_option(self.arguments[0])
278 else:
279 classes = []
280 except ValueError:
281 raise self.error(
282 'Invalid class attribute value for "%s" directive: "%s".'
283 % (self.name, self.arguments[0]))
284 node = nodes.container(text)
285 node['classes'].extend(classes)
286 self.add_name(node)
287 self.state.nested_parse(self.content, self.content_offset, node)
288 return [node]