| 1 | # Author: David Goodger |
|---|
| 2 | # Contact: goodger@python.org |
|---|
| 3 | # Revision: $Revision: 3963 $ |
|---|
| 4 | # Date: $Date: 2005-10-28 18:12:56 +0200 (Fri, 28 Oct 2005) $ |
|---|
| 5 | # Copyright: This module has been placed in the public domain. |
|---|
| 6 | |
|---|
| 7 | """ |
|---|
| 8 | Directives for additional body elements. |
|---|
| 9 | |
|---|
| 10 | See `docutils.parsers.rst.directives` for API details. |
|---|
| 11 | """ |
|---|
| 12 | |
|---|
| 13 | __docformat__ = 'reStructuredText' |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | import sys |
|---|
| 17 | from docutils import nodes |
|---|
| 18 | from docutils.parsers.rst import directives |
|---|
| 19 | from docutils.parsers.rst.roles import set_classes |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 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) |
|---|
| 31 | return [error] |
|---|
| 32 | if not content: |
|---|
| 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), |
|---|
| 36 | line=lineno) |
|---|
| 37 | return [warning] |
|---|
| 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'], |
|---|
| 44 | lineno) |
|---|
| 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', []) |
|---|
| 50 | if text: |
|---|
| 51 | state.nested_parse(content, content_offset, node) |
|---|
| 52 | return [node] |
|---|
| 53 | |
|---|
| 54 | topic.arguments = (1, 0, 1) |
|---|
| 55 | topic.options = {'class': directives.class_option} |
|---|
| 56 | topic.content = 1 |
|---|
| 57 | |
|---|
| 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) |
|---|
| 64 | return [error] |
|---|
| 65 | return topic(name, arguments, options, content, lineno, |
|---|
| 66 | content_offset, block_text, state, state_machine, |
|---|
| 67 | node_class=nodes.sidebar) |
|---|
| 68 | |
|---|
| 69 | sidebar.arguments = (1, 0, 1) |
|---|
| 70 | sidebar.options = {'subtitle': directives.unchanged_required, |
|---|
| 71 | 'class': directives.class_option} |
|---|
| 72 | sidebar.content = 1 |
|---|
| 73 | |
|---|
| 74 | def line_block(name, arguments, options, content, lineno, |
|---|
| 75 | content_offset, block_text, state, state_machine): |
|---|
| 76 | if not content: |
|---|
| 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) |
|---|
| 80 | return [warning] |
|---|
| 81 | block = nodes.line_block(classes=options.get('class', [])) |
|---|
| 82 | node_list = [block] |
|---|
| 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) |
|---|
| 87 | if line_text.strip(): |
|---|
| 88 | line.indent = len(line_text) - len(line_text.lstrip()) |
|---|
| 89 | block += line |
|---|
| 90 | node_list.extend(messages) |
|---|
| 91 | content_offset += 1 |
|---|
| 92 | state.nest_line_block_lines(block) |
|---|
| 93 | return node_list |
|---|
| 94 | |
|---|
| 95 | line_block.options = {'class': directives.class_option} |
|---|
| 96 | line_block.content = 1 |
|---|
| 97 | |
|---|
| 98 | def parsed_literal(name, arguments, options, content, lineno, |
|---|
| 99 | content_offset, block_text, state, state_machine): |
|---|
| 100 | set_classes(options) |
|---|
| 101 | return block(name, arguments, options, content, lineno, |
|---|
| 102 | content_offset, block_text, state, state_machine, |
|---|
| 103 | node_class=nodes.literal_block) |
|---|
| 104 | |
|---|
| 105 | parsed_literal.options = {'class': directives.class_option} |
|---|
| 106 | parsed_literal.content = 1 |
|---|
| 107 | |
|---|
| 108 | def block(name, arguments, options, content, lineno, |
|---|
| 109 | content_offset, block_text, state, state_machine, node_class): |
|---|
| 110 | if not content: |
|---|
| 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) |
|---|
| 114 | return [warning] |
|---|
| 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 |
|---|
| 120 | |
|---|
| 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 |
|---|
| 127 | |
|---|
| 128 | rubric.arguments = (1, 0, 1) |
|---|
| 129 | rubric.options = {'class': directives.class_option} |
|---|
| 130 | |
|---|
| 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 |
|---|
| 136 | |
|---|
| 137 | epigraph.content = 1 |
|---|
| 138 | |
|---|
| 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 |
|---|
| 144 | |
|---|
| 145 | highlights.content = 1 |
|---|
| 146 | |
|---|
| 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 |
|---|
| 152 | |
|---|
| 153 | pull_quote.content = 1 |
|---|
| 154 | |
|---|
| 155 | def compound(name, arguments, options, content, lineno, |
|---|
| 156 | content_offset, block_text, state, state_machine): |
|---|
| 157 | text = '\n'.join(content) |
|---|
| 158 | if not text: |
|---|
| 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) |
|---|
| 162 | return [error] |
|---|
| 163 | node = nodes.compound(text) |
|---|
| 164 | node['classes'] += options.get('class', []) |
|---|
| 165 | state.nested_parse(content, content_offset, node) |
|---|
| 166 | return [node] |
|---|
| 167 | |
|---|
| 168 | compound.options = {'class': directives.class_option} |
|---|
| 169 | compound.content = 1 |
|---|
| 170 | |
|---|
| 171 | def container(name, arguments, options, content, lineno, |
|---|
| 172 | content_offset, block_text, state, state_machine): |
|---|
| 173 | text = '\n'.join(content) |
|---|
| 174 | if not text: |
|---|
| 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) |
|---|
| 178 | return [error] |
|---|
| 179 | try: |
|---|
| 180 | if arguments: |
|---|
| 181 | classes = directives.class_option(arguments[0]) |
|---|
| 182 | else: |
|---|
| 183 | classes = [] |
|---|
| 184 | except ValueError: |
|---|
| 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) |
|---|
| 189 | return [error] |
|---|
| 190 | node = nodes.container(text) |
|---|
| 191 | node['classes'].extend(classes) |
|---|
| 192 | state.nested_parse(content, content_offset, node) |
|---|
| 193 | return [node] |
|---|
| 194 | |
|---|
| 195 | container.arguments = (0, 1, 1) |
|---|
| 196 | container.content = 1 |
|---|