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