~ubuntu-branches/ubuntu/jaunty/python-docutils/jaunty

« back to all changes in this revision

Viewing changes to docutils/parsers/rst/directives/body.py

  • Committer: Bazaar Package Importer
  • Author(s): Simon McVittie
  • Date: 2008-07-24 10:39:53 UTC
  • mfrom: (1.1.4 upstream) (3.1.7 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080724103953-8gh4uezg17g9ysgy
Tags: 0.5-2
* Upload docutils 0.5 to unstable
* Update rst.el to upstream Subversion r5596, which apparently fixes
  all its performance problems (17_speed_up_rst_el.dpatch, closes: #474941)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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) $
 
1
# $Id: body.py 4667 2006-07-12 21:40:56Z wiemann $
 
2
# Author: David Goodger <goodger@python.org>
5
3
# Copyright: This module has been placed in the public domain.
6
4
 
7
5
"""
15
13
 
16
14
import sys
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
20
19
 
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
 
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
    has_content = True
 
28
 
 
29
    node_class = None
 
30
    """Node class to be used (must be set in subclasses)."""
 
31
 
 
32
    def run(self):
 
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'], '',
 
46
                                         *textnodes))
 
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', [])
 
51
        if text:
 
52
            self.state.nested_parse(self.content, self.content_offset, node)
 
53
        return [node]
 
54
 
 
55
 
 
56
class Topic(BasePseudoSection):
 
57
 
 
58
    node_class = nodes.topic
 
59
 
 
60
 
 
61
class Sidebar(BasePseudoSection):
 
62
 
 
63
    node_class = nodes.sidebar
 
64
 
 
65
    option_spec = BasePseudoSection.option_spec.copy()
 
66
    option_spec['subtitle'] = directives.unchanged_required
 
67
 
 
68
    def run(self):
 
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)
 
73
 
 
74
 
 
75
class LineBlock(Directive):
 
76
 
 
77
    option_spec = {'class': directives.class_option}
 
78
    has_content = True
 
79
 
 
80
    def run(self):
 
81
        self.assert_has_content()
 
82
        block = nodes.line_block(classes=self.options.get('class', []))
 
83
        node_list = [block]
 
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)
 
88
            if line_text.strip():
 
89
                line.indent = len(line_text) - len(line_text.lstrip())
 
90
            block += line
 
91
            node_list.extend(messages)
 
92
            self.content_offset += 1
 
93
        self.state.nest_line_block_lines(block)
 
94
        return node_list
 
95
 
 
96
 
 
97
class ParsedLiteral(Directive):
 
98
 
 
99
    option_spec = {'class': directives.class_option}
 
100
    has_content = True
 
101
 
 
102
    def run(self):
 
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
 
110
 
 
111
 
 
112
class Rubric(Directive):
 
113
 
 
114
    required_arguments = 1
 
115
    optional_arguments = 0
 
116
    final_argument_whitespace = True
 
117
    option_spec = {'class': directives.class_option}
 
118
 
 
119
    def run(self):
 
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
 
125
 
 
126
 
 
127
class BlockQuote(Directive):
 
128
 
 
129
    has_content = True
 
130
    classes = []
 
131
 
 
132
    def run(self):
 
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
 
138
        return elements
 
139
 
 
140
 
 
141
class Epigraph(BlockQuote):
 
142
 
 
143
    classes = ['epigraph']
 
144
 
 
145
 
 
146
class Highlights(BlockQuote):
 
147
 
 
148
    classes = ['highlights']
 
149
 
 
150
 
 
151
class PullQuote(BlockQuote):
 
152
 
 
153
    classes = ['pull-quote']
 
154
 
 
155
 
 
156
class Compound(Directive):
 
157
 
 
158
    option_spec = {'class': directives.class_option}
 
159
    has_content = True
 
160
 
 
161
    def run(self):
 
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)
 
167
        return [node]
 
168
 
 
169
 
 
170
class Container(Directive):
 
171
 
 
172
    required_arguments = 0
 
173
    optional_arguments = 1
 
174
    final_argument_whitespace = True
 
175
    has_content = True
 
176
 
 
177
    def run(self):
 
178
        self.assert_has_content()
 
179
        text = '\n'.join(self.content)
 
180
        try:
 
181
            if self.arguments:
 
182
                classes = directives.class_option(self.arguments[0])
 
183
            else:
 
184
                classes = []
 
185
        except ValueError:
 
186
            raise self.error(
 
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)
 
192
        return [node]