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