Common directive options:
[docutils.git] / docutils / parsers / rst / directives / body.py
blob90b7ce1ca78b98636130f30ce67581937c260764
1 # $Id$
2 # Author: David Goodger <goodger@python.org>
3 # Copyright: This module has been placed in the public domain.
5 """
6 Directives for additional body elements.
8 See `docutils.parsers.rst.directives` for API details.
9 """
11 __docformat__ = 'reStructuredText'
14 import sys
15 from docutils import nodes
16 from docutils.parsers.rst import Directive
17 from docutils.parsers.rst import directives
18 from docutils.parsers.rst.roles import set_classes
21 class BasePseudoSection(Directive):
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
30 node_class = None
31 """Node class to be used (must be set in subclasses)."""
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]
58 class Topic(BasePseudoSection):
60 node_class = nodes.topic
63 class Sidebar(BasePseudoSection):
65 node_class = nodes.sidebar
67 option_spec = BasePseudoSection.option_spec.copy()
68 option_spec['subtitle'] = directives.unchanged_required
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)
77 class LineBlock(Directive):
79 option_spec = {'class': directives.class_option,
80 'name': directives.unchanged}
81 has_content = True
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
101 class ParsedLiteral(Directive):
103 option_spec = {'class': directives.class_option,
104 'name': directives.unchanged}
105 has_content = True
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
118 class MathBlock(Directive):
120 option_spec = {'class': directives.class_option,
121 'name': directives.unchanged}
122 ## TODO: Add Sphinx' ``mathbase.py`` option 'nowrap'?
123 # 'nowrap': directives.flag,
124 has_content = True
126 def run(self):
127 set_classes(self.options)
128 self.assert_has_content()
129 # join lines, separate blocks
130 content = '\n'.join(self.content).split('\n\n')
131 _nodes = []
132 for block in content:
133 if not block:
134 continue
135 node = nodes.math_block(self.block_text, block, **self.options)
136 node.line = self.content_offset + 1
137 self.add_name(node)
138 _nodes.append(node)
139 return _nodes
142 class Rubric(Directive):
144 required_arguments = 1
145 optional_arguments = 0
146 final_argument_whitespace = True
147 option_spec = {'class': directives.class_option,
148 'name': directives.unchanged}
150 def run(self):
151 set_classes(self.options)
152 rubric_text = self.arguments[0]
153 textnodes, messages = self.state.inline_text(rubric_text, self.lineno)
154 rubric = nodes.rubric(rubric_text, '', *textnodes, **self.options)
155 self.add_name(rubric)
156 return [rubric] + messages
159 class BlockQuote(Directive):
161 has_content = True
162 classes = []
164 def run(self):
165 self.assert_has_content()
166 elements = self.state.block_quote(self.content, self.content_offset)
167 for element in elements:
168 if isinstance(element, nodes.block_quote):
169 element['classes'] += self.classes
170 return elements
173 class Epigraph(BlockQuote):
175 classes = ['epigraph']
178 class Highlights(BlockQuote):
180 classes = ['highlights']
183 class PullQuote(BlockQuote):
185 classes = ['pull-quote']
188 class Compound(Directive):
190 option_spec = {'class': directives.class_option,
191 'name': directives.unchanged}
192 has_content = True
194 def run(self):
195 self.assert_has_content()
196 text = '\n'.join(self.content)
197 node = nodes.compound(text)
198 node['classes'] += self.options.get('class', [])
199 self.add_name(node)
200 self.state.nested_parse(self.content, self.content_offset, node)
201 return [node]
204 class Container(Directive):
206 optional_arguments = 1
207 final_argument_whitespace = True
208 option_spec = {'name': directives.unchanged}
209 has_content = True
211 def run(self):
212 self.assert_has_content()
213 text = '\n'.join(self.content)
214 try:
215 if self.arguments:
216 classes = directives.class_option(self.arguments[0])
217 else:
218 classes = []
219 except ValueError:
220 raise self.error(
221 'Invalid class attribute value for "%s" directive: "%s".'
222 % (self.name, self.arguments[0]))
223 node = nodes.container(text)
224 node['classes'].extend(classes)
225 self.add_name(node)
226 self.state.nested_parse(self.content, self.content_offset, node)
227 return [node]