##// END OF EJS Templates
minirst: support line blocks
Martin Geisler -
r10447:e957cc7c default
parent child Browse files
Show More
@@ -1,361 +1,366 b''
1 # minirst.py - minimal reStructuredText parser
1 # minirst.py - minimal reStructuredText parser
2 #
2 #
3 # Copyright 2009, 2010 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2009, 2010 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """simplified reStructuredText parser.
8 """simplified reStructuredText parser.
9
9
10 This parser knows just enough about reStructuredText to parse the
10 This parser knows just enough about reStructuredText to parse the
11 Mercurial docstrings.
11 Mercurial docstrings.
12
12
13 It cheats in a major way: nested blocks are not really nested. They
13 It cheats in a major way: nested blocks are not really nested. They
14 are just indented blocks that look like they are nested. This relies
14 are just indented blocks that look like they are nested. This relies
15 on the user to keep the right indentation for the blocks.
15 on the user to keep the right indentation for the blocks.
16
16
17 It only supports a small subset of reStructuredText:
17 It only supports a small subset of reStructuredText:
18
18
19 - sections
19 - sections
20
20
21 - paragraphs
21 - paragraphs
22
22
23 - literal blocks
23 - literal blocks
24
24
25 - definition lists
25 - definition lists
26
26
27 - bullet lists (items must start with '-')
27 - bullet lists (items must start with '-')
28
28
29 - enumerated lists (no autonumbering)
29 - enumerated lists (no autonumbering)
30
30
31 - field lists (colons cannot be escaped)
31 - field lists (colons cannot be escaped)
32
32
33 - option lists (supports only long options without arguments)
33 - option lists (supports only long options without arguments)
34
34
35 - inline literals (no other inline markup is not recognized)
35 - inline literals (no other inline markup is not recognized)
36 """
36 """
37
37
38 import re, sys, textwrap
38 import re, sys, textwrap
39
39
40
40
41 def findblocks(text):
41 def findblocks(text):
42 """Find continuous blocks of lines in text.
42 """Find continuous blocks of lines in text.
43
43
44 Returns a list of dictionaries representing the blocks. Each block
44 Returns a list of dictionaries representing the blocks. Each block
45 has an 'indent' field and a 'lines' field.
45 has an 'indent' field and a 'lines' field.
46 """
46 """
47 blocks = [[]]
47 blocks = [[]]
48 lines = text.splitlines()
48 lines = text.splitlines()
49 for line in lines:
49 for line in lines:
50 if line.strip():
50 if line.strip():
51 blocks[-1].append(line)
51 blocks[-1].append(line)
52 elif blocks[-1]:
52 elif blocks[-1]:
53 blocks.append([])
53 blocks.append([])
54 if not blocks[-1]:
54 if not blocks[-1]:
55 del blocks[-1]
55 del blocks[-1]
56
56
57 for i, block in enumerate(blocks):
57 for i, block in enumerate(blocks):
58 indent = min((len(l) - len(l.lstrip())) for l in block)
58 indent = min((len(l) - len(l.lstrip())) for l in block)
59 blocks[i] = dict(indent=indent, lines=[l[indent:] for l in block])
59 blocks[i] = dict(indent=indent, lines=[l[indent:] for l in block])
60 return blocks
60 return blocks
61
61
62
62
63 def findliteralblocks(blocks):
63 def findliteralblocks(blocks):
64 """Finds literal blocks and adds a 'type' field to the blocks.
64 """Finds literal blocks and adds a 'type' field to the blocks.
65
65
66 Literal blocks are given the type 'literal', all other blocks are
66 Literal blocks are given the type 'literal', all other blocks are
67 given type the 'paragraph'.
67 given type the 'paragraph'.
68 """
68 """
69 i = 0
69 i = 0
70 while i < len(blocks):
70 while i < len(blocks):
71 # Searching for a block that looks like this:
71 # Searching for a block that looks like this:
72 #
72 #
73 # +------------------------------+
73 # +------------------------------+
74 # | paragraph |
74 # | paragraph |
75 # | (ends with "::") |
75 # | (ends with "::") |
76 # +------------------------------+
76 # +------------------------------+
77 # +---------------------------+
77 # +---------------------------+
78 # | indented literal block |
78 # | indented literal block |
79 # +---------------------------+
79 # +---------------------------+
80 blocks[i]['type'] = 'paragraph'
80 blocks[i]['type'] = 'paragraph'
81 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
81 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
82 indent = blocks[i]['indent']
82 indent = blocks[i]['indent']
83 adjustment = blocks[i + 1]['indent'] - indent
83 adjustment = blocks[i + 1]['indent'] - indent
84
84
85 if blocks[i]['lines'] == ['::']:
85 if blocks[i]['lines'] == ['::']:
86 # Expanded form: remove block
86 # Expanded form: remove block
87 del blocks[i]
87 del blocks[i]
88 i -= 1
88 i -= 1
89 elif blocks[i]['lines'][-1].endswith(' ::'):
89 elif blocks[i]['lines'][-1].endswith(' ::'):
90 # Partially minimized form: remove space and both
90 # Partially minimized form: remove space and both
91 # colons.
91 # colons.
92 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
92 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
93 else:
93 else:
94 # Fully minimized form: remove just one colon.
94 # Fully minimized form: remove just one colon.
95 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
95 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
96
96
97 # List items are formatted with a hanging indent. We must
97 # List items are formatted with a hanging indent. We must
98 # correct for this here while we still have the original
98 # correct for this here while we still have the original
99 # information on the indentation of the subsequent literal
99 # information on the indentation of the subsequent literal
100 # blocks available.
100 # blocks available.
101 m = _bulletre.match(blocks[i]['lines'][0])
101 m = _bulletre.match(blocks[i]['lines'][0])
102 if m:
102 if m:
103 indent += m.end()
103 indent += m.end()
104 adjustment -= m.end()
104 adjustment -= m.end()
105
105
106 # Mark the following indented blocks.
106 # Mark the following indented blocks.
107 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
107 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
108 blocks[i + 1]['type'] = 'literal'
108 blocks[i + 1]['type'] = 'literal'
109 blocks[i + 1]['indent'] -= adjustment
109 blocks[i + 1]['indent'] -= adjustment
110 i += 1
110 i += 1
111 i += 1
111 i += 1
112 return blocks
112 return blocks
113
113
114 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)) ')
114 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
115 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
115 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
116 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
116 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
117 _definitionre = re.compile(r'[^ ]')
117 _definitionre = re.compile(r'[^ ]')
118
118
119 def splitparagraphs(blocks):
119 def splitparagraphs(blocks):
120 """Split paragraphs into lists."""
120 """Split paragraphs into lists."""
121 # Tuples with (list type, item regexp, single line items?). Order
121 # Tuples with (list type, item regexp, single line items?). Order
122 # matters: definition lists has the least specific regexp and must
122 # matters: definition lists has the least specific regexp and must
123 # come last.
123 # come last.
124 listtypes = [('bullet', _bulletre, True),
124 listtypes = [('bullet', _bulletre, True),
125 ('option', _optionre, True),
125 ('option', _optionre, True),
126 ('field', _fieldre, True),
126 ('field', _fieldre, True),
127 ('definition', _definitionre, False)]
127 ('definition', _definitionre, False)]
128
128
129 def match(lines, i, itemre, singleline):
129 def match(lines, i, itemre, singleline):
130 """Does itemre match an item at line i?
130 """Does itemre match an item at line i?
131
131
132 A list item can be followed by an idented line or another list
132 A list item can be followed by an idented line or another list
133 item (but only if singleline is True).
133 item (but only if singleline is True).
134 """
134 """
135 line1 = lines[i]
135 line1 = lines[i]
136 line2 = i + 1 < len(lines) and lines[i + 1] or ''
136 line2 = i + 1 < len(lines) and lines[i + 1] or ''
137 if not itemre.match(line1):
137 if not itemre.match(line1):
138 return False
138 return False
139 if singleline:
139 if singleline:
140 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
140 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
141 else:
141 else:
142 return line2.startswith(' ')
142 return line2.startswith(' ')
143
143
144 i = 0
144 i = 0
145 while i < len(blocks):
145 while i < len(blocks):
146 if blocks[i]['type'] == 'paragraph':
146 if blocks[i]['type'] == 'paragraph':
147 lines = blocks[i]['lines']
147 lines = blocks[i]['lines']
148 for type, itemre, singleline in listtypes:
148 for type, itemre, singleline in listtypes:
149 if match(lines, 0, itemre, singleline):
149 if match(lines, 0, itemre, singleline):
150 items = []
150 items = []
151 for j, line in enumerate(lines):
151 for j, line in enumerate(lines):
152 if match(lines, j, itemre, singleline):
152 if match(lines, j, itemre, singleline):
153 items.append(dict(type=type, lines=[],
153 items.append(dict(type=type, lines=[],
154 indent=blocks[i]['indent']))
154 indent=blocks[i]['indent']))
155 items[-1]['lines'].append(line)
155 items[-1]['lines'].append(line)
156 blocks[i:i + 1] = items
156 blocks[i:i + 1] = items
157 break
157 break
158 i += 1
158 i += 1
159 return blocks
159 return blocks
160
160
161
161
162 _fieldwidth = 12
162 _fieldwidth = 12
163
163
164 def updatefieldlists(blocks):
164 def updatefieldlists(blocks):
165 """Find key and maximum key width for field lists."""
165 """Find key and maximum key width for field lists."""
166 i = 0
166 i = 0
167 while i < len(blocks):
167 while i < len(blocks):
168 if blocks[i]['type'] != 'field':
168 if blocks[i]['type'] != 'field':
169 i += 1
169 i += 1
170 continue
170 continue
171
171
172 keywidth = 0
172 keywidth = 0
173 j = i
173 j = i
174 while j < len(blocks) and blocks[j]['type'] == 'field':
174 while j < len(blocks) and blocks[j]['type'] == 'field':
175 m = _fieldre.match(blocks[j]['lines'][0])
175 m = _fieldre.match(blocks[j]['lines'][0])
176 key, rest = m.groups()
176 key, rest = m.groups()
177 blocks[j]['lines'][0] = rest
177 blocks[j]['lines'][0] = rest
178 blocks[j]['key'] = key
178 blocks[j]['key'] = key
179 keywidth = max(keywidth, len(key))
179 keywidth = max(keywidth, len(key))
180 j += 1
180 j += 1
181
181
182 for block in blocks[i:j]:
182 for block in blocks[i:j]:
183 block['keywidth'] = keywidth
183 block['keywidth'] = keywidth
184 i = j + 1
184 i = j + 1
185
185
186 return blocks
186 return blocks
187
187
188
188
189 def prunecontainers(blocks, keep):
189 def prunecontainers(blocks, keep):
190 """Prune unwanted containers.
190 """Prune unwanted containers.
191
191
192 The blocks must have a 'type' field, i.e., they should have been
192 The blocks must have a 'type' field, i.e., they should have been
193 run through findliteralblocks first.
193 run through findliteralblocks first.
194 """
194 """
195 pruned = []
195 pruned = []
196 i = 0
196 i = 0
197 while i + 1 < len(blocks):
197 while i + 1 < len(blocks):
198 # Searching for a block that looks like this:
198 # Searching for a block that looks like this:
199 #
199 #
200 # +-------+---------------------------+
200 # +-------+---------------------------+
201 # | ".. container ::" type |
201 # | ".. container ::" type |
202 # +---+ |
202 # +---+ |
203 # | blocks |
203 # | blocks |
204 # +-------------------------------+
204 # +-------------------------------+
205 if (blocks[i]['type'] == 'paragraph' and
205 if (blocks[i]['type'] == 'paragraph' and
206 blocks[i]['lines'][0].startswith('.. container::')):
206 blocks[i]['lines'][0].startswith('.. container::')):
207 indent = blocks[i]['indent']
207 indent = blocks[i]['indent']
208 adjustment = blocks[i + 1]['indent'] - indent
208 adjustment = blocks[i + 1]['indent'] - indent
209 containertype = blocks[i]['lines'][0][15:]
209 containertype = blocks[i]['lines'][0][15:]
210 prune = containertype not in keep
210 prune = containertype not in keep
211 if prune:
211 if prune:
212 pruned.append(containertype)
212 pruned.append(containertype)
213
213
214 # Always delete "..container:: type" block
214 # Always delete "..container:: type" block
215 del blocks[i]
215 del blocks[i]
216 j = i
216 j = i
217 while j < len(blocks) and blocks[j]['indent'] > indent:
217 while j < len(blocks) and blocks[j]['indent'] > indent:
218 if prune:
218 if prune:
219 del blocks[j]
219 del blocks[j]
220 i -= 1 # adjust outer index
220 i -= 1 # adjust outer index
221 else:
221 else:
222 blocks[j]['indent'] -= adjustment
222 blocks[j]['indent'] -= adjustment
223 j += 1
223 j += 1
224 i += 1
224 i += 1
225 return blocks, pruned
225 return blocks, pruned
226
226
227
227
228 def findsections(blocks):
228 def findsections(blocks):
229 """Finds sections.
229 """Finds sections.
230
230
231 The blocks must have a 'type' field, i.e., they should have been
231 The blocks must have a 'type' field, i.e., they should have been
232 run through findliteralblocks first.
232 run through findliteralblocks first.
233 """
233 """
234 for block in blocks:
234 for block in blocks:
235 # Searching for a block that looks like this:
235 # Searching for a block that looks like this:
236 #
236 #
237 # +------------------------------+
237 # +------------------------------+
238 # | Section title |
238 # | Section title |
239 # | ------------- |
239 # | ------------- |
240 # +------------------------------+
240 # +------------------------------+
241 if (block['type'] == 'paragraph' and
241 if (block['type'] == 'paragraph' and
242 len(block['lines']) == 2 and
242 len(block['lines']) == 2 and
243 block['lines'][1] == '-' * len(block['lines'][0])):
243 block['lines'][1] == '-' * len(block['lines'][0])):
244 block['type'] = 'section'
244 block['type'] = 'section'
245 return blocks
245 return blocks
246
246
247
247
248 def inlineliterals(blocks):
248 def inlineliterals(blocks):
249 for b in blocks:
249 for b in blocks:
250 if b['type'] == 'paragraph':
250 if b['type'] == 'paragraph':
251 b['lines'] = [l.replace('``', '"') for l in b['lines']]
251 b['lines'] = [l.replace('``', '"') for l in b['lines']]
252 return blocks
252 return blocks
253
253
254
254
255 def addmargins(blocks):
255 def addmargins(blocks):
256 """Adds empty blocks for vertical spacing.
256 """Adds empty blocks for vertical spacing.
257
257
258 This groups bullets, options, and definitions together with no vertical
258 This groups bullets, options, and definitions together with no vertical
259 space between them, and adds an empty block between all other blocks.
259 space between them, and adds an empty block between all other blocks.
260 """
260 """
261 i = 1
261 i = 1
262 while i < len(blocks):
262 while i < len(blocks):
263 if (blocks[i]['type'] == blocks[i - 1]['type'] and
263 if (blocks[i]['type'] == blocks[i - 1]['type'] and
264 blocks[i]['type'] in ('bullet', 'option', 'field', 'definition')):
264 blocks[i]['type'] in ('bullet', 'option', 'field', 'definition')):
265 i += 1
265 i += 1
266 else:
266 else:
267 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
267 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
268 i += 2
268 i += 2
269 return blocks
269 return blocks
270
270
271
271
272 def formatblock(block, width):
272 def formatblock(block, width):
273 """Format a block according to width."""
273 """Format a block according to width."""
274 if width <= 0:
274 if width <= 0:
275 width = 78
275 width = 78
276 indent = ' ' * block['indent']
276 indent = ' ' * block['indent']
277 if block['type'] == 'margin':
277 if block['type'] == 'margin':
278 return ''
278 return ''
279 if block['type'] == 'literal':
279 if block['type'] == 'literal':
280 indent += ' '
280 indent += ' '
281 return indent + ('\n' + indent).join(block['lines'])
281 return indent + ('\n' + indent).join(block['lines'])
282 if block['type'] == 'section':
282 if block['type'] == 'section':
283 return indent + ('\n' + indent).join(block['lines'])
283 return indent + ('\n' + indent).join(block['lines'])
284 if block['type'] == 'definition':
284 if block['type'] == 'definition':
285 term = indent + block['lines'][0]
285 term = indent + block['lines'][0]
286 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
286 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
287 defindent = indent + hang * ' '
287 defindent = indent + hang * ' '
288 text = ' '.join(map(str.strip, block['lines'][1:]))
288 text = ' '.join(map(str.strip, block['lines'][1:]))
289 return "%s\n%s" % (term, textwrap.fill(text, width=width,
289 return "%s\n%s" % (term, textwrap.fill(text, width=width,
290 initial_indent=defindent,
290 initial_indent=defindent,
291 subsequent_indent=defindent))
291 subsequent_indent=defindent))
292 initindent = subindent = indent
292 initindent = subindent = indent
293 if block['type'] == 'bullet':
293 if block['type'] == 'bullet':
294 m = _bulletre.match(block['lines'][0])
294 if block['lines'][0].startswith('| '):
295 subindent = indent + m.end() * ' '
295 # Remove bullet for line blocks and add no extra
296 # indention.
297 block['lines'][0] = block['lines'][0][2:]
298 else:
299 m = _bulletre.match(block['lines'][0])
300 subindent = indent + m.end() * ' '
296 elif block['type'] == 'field':
301 elif block['type'] == 'field':
297 keywidth = block['keywidth']
302 keywidth = block['keywidth']
298 key = block['key']
303 key = block['key']
299
304
300 subindent = indent + _fieldwidth * ' '
305 subindent = indent + _fieldwidth * ' '
301 if len(key) + 2 > _fieldwidth:
306 if len(key) + 2 > _fieldwidth:
302 # key too large, use full line width
307 # key too large, use full line width
303 key = key.ljust(width)
308 key = key.ljust(width)
304 elif keywidth + 2 < _fieldwidth:
309 elif keywidth + 2 < _fieldwidth:
305 # all keys are small, add only two spaces
310 # all keys are small, add only two spaces
306 key = key.ljust(keywidth + 2)
311 key = key.ljust(keywidth + 2)
307 subindent = indent + (keywidth + 2) * ' '
312 subindent = indent + (keywidth + 2) * ' '
308 else:
313 else:
309 # mixed sizes, use fieldwidth for this one
314 # mixed sizes, use fieldwidth for this one
310 key = key.ljust(_fieldwidth)
315 key = key.ljust(_fieldwidth)
311 block['lines'][0] = key + block['lines'][0]
316 block['lines'][0] = key + block['lines'][0]
312 elif block['type'] == 'option':
317 elif block['type'] == 'option':
313 m = _optionre.match(block['lines'][0])
318 m = _optionre.match(block['lines'][0])
314 option, arg, rest = m.groups()
319 option, arg, rest = m.groups()
315 subindent = indent + (len(option) + len(arg)) * ' '
320 subindent = indent + (len(option) + len(arg)) * ' '
316
321
317 text = ' '.join(map(str.strip, block['lines']))
322 text = ' '.join(map(str.strip, block['lines']))
318 return textwrap.fill(text, width=width,
323 return textwrap.fill(text, width=width,
319 initial_indent=initindent,
324 initial_indent=initindent,
320 subsequent_indent=subindent)
325 subsequent_indent=subindent)
321
326
322
327
323 def format(text, width, indent=0, keep=None):
328 def format(text, width, indent=0, keep=None):
324 """Parse and format the text according to width."""
329 """Parse and format the text according to width."""
325 blocks = findblocks(text)
330 blocks = findblocks(text)
326 for b in blocks:
331 for b in blocks:
327 b['indent'] += indent
332 b['indent'] += indent
328 blocks = findliteralblocks(blocks)
333 blocks = findliteralblocks(blocks)
329 blocks, pruned = prunecontainers(blocks, keep or [])
334 blocks, pruned = prunecontainers(blocks, keep or [])
330 blocks = inlineliterals(blocks)
335 blocks = inlineliterals(blocks)
331 blocks = splitparagraphs(blocks)
336 blocks = splitparagraphs(blocks)
332 blocks = updatefieldlists(blocks)
337 blocks = updatefieldlists(blocks)
333 blocks = findsections(blocks)
338 blocks = findsections(blocks)
334 blocks = addmargins(blocks)
339 blocks = addmargins(blocks)
335 text = '\n'.join(formatblock(b, width) for b in blocks)
340 text = '\n'.join(formatblock(b, width) for b in blocks)
336 if keep is None:
341 if keep is None:
337 return text
342 return text
338 else:
343 else:
339 return text, pruned
344 return text, pruned
340
345
341
346
342 if __name__ == "__main__":
347 if __name__ == "__main__":
343 from pprint import pprint
348 from pprint import pprint
344
349
345 def debug(func, *args):
350 def debug(func, *args):
346 blocks = func(*args)
351 blocks = func(*args)
347 print "*** after %s:" % func.__name__
352 print "*** after %s:" % func.__name__
348 pprint(blocks)
353 pprint(blocks)
349 print
354 print
350 return blocks
355 return blocks
351
356
352 text = open(sys.argv[1]).read()
357 text = open(sys.argv[1]).read()
353 blocks = debug(findblocks, text)
358 blocks = debug(findblocks, text)
354 blocks = debug(findliteralblocks, blocks)
359 blocks = debug(findliteralblocks, blocks)
355 blocks = debug(prunecontainers, blocks, sys.argv[2:])
360 blocks = debug(prunecontainers, blocks, sys.argv[2:])
356 blocks = debug(inlineliterals, blocks)
361 blocks = debug(inlineliterals, blocks)
357 blocks = debug(splitparagraphs, blocks)
362 blocks = debug(splitparagraphs, blocks)
358 blocks = debug(updatefieldlists, blocks)
363 blocks = debug(updatefieldlists, blocks)
359 blocks = debug(findsections, blocks)
364 blocks = debug(findsections, blocks)
360 blocks = debug(addmargins, blocks)
365 blocks = debug(addmargins, blocks)
361 print '\n'.join(formatblock(b, 30) for b in blocks)
366 print '\n'.join(formatblock(b, 30) for b in blocks)
@@ -1,174 +1,180 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 from pprint import pprint
3 from pprint import pprint
4 from mercurial import minirst
4 from mercurial import minirst
5
5
6 def debugformat(title, text, width, **kwargs):
6 def debugformat(title, text, width, **kwargs):
7 print "%s formatted to fit within %d characters:" % (title, width)
7 print "%s formatted to fit within %d characters:" % (title, width)
8 print "-" * 70
8 print "-" * 70
9 formatted = minirst.format(text, width, **kwargs)
9 formatted = minirst.format(text, width, **kwargs)
10 if type(formatted) == tuple:
10 if type(formatted) == tuple:
11 print formatted[0]
11 print formatted[0]
12 print "-" * 70
12 print "-" * 70
13 pprint(formatted[1])
13 pprint(formatted[1])
14 else:
14 else:
15 print formatted
15 print formatted
16 print "-" * 70
16 print "-" * 70
17 print
17 print
18
18
19 paragraphs = """
19 paragraphs = """
20 This is some text in the first paragraph.
20 This is some text in the first paragraph.
21
21
22 A small indented paragraph.
22 A small indented paragraph.
23 It is followed by some lines
23 It is followed by some lines
24 containing random whitespace.
24 containing random whitespace.
25 \n \n \nThe third and final paragraph.
25 \n \n \nThe third and final paragraph.
26 """
26 """
27
27
28 debugformat('paragraphs', paragraphs, 60)
28 debugformat('paragraphs', paragraphs, 60)
29 debugformat('paragraphs', paragraphs, 30)
29 debugformat('paragraphs', paragraphs, 30)
30
30
31
31
32 definitions = """
32 definitions = """
33 A Term
33 A Term
34 Definition. The indented
34 Definition. The indented
35 lines make up the definition.
35 lines make up the definition.
36 Another Term
36 Another Term
37 Another definition. The final line in the
37 Another definition. The final line in the
38 definition determines the indentation, so
38 definition determines the indentation, so
39 this will be indented with four spaces.
39 this will be indented with four spaces.
40
40
41 A Nested/Indented Term
41 A Nested/Indented Term
42 Definition.
42 Definition.
43 """
43 """
44
44
45 debugformat('definitions', definitions, 60)
45 debugformat('definitions', definitions, 60)
46 debugformat('definitions', definitions, 30)
46 debugformat('definitions', definitions, 30)
47
47
48
48
49 literals = r"""
49 literals = r"""
50 The fully minimized form is the most
50 The fully minimized form is the most
51 convenient form::
51 convenient form::
52
52
53 Hello
53 Hello
54 literal
54 literal
55 world
55 world
56
56
57 In the partially minimized form a paragraph
57 In the partially minimized form a paragraph
58 simply ends with space-double-colon. ::
58 simply ends with space-double-colon. ::
59
59
60 ////////////////////////////////////////
60 ////////////////////////////////////////
61 long un-wrapped line in a literal block
61 long un-wrapped line in a literal block
62 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
62 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
63
63
64 ::
64 ::
65
65
66 This literal block is started with '::',
66 This literal block is started with '::',
67 the so-called expanded form. The paragraph
67 the so-called expanded form. The paragraph
68 with '::' disappears in the final output.
68 with '::' disappears in the final output.
69 """
69 """
70
70
71 debugformat('literals', literals, 60)
71 debugformat('literals', literals, 60)
72 debugformat('literals', literals, 30)
72 debugformat('literals', literals, 30)
73
73
74
74
75 lists = """
75 lists = """
76 - This is the first list item.
76 - This is the first list item.
77
77
78 Second paragraph in the first list item.
78 Second paragraph in the first list item.
79
79
80 - List items need not be separated
80 - List items need not be separated
81 by a blank line.
81 by a blank line.
82 - And will be rendered without
82 - And will be rendered without
83 one in any case.
83 one in any case.
84
84
85 We can have indented lists:
85 We can have indented lists:
86
86
87 - This is an indented list item
87 - This is an indented list item
88
88
89 - Another indented list item::
89 - Another indented list item::
90
90
91 - A literal block in the middle
91 - A literal block in the middle
92 of an indented list.
92 of an indented list.
93
93
94 (The above is not a list item since we are in the literal block.)
94 (The above is not a list item since we are in the literal block.)
95
95
96 ::
96 ::
97
97
98 Literal block with no indentation (apart from
98 Literal block with no indentation (apart from
99 the two spaces added to all literal blocks).
99 the two spaces added to all literal blocks).
100
100
101 1. This is an enumerated list (first item).
101 1. This is an enumerated list (first item).
102 2. Continuing with the second item.
102 2. Continuing with the second item.
103
103
104 (1) foo
104 (1) foo
105 (2) bar
105 (2) bar
106
106
107 1) Another
107 1) Another
108 2) List
108 2) List
109
110 Line blocks are also a form of list:
111
112 | This is the first line.
113 The line continues here.
114 | This is the second line.
109 """
115 """
110
116
111 debugformat('lists', lists, 60)
117 debugformat('lists', lists, 60)
112 debugformat('lists', lists, 30)
118 debugformat('lists', lists, 30)
113
119
114
120
115 options = """
121 options = """
116 There is support for simple option lists,
122 There is support for simple option lists,
117 but only with long options:
123 but only with long options:
118
124
119 --all Output all.
125 --all Output all.
120 --both Output both (this description is
126 --both Output both (this description is
121 quite long).
127 quite long).
122 --long Output all day long.
128 --long Output all day long.
123
129
124 --par This option has two paragraphs in its description.
130 --par This option has two paragraphs in its description.
125 This is the first.
131 This is the first.
126
132
127 This is the second. Blank lines may be omitted between
133 This is the second. Blank lines may be omitted between
128 options (as above) or left in (as here).
134 options (as above) or left in (as here).
129
135
130 The next paragraph looks like an option list, but lacks the two-space
136 The next paragraph looks like an option list, but lacks the two-space
131 marker after the option. It is treated as a normal paragraph:
137 marker after the option. It is treated as a normal paragraph:
132
138
133 --foo bar baz
139 --foo bar baz
134 """
140 """
135
141
136 debugformat('options', options, 60)
142 debugformat('options', options, 60)
137 debugformat('options', options, 30)
143 debugformat('options', options, 30)
138
144
139
145
140 fields = """
146 fields = """
141 :a: First item.
147 :a: First item.
142 :ab: Second item. Indentation and wrapping
148 :ab: Second item. Indentation and wrapping
143 is handled automatically.
149 is handled automatically.
144
150
145 Next list:
151 Next list:
146
152
147 :small: The larger key below triggers full indentation here.
153 :small: The larger key below triggers full indentation here.
148 :much too large: This key is big enough to get its own line.
154 :much too large: This key is big enough to get its own line.
149 """
155 """
150
156
151 debugformat('fields', fields, 60)
157 debugformat('fields', fields, 60)
152 debugformat('fields', fields, 30)
158 debugformat('fields', fields, 30)
153
159
154 containers = """
160 containers = """
155 Normal output.
161 Normal output.
156
162
157 .. container:: debug
163 .. container:: debug
158
164
159 Initial debug output.
165 Initial debug output.
160
166
161 .. container:: verbose
167 .. container:: verbose
162
168
163 Verbose output.
169 Verbose output.
164
170
165 .. container:: debug
171 .. container:: debug
166
172
167 Debug output.
173 Debug output.
168 """
174 """
169
175
170 debugformat('containers (normal)', containers, 60)
176 debugformat('containers (normal)', containers, 60)
171 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
177 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
172 debugformat('containers (debug)', containers, 60, keep=['debug'])
178 debugformat('containers (debug)', containers, 60, keep=['debug'])
173 debugformat('containers (verbose debug)', containers, 60,
179 debugformat('containers (verbose debug)', containers, 60,
174 keep=['verbose', 'debug'])
180 keep=['verbose', 'debug'])
@@ -1,284 +1,296 b''
1 paragraphs formatted to fit within 60 characters:
1 paragraphs formatted to fit within 60 characters:
2 ----------------------------------------------------------------------
2 ----------------------------------------------------------------------
3 This is some text in the first paragraph.
3 This is some text in the first paragraph.
4
4
5 A small indented paragraph. It is followed by some lines
5 A small indented paragraph. It is followed by some lines
6 containing random whitespace.
6 containing random whitespace.
7
7
8 The third and final paragraph.
8 The third and final paragraph.
9 ----------------------------------------------------------------------
9 ----------------------------------------------------------------------
10
10
11 paragraphs formatted to fit within 30 characters:
11 paragraphs formatted to fit within 30 characters:
12 ----------------------------------------------------------------------
12 ----------------------------------------------------------------------
13 This is some text in the first
13 This is some text in the first
14 paragraph.
14 paragraph.
15
15
16 A small indented paragraph.
16 A small indented paragraph.
17 It is followed by some lines
17 It is followed by some lines
18 containing random
18 containing random
19 whitespace.
19 whitespace.
20
20
21 The third and final paragraph.
21 The third and final paragraph.
22 ----------------------------------------------------------------------
22 ----------------------------------------------------------------------
23
23
24 definitions formatted to fit within 60 characters:
24 definitions formatted to fit within 60 characters:
25 ----------------------------------------------------------------------
25 ----------------------------------------------------------------------
26 A Term
26 A Term
27 Definition. The indented lines make up the definition.
27 Definition. The indented lines make up the definition.
28 Another Term
28 Another Term
29 Another definition. The final line in the definition
29 Another definition. The final line in the definition
30 determines the indentation, so this will be indented
30 determines the indentation, so this will be indented
31 with four spaces.
31 with four spaces.
32 A Nested/Indented Term
32 A Nested/Indented Term
33 Definition.
33 Definition.
34 ----------------------------------------------------------------------
34 ----------------------------------------------------------------------
35
35
36 definitions formatted to fit within 30 characters:
36 definitions formatted to fit within 30 characters:
37 ----------------------------------------------------------------------
37 ----------------------------------------------------------------------
38 A Term
38 A Term
39 Definition. The indented
39 Definition. The indented
40 lines make up the
40 lines make up the
41 definition.
41 definition.
42 Another Term
42 Another Term
43 Another definition. The
43 Another definition. The
44 final line in the
44 final line in the
45 definition determines the
45 definition determines the
46 indentation, so this will
46 indentation, so this will
47 be indented with four
47 be indented with four
48 spaces.
48 spaces.
49 A Nested/Indented Term
49 A Nested/Indented Term
50 Definition.
50 Definition.
51 ----------------------------------------------------------------------
51 ----------------------------------------------------------------------
52
52
53 literals formatted to fit within 60 characters:
53 literals formatted to fit within 60 characters:
54 ----------------------------------------------------------------------
54 ----------------------------------------------------------------------
55 The fully minimized form is the most convenient form:
55 The fully minimized form is the most convenient form:
56
56
57 Hello
57 Hello
58 literal
58 literal
59 world
59 world
60
60
61 In the partially minimized form a paragraph simply ends with
61 In the partially minimized form a paragraph simply ends with
62 space-double-colon.
62 space-double-colon.
63
63
64 ////////////////////////////////////////
64 ////////////////////////////////////////
65 long un-wrapped line in a literal block
65 long un-wrapped line in a literal block
66 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
66 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
67
67
68 This literal block is started with '::',
68 This literal block is started with '::',
69 the so-called expanded form. The paragraph
69 the so-called expanded form. The paragraph
70 with '::' disappears in the final output.
70 with '::' disappears in the final output.
71 ----------------------------------------------------------------------
71 ----------------------------------------------------------------------
72
72
73 literals formatted to fit within 30 characters:
73 literals formatted to fit within 30 characters:
74 ----------------------------------------------------------------------
74 ----------------------------------------------------------------------
75 The fully minimized form is
75 The fully minimized form is
76 the most convenient form:
76 the most convenient form:
77
77
78 Hello
78 Hello
79 literal
79 literal
80 world
80 world
81
81
82 In the partially minimized
82 In the partially minimized
83 form a paragraph simply ends
83 form a paragraph simply ends
84 with space-double-colon.
84 with space-double-colon.
85
85
86 ////////////////////////////////////////
86 ////////////////////////////////////////
87 long un-wrapped line in a literal block
87 long un-wrapped line in a literal block
88 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
88 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
89
89
90 This literal block is started with '::',
90 This literal block is started with '::',
91 the so-called expanded form. The paragraph
91 the so-called expanded form. The paragraph
92 with '::' disappears in the final output.
92 with '::' disappears in the final output.
93 ----------------------------------------------------------------------
93 ----------------------------------------------------------------------
94
94
95 lists formatted to fit within 60 characters:
95 lists formatted to fit within 60 characters:
96 ----------------------------------------------------------------------
96 ----------------------------------------------------------------------
97 - This is the first list item.
97 - This is the first list item.
98
98
99 Second paragraph in the first list item.
99 Second paragraph in the first list item.
100
100
101 - List items need not be separated by a blank line.
101 - List items need not be separated by a blank line.
102 - And will be rendered without one in any case.
102 - And will be rendered without one in any case.
103
103
104 We can have indented lists:
104 We can have indented lists:
105
105
106 - This is an indented list item
106 - This is an indented list item
107 - Another indented list item:
107 - Another indented list item:
108
108
109 - A literal block in the middle
109 - A literal block in the middle
110 of an indented list.
110 of an indented list.
111
111
112 (The above is not a list item since we are in the literal block.)
112 (The above is not a list item since we are in the literal block.)
113
113
114 Literal block with no indentation (apart from
114 Literal block with no indentation (apart from
115 the two spaces added to all literal blocks).
115 the two spaces added to all literal blocks).
116
116
117 1. This is an enumerated list (first item).
117 1. This is an enumerated list (first item).
118 2. Continuing with the second item.
118 2. Continuing with the second item.
119 (1) foo
119 (1) foo
120 (2) bar
120 (2) bar
121 1) Another
121 1) Another
122 2) List
122 2) List
123
124 Line blocks are also a form of list:
125
126 This is the first line. The line continues here.
127 This is the second line.
123 ----------------------------------------------------------------------
128 ----------------------------------------------------------------------
124
129
125 lists formatted to fit within 30 characters:
130 lists formatted to fit within 30 characters:
126 ----------------------------------------------------------------------
131 ----------------------------------------------------------------------
127 - This is the first list item.
132 - This is the first list item.
128
133
129 Second paragraph in the
134 Second paragraph in the
130 first list item.
135 first list item.
131
136
132 - List items need not be
137 - List items need not be
133 separated by a blank line.
138 separated by a blank line.
134 - And will be rendered without
139 - And will be rendered without
135 one in any case.
140 one in any case.
136
141
137 We can have indented lists:
142 We can have indented lists:
138
143
139 - This is an indented list
144 - This is an indented list
140 item
145 item
141 - Another indented list
146 - Another indented list
142 item:
147 item:
143
148
144 - A literal block in the middle
149 - A literal block in the middle
145 of an indented list.
150 of an indented list.
146
151
147 (The above is not a list item since we are in the literal block.)
152 (The above is not a list item since we are in the literal block.)
148
153
149 Literal block with no indentation (apart from
154 Literal block with no indentation (apart from
150 the two spaces added to all literal blocks).
155 the two spaces added to all literal blocks).
151
156
152 1. This is an enumerated list
157 1. This is an enumerated list
153 (first item).
158 (first item).
154 2. Continuing with the second
159 2. Continuing with the second
155 item.
160 item.
156 (1) foo
161 (1) foo
157 (2) bar
162 (2) bar
158 1) Another
163 1) Another
159 2) List
164 2) List
165
166 Line blocks are also a form of
167 list:
168
169 This is the first line. The
170 line continues here.
171 This is the second line.
160 ----------------------------------------------------------------------
172 ----------------------------------------------------------------------
161
173
162 options formatted to fit within 60 characters:
174 options formatted to fit within 60 characters:
163 ----------------------------------------------------------------------
175 ----------------------------------------------------------------------
164 There is support for simple option lists, but only with long
176 There is support for simple option lists, but only with long
165 options:
177 options:
166
178
167 --all Output all.
179 --all Output all.
168 --both Output both (this description is quite long).
180 --both Output both (this description is quite long).
169 --long Output all day long.
181 --long Output all day long.
170 --par This option has two paragraphs in its
182 --par This option has two paragraphs in its
171 description. This is the first.
183 description. This is the first.
172
184
173 This is the second. Blank lines may be omitted
185 This is the second. Blank lines may be omitted
174 between options (as above) or left in (as here).
186 between options (as above) or left in (as here).
175
187
176 The next paragraph looks like an option list, but lacks the
188 The next paragraph looks like an option list, but lacks the
177 two-space marker after the option. It is treated as a normal
189 two-space marker after the option. It is treated as a normal
178 paragraph:
190 paragraph:
179
191
180 --foo bar baz
192 --foo bar baz
181 ----------------------------------------------------------------------
193 ----------------------------------------------------------------------
182
194
183 options formatted to fit within 30 characters:
195 options formatted to fit within 30 characters:
184 ----------------------------------------------------------------------
196 ----------------------------------------------------------------------
185 There is support for simple
197 There is support for simple
186 option lists, but only with
198 option lists, but only with
187 long options:
199 long options:
188
200
189 --all Output all.
201 --all Output all.
190 --both Output both (this
202 --both Output both (this
191 description is
203 description is
192 quite long).
204 quite long).
193 --long Output all day
205 --long Output all day
194 long.
206 long.
195 --par This option has two
207 --par This option has two
196 paragraphs in its
208 paragraphs in its
197 description. This
209 description. This
198 is the first.
210 is the first.
199
211
200 This is the second.
212 This is the second.
201 Blank lines may be
213 Blank lines may be
202 omitted between
214 omitted between
203 options (as above)
215 options (as above)
204 or left in (as
216 or left in (as
205 here).
217 here).
206
218
207 The next paragraph looks like
219 The next paragraph looks like
208 an option list, but lacks the
220 an option list, but lacks the
209 two-space marker after the
221 two-space marker after the
210 option. It is treated as a
222 option. It is treated as a
211 normal paragraph:
223 normal paragraph:
212
224
213 --foo bar baz
225 --foo bar baz
214 ----------------------------------------------------------------------
226 ----------------------------------------------------------------------
215
227
216 fields formatted to fit within 60 characters:
228 fields formatted to fit within 60 characters:
217 ----------------------------------------------------------------------
229 ----------------------------------------------------------------------
218 a First item.
230 a First item.
219 ab Second item. Indentation and wrapping is handled
231 ab Second item. Indentation and wrapping is handled
220 automatically.
232 automatically.
221
233
222 Next list:
234 Next list:
223
235
224 small The larger key below triggers full indentation
236 small The larger key below triggers full indentation
225 here.
237 here.
226 much too large
238 much too large
227 This key is big enough to get its own line.
239 This key is big enough to get its own line.
228 ----------------------------------------------------------------------
240 ----------------------------------------------------------------------
229
241
230 fields formatted to fit within 30 characters:
242 fields formatted to fit within 30 characters:
231 ----------------------------------------------------------------------
243 ----------------------------------------------------------------------
232 a First item.
244 a First item.
233 ab Second item. Indentation
245 ab Second item. Indentation
234 and wrapping is handled
246 and wrapping is handled
235 automatically.
247 automatically.
236
248
237 Next list:
249 Next list:
238
250
239 small The larger key
251 small The larger key
240 below triggers
252 below triggers
241 full indentation
253 full indentation
242 here.
254 here.
243 much too large
255 much too large
244 This key is big
256 This key is big
245 enough to get its
257 enough to get its
246 own line.
258 own line.
247 ----------------------------------------------------------------------
259 ----------------------------------------------------------------------
248
260
249 containers (normal) formatted to fit within 60 characters:
261 containers (normal) formatted to fit within 60 characters:
250 ----------------------------------------------------------------------
262 ----------------------------------------------------------------------
251 Normal output.
263 Normal output.
252 ----------------------------------------------------------------------
264 ----------------------------------------------------------------------
253
265
254 containers (verbose) formatted to fit within 60 characters:
266 containers (verbose) formatted to fit within 60 characters:
255 ----------------------------------------------------------------------
267 ----------------------------------------------------------------------
256 Normal output.
268 Normal output.
257
269
258 Verbose output.
270 Verbose output.
259 ----------------------------------------------------------------------
271 ----------------------------------------------------------------------
260 ['debug', 'debug']
272 ['debug', 'debug']
261 ----------------------------------------------------------------------
273 ----------------------------------------------------------------------
262
274
263 containers (debug) formatted to fit within 60 characters:
275 containers (debug) formatted to fit within 60 characters:
264 ----------------------------------------------------------------------
276 ----------------------------------------------------------------------
265 Normal output.
277 Normal output.
266
278
267 Initial debug output.
279 Initial debug output.
268 ----------------------------------------------------------------------
280 ----------------------------------------------------------------------
269 ['verbose']
281 ['verbose']
270 ----------------------------------------------------------------------
282 ----------------------------------------------------------------------
271
283
272 containers (verbose debug) formatted to fit within 60 characters:
284 containers (verbose debug) formatted to fit within 60 characters:
273 ----------------------------------------------------------------------
285 ----------------------------------------------------------------------
274 Normal output.
286 Normal output.
275
287
276 Initial debug output.
288 Initial debug output.
277
289
278 Verbose output.
290 Verbose output.
279
291
280 Debug output.
292 Debug output.
281 ----------------------------------------------------------------------
293 ----------------------------------------------------------------------
282 []
294 []
283 ----------------------------------------------------------------------
295 ----------------------------------------------------------------------
284
296
General Comments 0
You need to be logged in to leave comments. Login now