##// END OF EJS Templates
minirst: Support for admonitions...
Erik Zielke -
r12388:75f044d4 default
parent child Browse files
Show More
@@ -1,392 +1,444 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 - specific admonitions
28
27 - bullet lists (items must start with '-')
29 - bullet lists (items must start with '-')
28
30
29 - enumerated lists (no autonumbering)
31 - enumerated lists (no autonumbering)
30
32
31 - field lists (colons cannot be escaped)
33 - field lists (colons cannot be escaped)
32
34
33 - option lists (supports only long options without arguments)
35 - option lists (supports only long options without arguments)
34
36
35 - inline literals (no other inline markup is not recognized)
37 - inline literals (no other inline markup is not recognized)
36 """
38 """
37
39
38 import re, sys
40 import re, sys
39 import util, encoding
41 import util, encoding
42 from i18n import _
43
40
44
41 def replace(text, substs):
45 def replace(text, substs):
42 utext = text.decode(encoding.encoding)
46 utext = text.decode(encoding.encoding)
43 for f, t in substs:
47 for f, t in substs:
44 utext = utext.replace(f, t)
48 utext = utext.replace(f, t)
45 return utext.encode(encoding.encoding)
49 return utext.encode(encoding.encoding)
46
50
47 def findblocks(text):
51 def findblocks(text):
48 """Find continuous blocks of lines in text.
52 """Find continuous blocks of lines in text.
49
53
50 Returns a list of dictionaries representing the blocks. Each block
54 Returns a list of dictionaries representing the blocks. Each block
51 has an 'indent' field and a 'lines' field.
55 has an 'indent' field and a 'lines' field.
52 """
56 """
53 blocks = [[]]
57 blocks = [[]]
54 lines = text.splitlines()
58 lines = text.splitlines()
55 for line in lines:
59 for line in lines:
56 if line.strip():
60 if line.strip():
57 blocks[-1].append(line)
61 blocks[-1].append(line)
58 elif blocks[-1]:
62 elif blocks[-1]:
59 blocks.append([])
63 blocks.append([])
60 if not blocks[-1]:
64 if not blocks[-1]:
61 del blocks[-1]
65 del blocks[-1]
62
66
63 for i, block in enumerate(blocks):
67 for i, block in enumerate(blocks):
64 indent = min((len(l) - len(l.lstrip())) for l in block)
68 indent = min((len(l) - len(l.lstrip())) for l in block)
65 blocks[i] = dict(indent=indent, lines=[l[indent:] for l in block])
69 blocks[i] = dict(indent=indent, lines=[l[indent:] for l in block])
66 return blocks
70 return blocks
67
71
68
72
69 def findliteralblocks(blocks):
73 def findliteralblocks(blocks):
70 """Finds literal blocks and adds a 'type' field to the blocks.
74 """Finds literal blocks and adds a 'type' field to the blocks.
71
75
72 Literal blocks are given the type 'literal', all other blocks are
76 Literal blocks are given the type 'literal', all other blocks are
73 given type the 'paragraph'.
77 given type the 'paragraph'.
74 """
78 """
75 i = 0
79 i = 0
76 while i < len(blocks):
80 while i < len(blocks):
77 # Searching for a block that looks like this:
81 # Searching for a block that looks like this:
78 #
82 #
79 # +------------------------------+
83 # +------------------------------+
80 # | paragraph |
84 # | paragraph |
81 # | (ends with "::") |
85 # | (ends with "::") |
82 # +------------------------------+
86 # +------------------------------+
83 # +---------------------------+
87 # +---------------------------+
84 # | indented literal block |
88 # | indented literal block |
85 # +---------------------------+
89 # +---------------------------+
86 blocks[i]['type'] = 'paragraph'
90 blocks[i]['type'] = 'paragraph'
87 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
91 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
88 indent = blocks[i]['indent']
92 indent = blocks[i]['indent']
89 adjustment = blocks[i + 1]['indent'] - indent
93 adjustment = blocks[i + 1]['indent'] - indent
90
94
91 if blocks[i]['lines'] == ['::']:
95 if blocks[i]['lines'] == ['::']:
92 # Expanded form: remove block
96 # Expanded form: remove block
93 del blocks[i]
97 del blocks[i]
94 i -= 1
98 i -= 1
95 elif blocks[i]['lines'][-1].endswith(' ::'):
99 elif blocks[i]['lines'][-1].endswith(' ::'):
96 # Partially minimized form: remove space and both
100 # Partially minimized form: remove space and both
97 # colons.
101 # colons.
98 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
102 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
99 else:
103 else:
100 # Fully minimized form: remove just one colon.
104 # Fully minimized form: remove just one colon.
101 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
105 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
102
106
103 # List items are formatted with a hanging indent. We must
107 # List items are formatted with a hanging indent. We must
104 # correct for this here while we still have the original
108 # correct for this here while we still have the original
105 # information on the indentation of the subsequent literal
109 # information on the indentation of the subsequent literal
106 # blocks available.
110 # blocks available.
107 m = _bulletre.match(blocks[i]['lines'][0])
111 m = _bulletre.match(blocks[i]['lines'][0])
108 if m:
112 if m:
109 indent += m.end()
113 indent += m.end()
110 adjustment -= m.end()
114 adjustment -= m.end()
111
115
112 # Mark the following indented blocks.
116 # Mark the following indented blocks.
113 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
117 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
114 blocks[i + 1]['type'] = 'literal'
118 blocks[i + 1]['type'] = 'literal'
115 blocks[i + 1]['indent'] -= adjustment
119 blocks[i + 1]['indent'] -= adjustment
116 i += 1
120 i += 1
117 i += 1
121 i += 1
118 return blocks
122 return blocks
119
123
120 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
124 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
121 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
125 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
122 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
126 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
123 _definitionre = re.compile(r'[^ ]')
127 _definitionre = re.compile(r'[^ ]')
124
128
125 def splitparagraphs(blocks):
129 def splitparagraphs(blocks):
126 """Split paragraphs into lists."""
130 """Split paragraphs into lists."""
127 # Tuples with (list type, item regexp, single line items?). Order
131 # Tuples with (list type, item regexp, single line items?). Order
128 # matters: definition lists has the least specific regexp and must
132 # matters: definition lists has the least specific regexp and must
129 # come last.
133 # come last.
130 listtypes = [('bullet', _bulletre, True),
134 listtypes = [('bullet', _bulletre, True),
131 ('option', _optionre, True),
135 ('option', _optionre, True),
132 ('field', _fieldre, True),
136 ('field', _fieldre, True),
133 ('definition', _definitionre, False)]
137 ('definition', _definitionre, False)]
134
138
135 def match(lines, i, itemre, singleline):
139 def match(lines, i, itemre, singleline):
136 """Does itemre match an item at line i?
140 """Does itemre match an item at line i?
137
141
138 A list item can be followed by an idented line or another list
142 A list item can be followed by an idented line or another list
139 item (but only if singleline is True).
143 item (but only if singleline is True).
140 """
144 """
141 line1 = lines[i]
145 line1 = lines[i]
142 line2 = i + 1 < len(lines) and lines[i + 1] or ''
146 line2 = i + 1 < len(lines) and lines[i + 1] or ''
143 if not itemre.match(line1):
147 if not itemre.match(line1):
144 return False
148 return False
145 if singleline:
149 if singleline:
146 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
150 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
147 else:
151 else:
148 return line2.startswith(' ')
152 return line2.startswith(' ')
149
153
150 i = 0
154 i = 0
151 while i < len(blocks):
155 while i < len(blocks):
152 if blocks[i]['type'] == 'paragraph':
156 if blocks[i]['type'] == 'paragraph':
153 lines = blocks[i]['lines']
157 lines = blocks[i]['lines']
154 for type, itemre, singleline in listtypes:
158 for type, itemre, singleline in listtypes:
155 if match(lines, 0, itemre, singleline):
159 if match(lines, 0, itemre, singleline):
156 items = []
160 items = []
157 for j, line in enumerate(lines):
161 for j, line in enumerate(lines):
158 if match(lines, j, itemre, singleline):
162 if match(lines, j, itemre, singleline):
159 items.append(dict(type=type, lines=[],
163 items.append(dict(type=type, lines=[],
160 indent=blocks[i]['indent']))
164 indent=blocks[i]['indent']))
161 items[-1]['lines'].append(line)
165 items[-1]['lines'].append(line)
162 blocks[i:i + 1] = items
166 blocks[i:i + 1] = items
163 break
167 break
164 i += 1
168 i += 1
165 return blocks
169 return blocks
166
170
167
171
168 _fieldwidth = 12
172 _fieldwidth = 12
169
173
170 def updatefieldlists(blocks):
174 def updatefieldlists(blocks):
171 """Find key and maximum key width for field lists."""
175 """Find key and maximum key width for field lists."""
172 i = 0
176 i = 0
173 while i < len(blocks):
177 while i < len(blocks):
174 if blocks[i]['type'] != 'field':
178 if blocks[i]['type'] != 'field':
175 i += 1
179 i += 1
176 continue
180 continue
177
181
178 keywidth = 0
182 keywidth = 0
179 j = i
183 j = i
180 while j < len(blocks) and blocks[j]['type'] == 'field':
184 while j < len(blocks) and blocks[j]['type'] == 'field':
181 m = _fieldre.match(blocks[j]['lines'][0])
185 m = _fieldre.match(blocks[j]['lines'][0])
182 key, rest = m.groups()
186 key, rest = m.groups()
183 blocks[j]['lines'][0] = rest
187 blocks[j]['lines'][0] = rest
184 blocks[j]['key'] = key
188 blocks[j]['key'] = key
185 keywidth = max(keywidth, len(key))
189 keywidth = max(keywidth, len(key))
186 j += 1
190 j += 1
187
191
188 for block in blocks[i:j]:
192 for block in blocks[i:j]:
189 block['keywidth'] = keywidth
193 block['keywidth'] = keywidth
190 i = j + 1
194 i = j + 1
191
195
192 return blocks
196 return blocks
193
197
194
198
195 def prunecontainers(blocks, keep):
199 def prunecontainers(blocks, keep):
196 """Prune unwanted containers.
200 """Prune unwanted containers.
197
201
198 The blocks must have a 'type' field, i.e., they should have been
202 The blocks must have a 'type' field, i.e., they should have been
199 run through findliteralblocks first.
203 run through findliteralblocks first.
200 """
204 """
201 pruned = []
205 pruned = []
202 i = 0
206 i = 0
203 while i + 1 < len(blocks):
207 while i + 1 < len(blocks):
204 # Searching for a block that looks like this:
208 # Searching for a block that looks like this:
205 #
209 #
206 # +-------+---------------------------+
210 # +-------+---------------------------+
207 # | ".. container ::" type |
211 # | ".. container ::" type |
208 # +---+ |
212 # +---+ |
209 # | blocks |
213 # | blocks |
210 # +-------------------------------+
214 # +-------------------------------+
211 if (blocks[i]['type'] == 'paragraph' and
215 if (blocks[i]['type'] == 'paragraph' and
212 blocks[i]['lines'][0].startswith('.. container::')):
216 blocks[i]['lines'][0].startswith('.. container::')):
213 indent = blocks[i]['indent']
217 indent = blocks[i]['indent']
214 adjustment = blocks[i + 1]['indent'] - indent
218 adjustment = blocks[i + 1]['indent'] - indent
215 containertype = blocks[i]['lines'][0][15:]
219 containertype = blocks[i]['lines'][0][15:]
216 prune = containertype not in keep
220 prune = containertype not in keep
217 if prune:
221 if prune:
218 pruned.append(containertype)
222 pruned.append(containertype)
219
223
220 # Always delete "..container:: type" block
224 # Always delete "..container:: type" block
221 del blocks[i]
225 del blocks[i]
222 j = i
226 j = i
223 while j < len(blocks) and blocks[j]['indent'] > indent:
227 while j < len(blocks) and blocks[j]['indent'] > indent:
224 if prune:
228 if prune:
225 del blocks[j]
229 del blocks[j]
226 i -= 1 # adjust outer index
230 i -= 1 # adjust outer index
227 else:
231 else:
228 blocks[j]['indent'] -= adjustment
232 blocks[j]['indent'] -= adjustment
229 j += 1
233 j += 1
230 i += 1
234 i += 1
231 return blocks, pruned
235 return blocks, pruned
232
236
233
237
234 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
238 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
235
239
236 def findsections(blocks):
240 def findsections(blocks):
237 """Finds sections.
241 """Finds sections.
238
242
239 The blocks must have a 'type' field, i.e., they should have been
243 The blocks must have a 'type' field, i.e., they should have been
240 run through findliteralblocks first.
244 run through findliteralblocks first.
241 """
245 """
242 for block in blocks:
246 for block in blocks:
243 # Searching for a block that looks like this:
247 # Searching for a block that looks like this:
244 #
248 #
245 # +------------------------------+
249 # +------------------------------+
246 # | Section title |
250 # | Section title |
247 # | ------------- |
251 # | ------------- |
248 # +------------------------------+
252 # +------------------------------+
249 if (block['type'] == 'paragraph' and
253 if (block['type'] == 'paragraph' and
250 len(block['lines']) == 2 and
254 len(block['lines']) == 2 and
251 len(block['lines'][0]) == len(block['lines'][1]) and
255 len(block['lines'][0]) == len(block['lines'][1]) and
252 _sectionre.match(block['lines'][1])):
256 _sectionre.match(block['lines'][1])):
253 block['underline'] = block['lines'][1][0]
257 block['underline'] = block['lines'][1][0]
254 block['type'] = 'section'
258 block['type'] = 'section'
255 del block['lines'][1]
259 del block['lines'][1]
256 return blocks
260 return blocks
257
261
258
262
259 def inlineliterals(blocks):
263 def inlineliterals(blocks):
260 substs = [('``', '"')]
264 substs = [('``', '"')]
261 for b in blocks:
265 for b in blocks:
262 if b['type'] in ('paragraph', 'section'):
266 if b['type'] in ('paragraph', 'section'):
263 b['lines'] = [replace(l, substs) for l in b['lines']]
267 b['lines'] = [replace(l, substs) for l in b['lines']]
264 return blocks
268 return blocks
265
269
266
270
267 def hgrole(blocks):
271 def hgrole(blocks):
268 substs = [(':hg:`', '"hg '), ('`', '"')]
272 substs = [(':hg:`', '"hg '), ('`', '"')]
269 for b in blocks:
273 for b in blocks:
270 if b['type'] in ('paragraph', 'section'):
274 if b['type'] in ('paragraph', 'section'):
271 # Turn :hg:`command` into "hg command". This also works
275 # Turn :hg:`command` into "hg command". This also works
272 # when there is a line break in the command and relies on
276 # when there is a line break in the command and relies on
273 # the fact that we have no stray back-quotes in the input
277 # the fact that we have no stray back-quotes in the input
274 # (run the blocks through inlineliterals first).
278 # (run the blocks through inlineliterals first).
275 b['lines'] = [replace(l, substs) for l in b['lines']]
279 b['lines'] = [replace(l, substs) for l in b['lines']]
276 return blocks
280 return blocks
277
281
278
282
279 def addmargins(blocks):
283 def addmargins(blocks):
280 """Adds empty blocks for vertical spacing.
284 """Adds empty blocks for vertical spacing.
281
285
282 This groups bullets, options, and definitions together with no vertical
286 This groups bullets, options, and definitions together with no vertical
283 space between them, and adds an empty block between all other blocks.
287 space between them, and adds an empty block between all other blocks.
284 """
288 """
285 i = 1
289 i = 1
286 while i < len(blocks):
290 while i < len(blocks):
287 if (blocks[i]['type'] == blocks[i - 1]['type'] and
291 if (blocks[i]['type'] == blocks[i - 1]['type'] and
288 blocks[i]['type'] in ('bullet', 'option', 'field')):
292 blocks[i]['type'] in ('bullet', 'option', 'field')):
289 i += 1
293 i += 1
290 else:
294 else:
291 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
295 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
292 i += 2
296 i += 2
293 return blocks
297 return blocks
294
298
299 def findadmonitions(blocks):
300 """
301 Makes the type of the block an admonition block if
302 the first line is an admonition directive
303 """
304
305 i = 0
306
307 pattern = (r"\.\. (admonition|attention|caution|danger|error|hint|"
308 r"important|note|tip|warning)::")
309
310 prog = re.compile(pattern, flags=re.IGNORECASE)
311 while i < len(blocks):
312 m = prog.match(blocks[i]['lines'][0])
313 if m:
314 blocks[i]['type'] = 'admonition'
315 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
316
317 firstline = blocks[i]['lines'][0][m.end() + 1:]
318 if firstline != '':
319 blocks[i]['lines'].insert(1, ' ' + firstline + '')
320
321
322 blocks[i]['admonitiontitle'] = admonitiontitle
323 del blocks[i]['lines'][0]
324 i = i + 1
325 return blocks
295
326
296 def formatblock(block, width):
327 def formatblock(block, width):
297 """Format a block according to width."""
328 """Format a block according to width."""
298 if width <= 0:
329 if width <= 0:
299 width = 78
330 width = 78
300 indent = ' ' * block['indent']
331 indent = ' ' * block['indent']
332 if block['type'] == 'admonition':
333 titles = {'attention': _('Attention:'),
334 'caution': _('Caution:'),
335 'danger': _('!Danger!') ,
336 'error': _('Error:'),
337 'hint': _('Hint:'),
338 'important': _('Important:'),
339 'note': _('Note:'),
340 'tip': _('Tip:'),
341 'warning': _('Warning!')}
342
343 admonition = titles[block['admonitiontitle']]
344 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
345
346 defindent = indent + hang * ' '
347 text = ' '.join(map(str.strip, block['lines']))
348 return '%s\n%s' % (indent + admonition, util.wrap(text, width=width,
349 initindent=defindent,
350 hangindent=defindent))
301 if block['type'] == 'margin':
351 if block['type'] == 'margin':
302 return ''
352 return ''
303 if block['type'] == 'literal':
353 if block['type'] == 'literal':
304 indent += ' '
354 indent += ' '
305 return indent + ('\n' + indent).join(block['lines'])
355 return indent + ('\n' + indent).join(block['lines'])
306 if block['type'] == 'section':
356 if block['type'] == 'section':
307 underline = len(block['lines'][0]) * block['underline']
357 underline = len(block['lines'][0]) * block['underline']
308 return "%s%s\n%s%s" % (indent, block['lines'][0],indent, underline)
358 return "%s%s\n%s%s" % (indent, block['lines'][0],indent, underline)
309 if block['type'] == 'definition':
359 if block['type'] == 'definition':
310 term = indent + block['lines'][0]
360 term = indent + block['lines'][0]
311 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
361 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
312 defindent = indent + hang * ' '
362 defindent = indent + hang * ' '
313 text = ' '.join(map(str.strip, block['lines'][1:]))
363 text = ' '.join(map(str.strip, block['lines'][1:]))
314 return '%s\n%s' % (term, util.wrap(text, width=width,
364 return '%s\n%s' % (term, util.wrap(text, width=width,
315 initindent=defindent,
365 initindent=defindent,
316 hangindent=defindent))
366 hangindent=defindent))
317 subindent = indent
367 subindent = indent
318 if block['type'] == 'bullet':
368 if block['type'] == 'bullet':
319 if block['lines'][0].startswith('| '):
369 if block['lines'][0].startswith('| '):
320 # Remove bullet for line blocks and add no extra
370 # Remove bullet for line blocks and add no extra
321 # indention.
371 # indention.
322 block['lines'][0] = block['lines'][0][2:]
372 block['lines'][0] = block['lines'][0][2:]
323 else:
373 else:
324 m = _bulletre.match(block['lines'][0])
374 m = _bulletre.match(block['lines'][0])
325 subindent = indent + m.end() * ' '
375 subindent = indent + m.end() * ' '
326 elif block['type'] == 'field':
376 elif block['type'] == 'field':
327 keywidth = block['keywidth']
377 keywidth = block['keywidth']
328 key = block['key']
378 key = block['key']
329
379
330 subindent = indent + _fieldwidth * ' '
380 subindent = indent + _fieldwidth * ' '
331 if len(key) + 2 > _fieldwidth:
381 if len(key) + 2 > _fieldwidth:
332 # key too large, use full line width
382 # key too large, use full line width
333 key = key.ljust(width)
383 key = key.ljust(width)
334 elif keywidth + 2 < _fieldwidth:
384 elif keywidth + 2 < _fieldwidth:
335 # all keys are small, add only two spaces
385 # all keys are small, add only two spaces
336 key = key.ljust(keywidth + 2)
386 key = key.ljust(keywidth + 2)
337 subindent = indent + (keywidth + 2) * ' '
387 subindent = indent + (keywidth + 2) * ' '
338 else:
388 else:
339 # mixed sizes, use fieldwidth for this one
389 # mixed sizes, use fieldwidth for this one
340 key = key.ljust(_fieldwidth)
390 key = key.ljust(_fieldwidth)
341 block['lines'][0] = key + block['lines'][0]
391 block['lines'][0] = key + block['lines'][0]
342 elif block['type'] == 'option':
392 elif block['type'] == 'option':
343 m = _optionre.match(block['lines'][0])
393 m = _optionre.match(block['lines'][0])
344 option, arg, rest = m.groups()
394 option, arg, rest = m.groups()
345 subindent = indent + (len(option) + len(arg)) * ' '
395 subindent = indent + (len(option) + len(arg)) * ' '
346
396
347 text = ' '.join(map(str.strip, block['lines']))
397 text = ' '.join(map(str.strip, block['lines']))
348 return util.wrap(text, width=width,
398 return util.wrap(text, width=width,
349 initindent=indent,
399 initindent=indent,
350 hangindent=subindent)
400 hangindent=subindent)
351
401
352
402
353 def format(text, width, indent=0, keep=None):
403 def format(text, width, indent=0, keep=None):
354 """Parse and format the text according to width."""
404 """Parse and format the text according to width."""
355 blocks = findblocks(text)
405 blocks = findblocks(text)
356 for b in blocks:
406 for b in blocks:
357 b['indent'] += indent
407 b['indent'] += indent
358 blocks = findliteralblocks(blocks)
408 blocks = findliteralblocks(blocks)
359 blocks, pruned = prunecontainers(blocks, keep or [])
409 blocks, pruned = prunecontainers(blocks, keep or [])
360 blocks = findsections(blocks)
410 blocks = findsections(blocks)
361 blocks = inlineliterals(blocks)
411 blocks = inlineliterals(blocks)
362 blocks = hgrole(blocks)
412 blocks = hgrole(blocks)
363 blocks = splitparagraphs(blocks)
413 blocks = splitparagraphs(blocks)
364 blocks = updatefieldlists(blocks)
414 blocks = updatefieldlists(blocks)
365 blocks = addmargins(blocks)
415 blocks = addmargins(blocks)
416 blocks = findadmonitions(blocks)
366 text = '\n'.join(formatblock(b, width) for b in blocks)
417 text = '\n'.join(formatblock(b, width) for b in blocks)
367 if keep is None:
418 if keep is None:
368 return text
419 return text
369 else:
420 else:
370 return text, pruned
421 return text, pruned
371
422
372
423
373 if __name__ == "__main__":
424 if __name__ == "__main__":
374 from pprint import pprint
425 from pprint import pprint
375
426
376 def debug(func, *args):
427 def debug(func, *args):
377 blocks = func(*args)
428 blocks = func(*args)
378 print "*** after %s:" % func.__name__
429 print "*** after %s:" % func.__name__
379 pprint(blocks)
430 pprint(blocks)
380 print
431 print
381 return blocks
432 return blocks
382
433
383 text = open(sys.argv[1]).read()
434 text = open(sys.argv[1]).read()
384 blocks = debug(findblocks, text)
435 blocks = debug(findblocks, text)
385 blocks = debug(findliteralblocks, blocks)
436 blocks = debug(findliteralblocks, blocks)
386 blocks, pruned = debug(prunecontainers, blocks, sys.argv[2:])
437 blocks, pruned = debug(prunecontainers, blocks, sys.argv[2:])
387 blocks = debug(inlineliterals, blocks)
438 blocks = debug(inlineliterals, blocks)
388 blocks = debug(splitparagraphs, blocks)
439 blocks = debug(splitparagraphs, blocks)
389 blocks = debug(updatefieldlists, blocks)
440 blocks = debug(updatefieldlists, blocks)
390 blocks = debug(findsections, blocks)
441 blocks = debug(findsections, blocks)
391 blocks = debug(addmargins, blocks)
442 blocks = debug(addmargins, blocks)
443 blocks = debug(findadmonitions, blocks)
392 print '\n'.join(formatblock(b, 30) for b in blocks)
444 print '\n'.join(formatblock(b, 30) for b in blocks)
@@ -1,199 +1,216 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 from pprint import pprint
3 from pprint import pprint
4 from mercurial import minirst
4 from mercurial import minirst
5
5
6 def debugformat(title, text, width, **kwargs):
6 def debugformat(title, text, width, **kwargs):
7 print "%s formatted to fit within %d characters:" % (title, width)
7 print "%s formatted to fit within %d characters:" % (title, width)
8 print "-" * 70
8 print "-" * 70
9 formatted = minirst.format(text, width, **kwargs)
9 formatted = minirst.format(text, width, **kwargs)
10 if type(formatted) == tuple:
10 if type(formatted) == tuple:
11 print formatted[0]
11 print formatted[0]
12 print "-" * 70
12 print "-" * 70
13 pprint(formatted[1])
13 pprint(formatted[1])
14 else:
14 else:
15 print formatted
15 print formatted
16 print "-" * 70
16 print "-" * 70
17 print
17 print
18
18
19 paragraphs = """
19 paragraphs = """
20 This is some text in the first paragraph.
20 This is some text in the first paragraph.
21
21
22 A small indented paragraph.
22 A small indented paragraph.
23 It is followed by some lines
23 It is followed by some lines
24 containing random whitespace.
24 containing random whitespace.
25 \n \n \nThe third and final paragraph.
25 \n \n \nThe third and final paragraph.
26 """
26 """
27
27
28 debugformat('paragraphs', paragraphs, 60)
28 debugformat('paragraphs', paragraphs, 60)
29 debugformat('paragraphs', paragraphs, 30)
29 debugformat('paragraphs', paragraphs, 30)
30
30
31
31
32 definitions = """
32 definitions = """
33 A Term
33 A Term
34 Definition. The indented
34 Definition. The indented
35 lines make up the definition.
35 lines make up the definition.
36 Another Term
36 Another Term
37 Another definition. The final line in the
37 Another definition. The final line in the
38 definition determines the indentation, so
38 definition determines the indentation, so
39 this will be indented with four spaces.
39 this will be indented with four spaces.
40
40
41 A Nested/Indented Term
41 A Nested/Indented Term
42 Definition.
42 Definition.
43 """
43 """
44
44
45 debugformat('definitions', definitions, 60)
45 debugformat('definitions', definitions, 60)
46 debugformat('definitions', definitions, 30)
46 debugformat('definitions', definitions, 30)
47
47
48
48
49 literals = r"""
49 literals = r"""
50 The fully minimized form is the most
50 The fully minimized form is the most
51 convenient form::
51 convenient form::
52
52
53 Hello
53 Hello
54 literal
54 literal
55 world
55 world
56
56
57 In the partially minimized form a paragraph
57 In the partially minimized form a paragraph
58 simply ends with space-double-colon. ::
58 simply ends with space-double-colon. ::
59
59
60 ////////////////////////////////////////
60 ////////////////////////////////////////
61 long un-wrapped line in a literal block
61 long un-wrapped line in a literal block
62 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
62 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
63
63
64 ::
64 ::
65
65
66 This literal block is started with '::',
66 This literal block is started with '::',
67 the so-called expanded form. The paragraph
67 the so-called expanded form. The paragraph
68 with '::' disappears in the final output.
68 with '::' disappears in the final output.
69 """
69 """
70
70
71 debugformat('literals', literals, 60)
71 debugformat('literals', literals, 60)
72 debugformat('literals', literals, 30)
72 debugformat('literals', literals, 30)
73
73
74
74
75 lists = """
75 lists = """
76 - This is the first list item.
76 - This is the first list item.
77
77
78 Second paragraph in the first list item.
78 Second paragraph in the first list item.
79
79
80 - List items need not be separated
80 - List items need not be separated
81 by a blank line.
81 by a blank line.
82 - And will be rendered without
82 - And will be rendered without
83 one in any case.
83 one in any case.
84
84
85 We can have indented lists:
85 We can have indented lists:
86
86
87 - This is an indented list item
87 - This is an indented list item
88
88
89 - Another indented list item::
89 - Another indented list item::
90
90
91 - A literal block in the middle
91 - A literal block in the middle
92 of an indented list.
92 of an indented list.
93
93
94 (The above is not a list item since we are in the literal block.)
94 (The above is not a list item since we are in the literal block.)
95
95
96 ::
96 ::
97
97
98 Literal block with no indentation (apart from
98 Literal block with no indentation (apart from
99 the two spaces added to all literal blocks).
99 the two spaces added to all literal blocks).
100
100
101 1. This is an enumerated list (first item).
101 1. This is an enumerated list (first item).
102 2. Continuing with the second item.
102 2. Continuing with the second item.
103
103
104 (1) foo
104 (1) foo
105 (2) bar
105 (2) bar
106
106
107 1) Another
107 1) Another
108 2) List
108 2) List
109
109
110 Line blocks are also a form of list:
110 Line blocks are also a form of list:
111
111
112 | This is the first line.
112 | This is the first line.
113 The line continues here.
113 The line continues here.
114 | This is the second line.
114 | This is the second line.
115 """
115 """
116
116
117 debugformat('lists', lists, 60)
117 debugformat('lists', lists, 60)
118 debugformat('lists', lists, 30)
118 debugformat('lists', lists, 30)
119
119
120
120
121 options = """
121 options = """
122 There is support for simple option lists,
122 There is support for simple option lists,
123 but only with long options:
123 but only with long options:
124
124
125 --all Output all.
125 --all Output all.
126 --both Output both (this description is
126 --both Output both (this description is
127 quite long).
127 quite long).
128 --long Output all day long.
128 --long Output all day long.
129
129
130 --par This option has two paragraphs in its description.
130 --par This option has two paragraphs in its description.
131 This is the first.
131 This is the first.
132
132
133 This is the second. Blank lines may be omitted between
133 This is the second. Blank lines may be omitted between
134 options (as above) or left in (as here).
134 options (as above) or left in (as here).
135
135
136 The next paragraph looks like an option list, but lacks the two-space
136 The next paragraph looks like an option list, but lacks the two-space
137 marker after the option. It is treated as a normal paragraph:
137 marker after the option. It is treated as a normal paragraph:
138
138
139 --foo bar baz
139 --foo bar baz
140 """
140 """
141
141
142 debugformat('options', options, 60)
142 debugformat('options', options, 60)
143 debugformat('options', options, 30)
143 debugformat('options', options, 30)
144
144
145
145
146 fields = """
146 fields = """
147 :a: First item.
147 :a: First item.
148 :ab: Second item. Indentation and wrapping
148 :ab: Second item. Indentation and wrapping
149 is handled automatically.
149 is handled automatically.
150
150
151 Next list:
151 Next list:
152
152
153 :small: The larger key below triggers full indentation here.
153 :small: The larger key below triggers full indentation here.
154 :much too large: This key is big enough to get its own line.
154 :much too large: This key is big enough to get its own line.
155 """
155 """
156
156
157 debugformat('fields', fields, 60)
157 debugformat('fields', fields, 60)
158 debugformat('fields', fields, 30)
158 debugformat('fields', fields, 30)
159
159
160 containers = """
160 containers = """
161 Normal output.
161 Normal output.
162
162
163 .. container:: debug
163 .. container:: debug
164
164
165 Initial debug output.
165 Initial debug output.
166
166
167 .. container:: verbose
167 .. container:: verbose
168
168
169 Verbose output.
169 Verbose output.
170
170
171 .. container:: debug
171 .. container:: debug
172
172
173 Debug output.
173 Debug output.
174 """
174 """
175
175
176 debugformat('containers (normal)', containers, 60)
176 debugformat('containers (normal)', containers, 60)
177 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
177 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
178 debugformat('containers (debug)', containers, 60, keep=['debug'])
178 debugformat('containers (debug)', containers, 60, keep=['debug'])
179 debugformat('containers (verbose debug)', containers, 60,
179 debugformat('containers (verbose debug)', containers, 60,
180 keep=['verbose', 'debug'])
180 keep=['verbose', 'debug'])
181
181
182 roles = """Please see :hg:`add`."""
182 roles = """Please see :hg:`add`."""
183 debugformat('roles', roles, 60)
183 debugformat('roles', roles, 60)
184
184
185
185
186 sections = """
186 sections = """
187 Title
187 Title
188 =====
188 =====
189
189
190 Section
190 Section
191 -------
191 -------
192
192
193 Subsection
193 Subsection
194 ''''''''''
194 ''''''''''
195
195
196 Markup: ``foo`` and :hg:`help`
196 Markup: ``foo`` and :hg:`help`
197 ------------------------------
197 ------------------------------
198 """
198 """
199 debugformat('sections', sections, 20)
199 debugformat('sections', sections, 20)
200
201
202 admonitions = """
203 .. note::
204 This is a note
205
206 - Bullet 1
207 - Bullet 2
208
209 .. warning:: This is a warning Second
210 input line of warning
211
212 .. danger::
213 This is danger
214 """
215
216 debugformat('admonitions', admonitions, 30)
@@ -1,320 +1,336 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
28
29 Another Term
29 Another Term
30 Another definition. The final line in the definition
30 Another definition. The final line in the definition
31 determines the indentation, so this will be indented
31 determines the indentation, so this will be indented
32 with four spaces.
32 with four spaces.
33
33
34 A Nested/Indented Term
34 A Nested/Indented Term
35 Definition.
35 Definition.
36 ----------------------------------------------------------------------
36 ----------------------------------------------------------------------
37
37
38 definitions formatted to fit within 30 characters:
38 definitions formatted to fit within 30 characters:
39 ----------------------------------------------------------------------
39 ----------------------------------------------------------------------
40 A Term
40 A Term
41 Definition. The indented
41 Definition. The indented
42 lines make up the
42 lines make up the
43 definition.
43 definition.
44
44
45 Another Term
45 Another Term
46 Another definition. The
46 Another definition. The
47 final line in the
47 final line in the
48 definition determines the
48 definition determines the
49 indentation, so this will
49 indentation, so this will
50 be indented with four
50 be indented with four
51 spaces.
51 spaces.
52
52
53 A Nested/Indented Term
53 A Nested/Indented Term
54 Definition.
54 Definition.
55 ----------------------------------------------------------------------
55 ----------------------------------------------------------------------
56
56
57 literals formatted to fit within 60 characters:
57 literals formatted to fit within 60 characters:
58 ----------------------------------------------------------------------
58 ----------------------------------------------------------------------
59 The fully minimized form is the most convenient form:
59 The fully minimized form is the most convenient form:
60
60
61 Hello
61 Hello
62 literal
62 literal
63 world
63 world
64
64
65 In the partially minimized form a paragraph simply ends with
65 In the partially minimized form a paragraph simply ends with
66 space-double-colon.
66 space-double-colon.
67
67
68 ////////////////////////////////////////
68 ////////////////////////////////////////
69 long un-wrapped line in a literal block
69 long un-wrapped line in a literal block
70 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
70 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
71
71
72 This literal block is started with '::',
72 This literal block is started with '::',
73 the so-called expanded form. The paragraph
73 the so-called expanded form. The paragraph
74 with '::' disappears in the final output.
74 with '::' disappears in the final output.
75 ----------------------------------------------------------------------
75 ----------------------------------------------------------------------
76
76
77 literals formatted to fit within 30 characters:
77 literals formatted to fit within 30 characters:
78 ----------------------------------------------------------------------
78 ----------------------------------------------------------------------
79 The fully minimized form is
79 The fully minimized form is
80 the most convenient form:
80 the most convenient form:
81
81
82 Hello
82 Hello
83 literal
83 literal
84 world
84 world
85
85
86 In the partially minimized
86 In the partially minimized
87 form a paragraph simply ends
87 form a paragraph simply ends
88 with space-double-colon.
88 with space-double-colon.
89
89
90 ////////////////////////////////////////
90 ////////////////////////////////////////
91 long un-wrapped line in a literal block
91 long un-wrapped line in a literal block
92 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
92 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
93
93
94 This literal block is started with '::',
94 This literal block is started with '::',
95 the so-called expanded form. The paragraph
95 the so-called expanded form. The paragraph
96 with '::' disappears in the final output.
96 with '::' disappears in the final output.
97 ----------------------------------------------------------------------
97 ----------------------------------------------------------------------
98
98
99 lists formatted to fit within 60 characters:
99 lists formatted to fit within 60 characters:
100 ----------------------------------------------------------------------
100 ----------------------------------------------------------------------
101 - This is the first list item.
101 - This is the first list item.
102
102
103 Second paragraph in the first list item.
103 Second paragraph in the first list item.
104
104
105 - List items need not be separated by a blank line.
105 - List items need not be separated by a blank line.
106 - And will be rendered without one in any case.
106 - And will be rendered without one in any case.
107
107
108 We can have indented lists:
108 We can have indented lists:
109
109
110 - This is an indented list item
110 - This is an indented list item
111 - Another indented list item:
111 - Another indented list item:
112
112
113 - A literal block in the middle
113 - A literal block in the middle
114 of an indented list.
114 of an indented list.
115
115
116 (The above is not a list item since we are in the literal block.)
116 (The above is not a list item since we are in the literal block.)
117
117
118 Literal block with no indentation (apart from
118 Literal block with no indentation (apart from
119 the two spaces added to all literal blocks).
119 the two spaces added to all literal blocks).
120
120
121 1. This is an enumerated list (first item).
121 1. This is an enumerated list (first item).
122 2. Continuing with the second item.
122 2. Continuing with the second item.
123 (1) foo
123 (1) foo
124 (2) bar
124 (2) bar
125 1) Another
125 1) Another
126 2) List
126 2) List
127
127
128 Line blocks are also a form of list:
128 Line blocks are also a form of list:
129
129
130 This is the first line. The line continues here.
130 This is the first line. The line continues here.
131 This is the second line.
131 This is the second line.
132 ----------------------------------------------------------------------
132 ----------------------------------------------------------------------
133
133
134 lists formatted to fit within 30 characters:
134 lists formatted to fit within 30 characters:
135 ----------------------------------------------------------------------
135 ----------------------------------------------------------------------
136 - This is the first list item.
136 - This is the first list item.
137
137
138 Second paragraph in the
138 Second paragraph in the
139 first list item.
139 first list item.
140
140
141 - List items need not be
141 - List items need not be
142 separated by a blank line.
142 separated by a blank line.
143 - And will be rendered without
143 - And will be rendered without
144 one in any case.
144 one in any case.
145
145
146 We can have indented lists:
146 We can have indented lists:
147
147
148 - This is an indented list
148 - This is an indented list
149 item
149 item
150 - Another indented list
150 - Another indented list
151 item:
151 item:
152
152
153 - A literal block in the middle
153 - A literal block in the middle
154 of an indented list.
154 of an indented list.
155
155
156 (The above is not a list item since we are in the literal block.)
156 (The above is not a list item since we are in the literal block.)
157
157
158 Literal block with no indentation (apart from
158 Literal block with no indentation (apart from
159 the two spaces added to all literal blocks).
159 the two spaces added to all literal blocks).
160
160
161 1. This is an enumerated list
161 1. This is an enumerated list
162 (first item).
162 (first item).
163 2. Continuing with the second
163 2. Continuing with the second
164 item.
164 item.
165 (1) foo
165 (1) foo
166 (2) bar
166 (2) bar
167 1) Another
167 1) Another
168 2) List
168 2) List
169
169
170 Line blocks are also a form of
170 Line blocks are also a form of
171 list:
171 list:
172
172
173 This is the first line. The
173 This is the first line. The
174 line continues here.
174 line continues here.
175 This is the second line.
175 This is the second line.
176 ----------------------------------------------------------------------
176 ----------------------------------------------------------------------
177
177
178 options formatted to fit within 60 characters:
178 options formatted to fit within 60 characters:
179 ----------------------------------------------------------------------
179 ----------------------------------------------------------------------
180 There is support for simple option lists, but only with long
180 There is support for simple option lists, but only with long
181 options:
181 options:
182
182
183 --all Output all.
183 --all Output all.
184 --both Output both (this description is quite long).
184 --both Output both (this description is quite long).
185 --long Output all day long.
185 --long Output all day long.
186 --par This option has two paragraphs in its
186 --par This option has two paragraphs in its
187 description. This is the first.
187 description. This is the first.
188
188
189 This is the second. Blank lines may be omitted
189 This is the second. Blank lines may be omitted
190 between options (as above) or left in (as here).
190 between options (as above) or left in (as here).
191
191
192 The next paragraph looks like an option list, but lacks the
192 The next paragraph looks like an option list, but lacks the
193 two-space marker after the option. It is treated as a normal
193 two-space marker after the option. It is treated as a normal
194 paragraph:
194 paragraph:
195
195
196 --foo bar baz
196 --foo bar baz
197 ----------------------------------------------------------------------
197 ----------------------------------------------------------------------
198
198
199 options formatted to fit within 30 characters:
199 options formatted to fit within 30 characters:
200 ----------------------------------------------------------------------
200 ----------------------------------------------------------------------
201 There is support for simple
201 There is support for simple
202 option lists, but only with
202 option lists, but only with
203 long options:
203 long options:
204
204
205 --all Output all.
205 --all Output all.
206 --both Output both (this
206 --both Output both (this
207 description is
207 description is
208 quite long).
208 quite long).
209 --long Output all day
209 --long Output all day
210 long.
210 long.
211 --par This option has two
211 --par This option has two
212 paragraphs in its
212 paragraphs in its
213 description. This
213 description. This
214 is the first.
214 is the first.
215
215
216 This is the second.
216 This is the second.
217 Blank lines may be
217 Blank lines may be
218 omitted between
218 omitted between
219 options (as above)
219 options (as above)
220 or left in (as
220 or left in (as
221 here).
221 here).
222
222
223 The next paragraph looks like
223 The next paragraph looks like
224 an option list, but lacks the
224 an option list, but lacks the
225 two-space marker after the
225 two-space marker after the
226 option. It is treated as a
226 option. It is treated as a
227 normal paragraph:
227 normal paragraph:
228
228
229 --foo bar baz
229 --foo bar baz
230 ----------------------------------------------------------------------
230 ----------------------------------------------------------------------
231
231
232 fields formatted to fit within 60 characters:
232 fields formatted to fit within 60 characters:
233 ----------------------------------------------------------------------
233 ----------------------------------------------------------------------
234 a First item.
234 a First item.
235 ab Second item. Indentation and wrapping is handled
235 ab Second item. Indentation and wrapping is handled
236 automatically.
236 automatically.
237
237
238 Next list:
238 Next list:
239
239
240 small The larger key below triggers full indentation
240 small The larger key below triggers full indentation
241 here.
241 here.
242 much too large
242 much too large
243 This key is big enough to get its own line.
243 This key is big enough to get its own line.
244 ----------------------------------------------------------------------
244 ----------------------------------------------------------------------
245
245
246 fields formatted to fit within 30 characters:
246 fields formatted to fit within 30 characters:
247 ----------------------------------------------------------------------
247 ----------------------------------------------------------------------
248 a First item.
248 a First item.
249 ab Second item. Indentation
249 ab Second item. Indentation
250 and wrapping is handled
250 and wrapping is handled
251 automatically.
251 automatically.
252
252
253 Next list:
253 Next list:
254
254
255 small The larger key
255 small The larger key
256 below triggers
256 below triggers
257 full indentation
257 full indentation
258 here.
258 here.
259 much too large
259 much too large
260 This key is big
260 This key is big
261 enough to get its
261 enough to get its
262 own line.
262 own line.
263 ----------------------------------------------------------------------
263 ----------------------------------------------------------------------
264
264
265 containers (normal) formatted to fit within 60 characters:
265 containers (normal) formatted to fit within 60 characters:
266 ----------------------------------------------------------------------
266 ----------------------------------------------------------------------
267 Normal output.
267 Normal output.
268 ----------------------------------------------------------------------
268 ----------------------------------------------------------------------
269
269
270 containers (verbose) formatted to fit within 60 characters:
270 containers (verbose) formatted to fit within 60 characters:
271 ----------------------------------------------------------------------
271 ----------------------------------------------------------------------
272 Normal output.
272 Normal output.
273
273
274 Verbose output.
274 Verbose output.
275 ----------------------------------------------------------------------
275 ----------------------------------------------------------------------
276 ['debug', 'debug']
276 ['debug', 'debug']
277 ----------------------------------------------------------------------
277 ----------------------------------------------------------------------
278
278
279 containers (debug) formatted to fit within 60 characters:
279 containers (debug) formatted to fit within 60 characters:
280 ----------------------------------------------------------------------
280 ----------------------------------------------------------------------
281 Normal output.
281 Normal output.
282
282
283 Initial debug output.
283 Initial debug output.
284 ----------------------------------------------------------------------
284 ----------------------------------------------------------------------
285 ['verbose']
285 ['verbose']
286 ----------------------------------------------------------------------
286 ----------------------------------------------------------------------
287
287
288 containers (verbose debug) formatted to fit within 60 characters:
288 containers (verbose debug) formatted to fit within 60 characters:
289 ----------------------------------------------------------------------
289 ----------------------------------------------------------------------
290 Normal output.
290 Normal output.
291
291
292 Initial debug output.
292 Initial debug output.
293
293
294 Verbose output.
294 Verbose output.
295
295
296 Debug output.
296 Debug output.
297 ----------------------------------------------------------------------
297 ----------------------------------------------------------------------
298 []
298 []
299 ----------------------------------------------------------------------
299 ----------------------------------------------------------------------
300
300
301 roles formatted to fit within 60 characters:
301 roles formatted to fit within 60 characters:
302 ----------------------------------------------------------------------
302 ----------------------------------------------------------------------
303 Please see "hg add".
303 Please see "hg add".
304 ----------------------------------------------------------------------
304 ----------------------------------------------------------------------
305
305
306 sections formatted to fit within 20 characters:
306 sections formatted to fit within 20 characters:
307 ----------------------------------------------------------------------
307 ----------------------------------------------------------------------
308 Title
308 Title
309 =====
309 =====
310
310
311 Section
311 Section
312 -------
312 -------
313
313
314 Subsection
314 Subsection
315 ''''''''''
315 ''''''''''
316
316
317 Markup: "foo" and "hg help"
317 Markup: "foo" and "hg help"
318 ---------------------------
318 ---------------------------
319 ----------------------------------------------------------------------
319 ----------------------------------------------------------------------
320
320
321 admonitions formatted to fit within 30 characters:
322 ----------------------------------------------------------------------
323 Note:
324 This is a note
325
326 - Bullet 1
327 - Bullet 2
328
329 Warning!
330 This is a warning Second
331 input line of warning
332
333 !Danger!
334 This is danger
335 ----------------------------------------------------------------------
336
General Comments 0
You need to be logged in to leave comments. Login now