2 # Author: David Goodger <goodger@python.org>
3 # Copyright: This module has been placed in the public domain.
6 Directives for additional body elements.
8 See `docutils.parsers.rst.directives` for API details.
11 __docformat__
= 'reStructuredText'
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
}
31 """Node class to be used (must be set in subclasses)."""
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'], '',
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', [])
54 self
.state
.nested_parse(self
.content
, self
.content_offset
, 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
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
}
84 self
.assert_has_content()
85 block
= nodes
.line_block(classes
=self
.options
.get('class', []))
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
)
93 line
.indent
= len(line_text
) - len(line_text
.lstrip())
95 node_list
.extend(messages
)
96 self
.content_offset
+= 1
97 self
.state
.nest_line_block_lines(block
)
101 class ParsedLiteral(Directive
):
103 option_spec
= {'class': directives
.class_option
,
104 'name': directives
.unchanged
}
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
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,
127 set_classes(self
.options
)
128 self
.assert_has_content()
129 # join lines, separate blocks
130 content
= '\n'.join(self
.content
).split('\n\n')
132 for block
in content
:
135 node
= nodes
.math_block(self
.block_text
, block
, **self
.options
)
136 node
.line
= self
.content_offset
+ 1
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
}
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
):
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
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
}
195 self
.assert_has_content()
196 text
= '\n'.join(self
.content
)
197 node
= nodes
.compound(text
)
198 node
['classes'] += self
.options
.get('class', [])
200 self
.state
.nested_parse(self
.content
, self
.content_offset
, node
)
204 class Container(Directive
):
206 optional_arguments
= 1
207 final_argument_whitespace
= True
208 option_spec
= {'name': directives
.unchanged
}
212 self
.assert_has_content()
213 text
= '\n'.join(self
.content
)
216 classes
= directives
.class_option(self
.arguments
[0])
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
)
226 self
.state
.nested_parse(self
.content
, self
.content_offset
, node
)