17
15
from docutils import nodes
16
from docutils.parsers.rst import Directive
18
17
from docutils.parsers.rst import directives
19
18
from docutils.parsers.rst.roles import set_classes
22
def topic(name, arguments, options, content, lineno,
23
content_offset, block_text, state, state_machine,
24
node_class=nodes.topic):
25
if not (state_machine.match_titles
26
or isinstance(state_machine.node, nodes.sidebar)):
27
error = state_machine.reporter.error(
28
'The "%s" directive may not be used within topics '
29
'or body elements.' % name,
30
nodes.literal_block(block_text, block_text), line=lineno)
33
warning = state_machine.reporter.warning(
34
'Content block expected for the "%s" directive; none found.'
35
% name, nodes.literal_block(block_text, block_text),
38
title_text = arguments[0]
39
textnodes, messages = state.inline_text(title_text, lineno)
40
titles = [nodes.title(title_text, '', *textnodes)]
41
# sidebar uses this code
42
if options.has_key('subtitle'):
43
textnodes, more_messages = state.inline_text(options['subtitle'],
45
titles.append(nodes.subtitle(options['subtitle'], '', *textnodes))
46
messages.extend(more_messages)
47
text = '\n'.join(content)
48
node = node_class(text, *(titles + messages))
49
node['classes'] += options.get('class', [])
51
state.nested_parse(content, content_offset, node)
54
topic.arguments = (1, 0, 1)
55
topic.options = {'class': directives.class_option}
58
def sidebar(name, arguments, options, content, lineno,
59
content_offset, block_text, state, state_machine):
60
if isinstance(state_machine.node, nodes.sidebar):
61
error = state_machine.reporter.error(
62
'The "%s" directive may not be used within a sidebar element.'
63
% name, nodes.literal_block(block_text, block_text), line=lineno)
65
return topic(name, arguments, options, content, lineno,
66
content_offset, block_text, state, state_machine,
67
node_class=nodes.sidebar)
69
sidebar.arguments = (1, 0, 1)
70
sidebar.options = {'subtitle': directives.unchanged_required,
71
'class': directives.class_option}
74
def line_block(name, arguments, options, content, lineno,
75
content_offset, block_text, state, state_machine):
77
warning = state_machine.reporter.warning(
78
'Content block expected for the "%s" directive; none found.'
79
% name, nodes.literal_block(block_text, block_text), line=lineno)
81
block = nodes.line_block(classes=options.get('class', []))
83
for line_text in content:
84
text_nodes, messages = state.inline_text(line_text.strip(),
85
lineno + content_offset)
86
line = nodes.line(line_text, '', *text_nodes)
88
line.indent = len(line_text) - len(line_text.lstrip())
90
node_list.extend(messages)
92
state.nest_line_block_lines(block)
95
line_block.options = {'class': directives.class_option}
96
line_block.content = 1
98
def parsed_literal(name, arguments, options, content, lineno,
99
content_offset, block_text, state, state_machine):
101
return block(name, arguments, options, content, lineno,
102
content_offset, block_text, state, state_machine,
103
node_class=nodes.literal_block)
105
parsed_literal.options = {'class': directives.class_option}
106
parsed_literal.content = 1
108
def block(name, arguments, options, content, lineno,
109
content_offset, block_text, state, state_machine, node_class):
111
warning = state_machine.reporter.warning(
112
'Content block expected for the "%s" directive; none found.'
113
% name, nodes.literal_block(block_text, block_text), line=lineno)
115
text = '\n'.join(content)
116
text_nodes, messages = state.inline_text(text, lineno)
117
node = node_class(text, '', *text_nodes, **options)
118
node.line = content_offset + 1
119
return [node] + messages
121
def rubric(name, arguments, options, content, lineno,
122
content_offset, block_text, state, state_machine):
123
rubric_text = arguments[0]
124
textnodes, messages = state.inline_text(rubric_text, lineno)
125
rubric = nodes.rubric(rubric_text, '', *textnodes, **options)
126
return [rubric] + messages
128
rubric.arguments = (1, 0, 1)
129
rubric.options = {'class': directives.class_option}
131
def epigraph(name, arguments, options, content, lineno,
132
content_offset, block_text, state, state_machine):
133
block_quote, messages = state.block_quote(content, content_offset)
134
block_quote['classes'].append('epigraph')
135
return [block_quote] + messages
139
def highlights(name, arguments, options, content, lineno,
140
content_offset, block_text, state, state_machine):
141
block_quote, messages = state.block_quote(content, content_offset)
142
block_quote['classes'].append('highlights')
143
return [block_quote] + messages
145
highlights.content = 1
147
def pull_quote(name, arguments, options, content, lineno,
148
content_offset, block_text, state, state_machine):
149
block_quote, messages = state.block_quote(content, content_offset)
150
block_quote['classes'].append('pull-quote')
151
return [block_quote] + messages
153
pull_quote.content = 1
155
def compound(name, arguments, options, content, lineno,
156
content_offset, block_text, state, state_machine):
157
text = '\n'.join(content)
159
error = state_machine.reporter.error(
160
'The "%s" directive is empty; content required.' % name,
161
nodes.literal_block(block_text, block_text), line=lineno)
163
node = nodes.compound(text)
164
node['classes'] += options.get('class', [])
165
state.nested_parse(content, content_offset, node)
168
compound.options = {'class': directives.class_option}
171
def container(name, arguments, options, content, lineno,
172
content_offset, block_text, state, state_machine):
173
text = '\n'.join(content)
175
error = state_machine.reporter.error(
176
'The "%s" directive is empty; content required.' % name,
177
nodes.literal_block(block_text, block_text), line=lineno)
181
classes = directives.class_option(arguments[0])
185
error = state_machine.reporter.error(
186
'Invalid class attribute value for "%s" directive: "%s".'
187
% (name, arguments[0]),
188
nodes.literal_block(block_text, block_text), line=lineno)
190
node = nodes.container(text)
191
node['classes'].extend(classes)
192
state.nested_parse(content, content_offset, node)
195
container.arguments = (0, 1, 1)
196
container.content = 1
21
class BasePseudoSection(Directive):
23
required_arguments = 1
24
optional_arguments = 0
25
final_argument_whitespace = True
26
option_spec = {'class': directives.class_option}
30
"""Node class to be used (must be set in subclasses)."""
33
if not (self.state_machine.match_titles
34
or isinstance(self.state_machine.node, nodes.sidebar)):
35
raise self.error('The "%s" directive may not be used within '
36
'topics or body elements.' % self.name)
37
self.assert_has_content()
38
title_text = self.arguments[0]
39
textnodes, messages = self.state.inline_text(title_text, self.lineno)
40
titles = [nodes.title(title_text, '', *textnodes)]
41
# Sidebar uses this code.
42
if self.options.has_key('subtitle'):
43
textnodes, more_messages = self.state.inline_text(
44
self.options['subtitle'], self.lineno)
45
titles.append(nodes.subtitle(self.options['subtitle'], '',
47
messages.extend(more_messages)
48
text = '\n'.join(self.content)
49
node = self.node_class(text, *(titles + messages))
50
node['classes'] += self.options.get('class', [])
52
self.state.nested_parse(self.content, self.content_offset, node)
56
class Topic(BasePseudoSection):
58
node_class = nodes.topic
61
class Sidebar(BasePseudoSection):
63
node_class = nodes.sidebar
65
option_spec = BasePseudoSection.option_spec.copy()
66
option_spec['subtitle'] = directives.unchanged_required
69
if isinstance(self.state_machine.node, nodes.sidebar):
70
raise self.error('The "%s" directive may not be used within a '
71
'sidebar element.' % self.name)
72
return BasePseudoSection.run(self)
75
class LineBlock(Directive):
77
option_spec = {'class': directives.class_option}
81
self.assert_has_content()
82
block = nodes.line_block(classes=self.options.get('class', []))
84
for line_text in self.content:
85
text_nodes, messages = self.state.inline_text(
86
line_text.strip(), self.lineno + self.content_offset)
87
line = nodes.line(line_text, '', *text_nodes)
89
line.indent = len(line_text) - len(line_text.lstrip())
91
node_list.extend(messages)
92
self.content_offset += 1
93
self.state.nest_line_block_lines(block)
97
class ParsedLiteral(Directive):
99
option_spec = {'class': directives.class_option}
103
set_classes(self.options)
104
self.assert_has_content()
105
text = '\n'.join(self.content)
106
text_nodes, messages = self.state.inline_text(text, self.lineno)
107
node = nodes.literal_block(text, '', *text_nodes, **self.options)
108
node.line = self.content_offset + 1
109
return [node] + messages
112
class Rubric(Directive):
114
required_arguments = 1
115
optional_arguments = 0
116
final_argument_whitespace = True
117
option_spec = {'class': directives.class_option}
120
set_classes(self.options)
121
rubric_text = self.arguments[0]
122
textnodes, messages = self.state.inline_text(rubric_text, self.lineno)
123
rubric = nodes.rubric(rubric_text, '', *textnodes, **self.options)
124
return [rubric] + messages
127
class BlockQuote(Directive):
133
self.assert_has_content()
134
elements = self.state.block_quote(self.content, self.content_offset)
135
for element in elements:
136
if isinstance(element, nodes.block_quote):
137
element['classes'] += self.classes
141
class Epigraph(BlockQuote):
143
classes = ['epigraph']
146
class Highlights(BlockQuote):
148
classes = ['highlights']
151
class PullQuote(BlockQuote):
153
classes = ['pull-quote']
156
class Compound(Directive):
158
option_spec = {'class': directives.class_option}
162
self.assert_has_content()
163
text = '\n'.join(self.content)
164
node = nodes.compound(text)
165
node['classes'] += self.options.get('class', [])
166
self.state.nested_parse(self.content, self.content_offset, node)
170
class Container(Directive):
172
required_arguments = 0
173
optional_arguments = 1
174
final_argument_whitespace = True
178
self.assert_has_content()
179
text = '\n'.join(self.content)
182
classes = directives.class_option(self.arguments[0])
187
'Invalid class attribute value for "%s" directive: "%s".'
188
% (self.name, self.arguments[0]))
189
node = nodes.container(text)
190
node['classes'].extend(classes)
191
self.state.nested_parse(self.content, self.content_offset, node)