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