removed obsolete issues (many of them fixed with AE)
[docutils.git] / sandbox / delza / parsers / rst / directives / misc.py
blob40e908b830ef183d857c8719838c8f2bc4321523
1 # Authors: David Goodger, Dethe Elza
2 # Contact: goodger@users.sourceforge.net
3 # Revision: $Revision$
4 # Date: $Date$
5 # Copyright: This module has been placed in the public domain.
7 """Miscellaneous directives."""
9 __docformat__ = 'reStructuredText'
11 import sys
12 import os.path
13 import re
14 from urllib2 import urlopen, URLError
15 from docutils import io, nodes, statemachine, utils
16 from docutils.parsers.rst import directives, states
17 from docutils.transforms import misc
19 include_registry = {}
20 def include(name, arguments, options, content, lineno,
21 content_offset, block_text, state, state_machine):
22 """Include a reST file as part of the content of this reST file."""
23 try:
24 source = state_machine.input_lines.source(
25 lineno - state_machine.input_offset - 1)
26 source_dir = os.path.dirname(os.path.abspath(source))
27 except AttributeError:
28 # It might be that we're not actually reading from a file
29 # right now; so just read the first line of block_text
30 # instead and grab the filename from that
31 process_me=block_text
32 lines=re.compile("\n").split(process_me)
33 path=re.sub(re.compile("..\s+include::\s+"),"",lines[0])
34 source_dir = os.path.dirname(os.path.abspath(path))
36 path = ''.join(arguments[0].splitlines())
37 if path.find(' ') != -1:
38 error = state_machine.reporter.error(
39 '"%s" directive path contains whitespace.' % name,
40 nodes.literal_block(block_text, block_text), line=lineno)
41 return [error]
42 path = os.path.normpath(os.path.join(source_dir, path))
43 path = utils.relative_path(None, path)
44 if include_registry.has_key(path): return []
45 include_registry[path] = True
46 try:
47 include_file = io.FileInput(
48 source_path=path, encoding=state.document.settings.input_encoding,
49 handle_io_errors=None)
50 except IOError, error:
51 severe = state_machine.reporter.severe(
52 'Problems with "%s" directive path:\n%s: %s.'
53 % (name, error.__class__.__name__, error),
54 nodes.literal_block(block_text, block_text), line=lineno)
55 return [severe]
56 include_text = include_file.read()
57 if options.has_key('literal'):
58 literal_block = nodes.literal_block(include_text, include_text,
59 source=path)
60 literal_block.line = 1
61 return literal_block
62 else:
63 include_lines = statemachine.string2lines(include_text,
64 convert_whitespace=1)
65 state_machine.insert_input(include_lines, path)
66 return []
68 include.arguments = (1, 0, 1)
69 include.options = {'literal': directives.flag}
71 def raw(name, arguments, options, content, lineno,
72 content_offset, block_text, state, state_machine):
73 """
74 Pass through content unchanged
76 Content is included in output based on type argument
78 Content may be included inline (content section of directive) or
79 imported from a file or url.
80 """
81 attributes = {'format': arguments[0]}
82 if content:
83 if options.has_key('file') or options.has_key('url'):
84 error = state_machine.reporter.error(
85 '"%s" directive may not both specify an external file and '
86 'have content.' % name,
87 nodes.literal_block(block_text, block_text), line=lineno)
88 return [error]
89 text = '\n'.join(content)
90 elif options.has_key('file'):
91 if options.has_key('url'):
92 error = state_machine.reporter.error(
93 'The "file" and "url" options may not be simultaneously '
94 'specified for the "%s" directive.' % name,
95 nodes.literal_block(block_text, block_text), line=lineno)
96 return [error]
97 source_dir = os.path.dirname(
98 os.path.abspath(state.document.current_source))
99 path = os.path.normpath(os.path.join(source_dir, options['file']))
100 path = utils.relative_path(None, path)
101 try:
102 raw_file = open(path)
103 except IOError, error:
104 severe = state_machine.reporter.severe(
105 'Problems with "%s" directive path:\n%s.' % (name, error),
106 nodes.literal_block(block_text, block_text), line=lineno)
107 return [severe]
108 text = raw_file.read()
109 raw_file.close()
110 attributes['source'] = path
111 elif options.has_key('url'):
112 try:
113 raw_file = urlopen(options['url'])
114 except (URLError, IOError, OSError), error:
115 severe = state_machine.reporter.severe(
116 'Problems with "%s" directive URL "%s":\n%s.'
117 % (name, options['url'], error),
118 nodes.literal_block(block_text, block_text), line=lineno)
119 return [severe]
120 text = raw_file.read()
121 raw_file.close()
122 attributes['source'] = options['file']
123 else:
124 error = state_machine.reporter.warning(
125 'The "%s" directive requires content; none supplied.' % (name),
126 nodes.literal_block(block_text, block_text), line=lineno)
127 return [error]
128 raw_node = nodes.raw('', text, **attributes)
129 return [raw_node]
131 raw.arguments = (1, 0, 1)
132 raw.options = {'file': directives.path,
133 'url': directives.path}
134 raw.content = 1
136 def replace(name, arguments, options, content, lineno,
137 content_offset, block_text, state, state_machine):
138 if not isinstance(state, states.SubstitutionDef):
139 error = state_machine.reporter.error(
140 'Invalid context: the "%s" directive can only be used within a '
141 'substitution definition.' % (name),
142 nodes.literal_block(block_text, block_text), line=lineno)
143 return [error]
144 text = '\n'.join(content)
145 element = nodes.Element(text)
146 if text:
147 state.nested_parse(content, content_offset, element)
148 if len(element) != 1 or not isinstance(element[0], nodes.paragraph):
149 messages = []
150 for node in element:
151 if isinstance(node, nodes.system_message):
152 if node.has_key('backrefs'):
153 del node['backrefs']
154 messages.append(node)
155 error = state_machine.reporter.error(
156 'Error in "%s" directive: may contain a single paragraph '
157 'only.' % (name), line=lineno)
158 messages.append(error)
159 return messages
160 else:
161 return element[0].children
162 else:
163 error = state_machine.reporter.error(
164 'The "%s" directive is empty; content required.' % (name),
165 line=lineno)
166 return [error]
168 replace.content = 1
170 def unicode_directive(name, arguments, options, content, lineno,
171 content_offset, block_text, state, state_machine):
172 r"""
173 Convert Unicode character codes (numbers) to characters. Codes may be
174 decimal numbers, hexadecimal numbers (prefixed by ``0x``, ``x``, ``\x``,
175 ``U+``, ``u``, or ``\u``; e.g. ``U+262E``), or XML-style numeric character
176 entities (e.g. ``☮``). Text following ".." is a comment and is
177 ignored. Spaces are ignored, and any other text remains as-is.
179 if not isinstance(state, states.SubstitutionDef):
180 error = state_machine.reporter.error(
181 'Invalid context: the "%s" directive can only be used within a '
182 'substitution definition.' % (name),
183 nodes.literal_block(block_text, block_text), line=lineno)
184 return [error]
185 codes = arguments[0].split('.. ')[0].split()
186 element = nodes.Element()
187 for code in codes:
188 try:
189 if code.isdigit():
190 element += nodes.Text(unichr(int(code)))
191 else:
192 match = unicode_pattern.match(code)
193 if match:
194 value = match.group(1) or match.group(2)
195 element += nodes.Text(unichr(int(value, 16)))
196 else:
197 element += nodes.Text(code)
198 except (ValueError, OverflowError), err:
199 error = state_machine.reporter.error(
200 'Invalid character code: %s\n%s: %s'
201 % (code, err.__class__.__name__, err),
202 nodes.literal_block(block_text, block_text), line=lineno)
203 return [error]
204 return element.children
206 unicode_directive.arguments = (1, 0, 1)
207 unicode_pattern = re.compile(
208 r'(?:0x|x|\x00x|U\+?|\x00u)([0-9a-f]+)$|&#x([0-9a-f]+);$', re.IGNORECASE)
210 def class_directive(name, arguments, options, content, lineno,
211 content_offset, block_text, state, state_machine):
212 """"""
213 class_value = nodes.make_id(arguments[0])
214 if class_value:
215 pending = nodes.pending(misc.ClassAttribute,
216 {'class': class_value, 'directive': name},
217 block_text)
218 state_machine.document.note_pending(pending)
219 return [pending]
220 else:
221 error = state_machine.reporter.error(
222 'Invalid class attribute value for "%s" directive: %s'
223 % (name, arguments[0]),
224 nodes.literal_block(block_text, block_text), line=lineno)
225 return [error]
227 class_directive.arguments = (1, 0, 0)
228 class_directive.content = 1
230 def directive_test_function(name, arguments, options, content, lineno,
231 content_offset, block_text, state, state_machine):
232 if content:
233 text = '\n'.join(content)
234 info = state_machine.reporter.info(
235 'Directive processed. Type="%s", arguments=%r, options=%r, '
236 'content:' % (name, arguments, options),
237 nodes.literal_block(text, text), line=lineno)
238 else:
239 info = state_machine.reporter.info(
240 'Directive processed. Type="%s", arguments=%r, options=%r, '
241 'content: None' % (name, arguments, options), line=lineno)
242 return [info]
244 directive_test_function.arguments = (0, 1, 1)
245 directive_test_function.options = {'option': directives.unchanged_required}
246 directive_test_function.content = 1