##// END OF EJS Templates
minirst: add basic HTML formatting support
Matt Mackall -
r15261:e2df5b86 default
parent child Browse files
Show More
@@ -1,579 +1,666 b''
1 1 # minirst.py - minimal reStructuredText parser
2 2 #
3 3 # Copyright 2009, 2010 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """simplified reStructuredText parser.
9 9
10 10 This parser knows just enough about reStructuredText to parse the
11 11 Mercurial docstrings.
12 12
13 13 It cheats in a major way: nested blocks are not really nested. They
14 14 are just indented blocks that look like they are nested. This relies
15 15 on the user to keep the right indentation for the blocks.
16 16
17 17 Remember to update http://mercurial.selenic.com/wiki/HelpStyleGuide
18 18 when adding support for new constructs.
19 19 """
20 20
21 21 import re
22 22 import util, encoding
23 23 from i18n import _
24 24
25 25 def replace(text, substs):
26 26 for f, t in substs:
27 27 text = text.replace(f, t)
28 28 return text
29 29
30 30 _blockre = re.compile(r"\n(?:\s*\n)+")
31 31
32 32 def findblocks(text):
33 33 """Find continuous blocks of lines in text.
34 34
35 35 Returns a list of dictionaries representing the blocks. Each block
36 36 has an 'indent' field and a 'lines' field.
37 37 """
38 38 blocks = []
39 39 for b in _blockre.split(text.lstrip('\n').rstrip()):
40 40 lines = b.splitlines()
41 41 if lines:
42 42 indent = min((len(l) - len(l.lstrip())) for l in lines)
43 43 lines = [l[indent:] for l in lines]
44 44 blocks.append(dict(indent=indent, lines=lines))
45 45 return blocks
46 46
47 47 def findliteralblocks(blocks):
48 48 """Finds literal blocks and adds a 'type' field to the blocks.
49 49
50 50 Literal blocks are given the type 'literal', all other blocks are
51 51 given type the 'paragraph'.
52 52 """
53 53 i = 0
54 54 while i < len(blocks):
55 55 # Searching for a block that looks like this:
56 56 #
57 57 # +------------------------------+
58 58 # | paragraph |
59 59 # | (ends with "::") |
60 60 # +------------------------------+
61 61 # +---------------------------+
62 62 # | indented literal block |
63 63 # +---------------------------+
64 64 blocks[i]['type'] = 'paragraph'
65 65 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
66 66 indent = blocks[i]['indent']
67 67 adjustment = blocks[i + 1]['indent'] - indent
68 68
69 69 if blocks[i]['lines'] == ['::']:
70 70 # Expanded form: remove block
71 71 del blocks[i]
72 72 i -= 1
73 73 elif blocks[i]['lines'][-1].endswith(' ::'):
74 74 # Partially minimized form: remove space and both
75 75 # colons.
76 76 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
77 77 else:
78 78 # Fully minimized form: remove just one colon.
79 79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
80 80
81 81 # List items are formatted with a hanging indent. We must
82 82 # correct for this here while we still have the original
83 83 # information on the indentation of the subsequent literal
84 84 # blocks available.
85 85 m = _bulletre.match(blocks[i]['lines'][0])
86 86 if m:
87 87 indent += m.end()
88 88 adjustment -= m.end()
89 89
90 90 # Mark the following indented blocks.
91 91 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
92 92 blocks[i + 1]['type'] = 'literal'
93 93 blocks[i + 1]['indent'] -= adjustment
94 94 i += 1
95 95 i += 1
96 96 return blocks
97 97
98 98 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
99 99 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
100 100 r'((.*) +)(.*)$')
101 101 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
102 102 _definitionre = re.compile(r'[^ ]')
103 103 _tablere = re.compile(r'(=+\s+)*=+')
104 104
105 105 def splitparagraphs(blocks):
106 106 """Split paragraphs into lists."""
107 107 # Tuples with (list type, item regexp, single line items?). Order
108 108 # matters: definition lists has the least specific regexp and must
109 109 # come last.
110 110 listtypes = [('bullet', _bulletre, True),
111 111 ('option', _optionre, True),
112 112 ('field', _fieldre, True),
113 113 ('definition', _definitionre, False)]
114 114
115 115 def match(lines, i, itemre, singleline):
116 116 """Does itemre match an item at line i?
117 117
118 118 A list item can be followed by an idented line or another list
119 119 item (but only if singleline is True).
120 120 """
121 121 line1 = lines[i]
122 122 line2 = i + 1 < len(lines) and lines[i + 1] or ''
123 123 if not itemre.match(line1):
124 124 return False
125 125 if singleline:
126 126 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
127 127 else:
128 128 return line2.startswith(' ')
129 129
130 130 i = 0
131 131 while i < len(blocks):
132 132 if blocks[i]['type'] == 'paragraph':
133 133 lines = blocks[i]['lines']
134 134 for type, itemre, singleline in listtypes:
135 135 if match(lines, 0, itemre, singleline):
136 136 items = []
137 137 for j, line in enumerate(lines):
138 138 if match(lines, j, itemre, singleline):
139 139 items.append(dict(type=type, lines=[],
140 140 indent=blocks[i]['indent']))
141 141 items[-1]['lines'].append(line)
142 142 blocks[i:i + 1] = items
143 143 break
144 144 i += 1
145 145 return blocks
146 146
147 147 _fieldwidth = 12
148 148
149 149 def updatefieldlists(blocks):
150 150 """Find key and maximum key width for field lists."""
151 151 i = 0
152 152 while i < len(blocks):
153 153 if blocks[i]['type'] != 'field':
154 154 i += 1
155 155 continue
156 156
157 157 keywidth = 0
158 158 j = i
159 159 while j < len(blocks) and blocks[j]['type'] == 'field':
160 160 m = _fieldre.match(blocks[j]['lines'][0])
161 161 key, rest = m.groups()
162 162 blocks[j]['lines'][0] = rest
163 163 blocks[j]['key'] = key
164 164 keywidth = max(keywidth, len(key))
165 165 j += 1
166 166
167 167 for block in blocks[i:j]:
168 168 block['keywidth'] = keywidth
169 169 i = j + 1
170 170
171 171 return blocks
172 172
173 173 def updateoptionlists(blocks):
174 174 i = 0
175 175 while i < len(blocks):
176 176 if blocks[i]['type'] != 'option':
177 177 i += 1
178 178 continue
179 179
180 180 optstrwidth = 0
181 181 j = i
182 182 while j < len(blocks) and blocks[j]['type'] == 'option':
183 183 m = _optionre.match(blocks[j]['lines'][0])
184 184
185 185 shortoption = m.group(2)
186 186 group3 = m.group(3)
187 187 longoption = group3[2:].strip()
188 188 desc = m.group(6).strip()
189 189 longoptionarg = m.group(5).strip()
190 190 blocks[j]['lines'][0] = desc
191 191
192 192 noshortop = ''
193 193 if not shortoption:
194 194 noshortop = ' '
195 195
196 196 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
197 197 ("%s--%s %s") % (noshortop, longoption,
198 198 longoptionarg))
199 199 opt = opt.rstrip()
200 200 blocks[j]['optstr'] = opt
201 201 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
202 202 j += 1
203 203
204 204 for block in blocks[i:j]:
205 205 block['optstrwidth'] = optstrwidth
206 206 i = j + 1
207 207 return blocks
208 208
209 209 def prunecontainers(blocks, keep):
210 210 """Prune unwanted containers.
211 211
212 212 The blocks must have a 'type' field, i.e., they should have been
213 213 run through findliteralblocks first.
214 214 """
215 215 pruned = []
216 216 i = 0
217 217 while i + 1 < len(blocks):
218 218 # Searching for a block that looks like this:
219 219 #
220 220 # +-------+---------------------------+
221 221 # | ".. container ::" type |
222 222 # +---+ |
223 223 # | blocks |
224 224 # +-------------------------------+
225 225 if (blocks[i]['type'] == 'paragraph' and
226 226 blocks[i]['lines'][0].startswith('.. container::')):
227 227 indent = blocks[i]['indent']
228 228 adjustment = blocks[i + 1]['indent'] - indent
229 229 containertype = blocks[i]['lines'][0][15:]
230 230 prune = containertype not in keep
231 231 if prune:
232 232 pruned.append(containertype)
233 233
234 234 # Always delete "..container:: type" block
235 235 del blocks[i]
236 236 j = i
237 237 i -= 1
238 238 while j < len(blocks) and blocks[j]['indent'] > indent:
239 239 if prune:
240 240 del blocks[j]
241 241 else:
242 242 blocks[j]['indent'] -= adjustment
243 243 j += 1
244 244 i += 1
245 245 return blocks, pruned
246 246
247 247 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
248 248
249 249 def findtables(blocks):
250 250 '''Find simple tables
251 251
252 252 Only simple one-line table elements are supported
253 253 '''
254 254
255 255 for block in blocks:
256 256 # Searching for a block that looks like this:
257 257 #
258 258 # === ==== ===
259 259 # A B C
260 260 # === ==== === <- optional
261 261 # 1 2 3
262 262 # x y z
263 263 # === ==== ===
264 264 if (block['type'] == 'paragraph' and
265 265 len(block['lines']) > 2 and
266 266 _tablere.match(block['lines'][0]) and
267 267 block['lines'][0] == block['lines'][-1]):
268 268 block['type'] = 'table'
269 269 block['header'] = False
270 270 div = block['lines'][0]
271 271
272 272 # column markers are ASCII so we can calculate column
273 273 # position in bytes
274 274 columns = [x for x in xrange(len(div))
275 275 if div[x] == '=' and (x == 0 or div[x - 1] == ' ')]
276 276 rows = []
277 277 for l in block['lines'][1:-1]:
278 278 if l == div:
279 279 block['header'] = True
280 280 continue
281 281 row = []
282 282 # we measure columns not in bytes or characters but in
283 283 # colwidth which makes things tricky
284 284 pos = columns[0] # leading whitespace is bytes
285 285 for n, start in enumerate(columns):
286 286 if n + 1 < len(columns):
287 287 width = columns[n + 1] - start
288 288 v = encoding.getcols(l, pos, width) # gather columns
289 289 pos += len(v) # calculate byte position of end
290 290 row.append(v.strip())
291 291 else:
292 292 row.append(l[pos:].strip())
293 293 rows.append(row)
294 294
295 295 block['table'] = rows
296 296
297 297 return blocks
298 298
299 299 def findsections(blocks):
300 300 """Finds sections.
301 301
302 302 The blocks must have a 'type' field, i.e., they should have been
303 303 run through findliteralblocks first.
304 304 """
305 305 for block in blocks:
306 306 # Searching for a block that looks like this:
307 307 #
308 308 # +------------------------------+
309 309 # | Section title |
310 310 # | ------------- |
311 311 # +------------------------------+
312 312 if (block['type'] == 'paragraph' and
313 313 len(block['lines']) == 2 and
314 314 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
315 315 _sectionre.match(block['lines'][1])):
316 316 block['underline'] = block['lines'][1][0]
317 317 block['type'] = 'section'
318 318 del block['lines'][1]
319 319 return blocks
320 320
321 321 def inlineliterals(blocks):
322 322 substs = [('``', '"')]
323 323 for b in blocks:
324 324 if b['type'] in ('paragraph', 'section'):
325 325 b['lines'] = [replace(l, substs) for l in b['lines']]
326 326 return blocks
327 327
328 328 def hgrole(blocks):
329 329 substs = [(':hg:`', '"hg '), ('`', '"')]
330 330 for b in blocks:
331 331 if b['type'] in ('paragraph', 'section'):
332 332 # Turn :hg:`command` into "hg command". This also works
333 333 # when there is a line break in the command and relies on
334 334 # the fact that we have no stray back-quotes in the input
335 335 # (run the blocks through inlineliterals first).
336 336 b['lines'] = [replace(l, substs) for l in b['lines']]
337 337 return blocks
338 338
339 339 def addmargins(blocks):
340 340 """Adds empty blocks for vertical spacing.
341 341
342 342 This groups bullets, options, and definitions together with no vertical
343 343 space between them, and adds an empty block between all other blocks.
344 344 """
345 345 i = 1
346 346 while i < len(blocks):
347 347 if (blocks[i]['type'] == blocks[i - 1]['type'] and
348 348 blocks[i]['type'] in ('bullet', 'option', 'field')):
349 349 i += 1
350 350 else:
351 351 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
352 352 i += 2
353 353 return blocks
354 354
355 355 def prunecomments(blocks):
356 356 """Remove comments."""
357 357 i = 0
358 358 while i < len(blocks):
359 359 b = blocks[i]
360 360 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
361 361 b['lines'] == ['..']):
362 362 del blocks[i]
363 363 if i < len(blocks) and blocks[i]['type'] == 'margin':
364 364 del blocks[i]
365 365 else:
366 366 i += 1
367 367 return blocks
368 368
369 369 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
370 370 r"error|hint|important|note|tip|warning)::",
371 371 flags=re.IGNORECASE)
372 372
373 373 def findadmonitions(blocks):
374 374 """
375 375 Makes the type of the block an admonition block if
376 376 the first line is an admonition directive
377 377 """
378 378 i = 0
379 379 while i < len(blocks):
380 380 m = _admonitionre.match(blocks[i]['lines'][0])
381 381 if m:
382 382 blocks[i]['type'] = 'admonition'
383 383 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
384 384
385 385 firstline = blocks[i]['lines'][0][m.end() + 1:]
386 386 if firstline:
387 387 blocks[i]['lines'].insert(1, ' ' + firstline)
388 388
389 389 blocks[i]['admonitiontitle'] = admonitiontitle
390 390 del blocks[i]['lines'][0]
391 391 i = i + 1
392 392 return blocks
393 393
394 394 _admonitiontitles = {'attention': _('Attention:'),
395 395 'caution': _('Caution:'),
396 396 'danger': _('!Danger!') ,
397 397 'error': _('Error:'),
398 398 'hint': _('Hint:'),
399 399 'important': _('Important:'),
400 400 'note': _('Note:'),
401 401 'tip': _('Tip:'),
402 402 'warning': _('Warning!')}
403 403
404 404 def formatoption(block, width):
405 405 desc = ' '.join(map(str.strip, block['lines']))
406 406 colwidth = encoding.colwidth(block['optstr'])
407 407 usablewidth = width - 1
408 408 hanging = block['optstrwidth']
409 409 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
410 410 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
411 411 return ' %s\n' % (util.wrap(desc, usablewidth,
412 412 initindent=initindent,
413 413 hangindent=hangindent))
414 414
415 415 def formatblock(block, width):
416 416 """Format a block according to width."""
417 417 if width <= 0:
418 418 width = 78
419 419 indent = ' ' * block['indent']
420 420 if block['type'] == 'admonition':
421 421 admonition = _admonitiontitles[block['admonitiontitle']]
422 422 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
423 423
424 424 defindent = indent + hang * ' '
425 425 text = ' '.join(map(str.strip, block['lines']))
426 426 return '%s\n%s\n' % (indent + admonition,
427 427 util.wrap(text, width=width,
428 428 initindent=defindent,
429 429 hangindent=defindent))
430 430 if block['type'] == 'margin':
431 431 return '\n'
432 432 if block['type'] == 'literal':
433 433 indent += ' '
434 434 return indent + ('\n' + indent).join(block['lines']) + '\n'
435 435 if block['type'] == 'section':
436 436 underline = encoding.colwidth(block['lines'][0]) * block['underline']
437 437 return "%s%s\n%s%s\n" % (indent, block['lines'][0],indent, underline)
438 438 if block['type'] == 'table':
439 439 table = block['table']
440 440 # compute column widths
441 441 widths = [max([encoding.colwidth(e) for e in c]) for c in zip(*table)]
442 442 text = ''
443 443 span = sum(widths) + len(widths) - 1
444 444 indent = ' ' * block['indent']
445 445 hang = ' ' * (len(indent) + span - widths[-1])
446 446
447 447 for row in table:
448 448 l = []
449 449 for w, v in zip(widths, row):
450 450 pad = ' ' * (w - encoding.colwidth(v))
451 451 l.append(v + pad)
452 452 l = ' '.join(l)
453 453 l = util.wrap(l, width=width, initindent=indent, hangindent=hang)
454 454 if not text and block['header']:
455 455 text = l + '\n' + indent + '-' * (min(width, span)) + '\n'
456 456 else:
457 457 text += l + "\n"
458 458 return text
459 459 if block['type'] == 'definition':
460 460 term = indent + block['lines'][0]
461 461 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
462 462 defindent = indent + hang * ' '
463 463 text = ' '.join(map(str.strip, block['lines'][1:]))
464 464 return '%s\n%s\n' % (term, util.wrap(text, width=width,
465 465 initindent=defindent,
466 466 hangindent=defindent))
467 467 subindent = indent
468 468 if block['type'] == 'bullet':
469 469 if block['lines'][0].startswith('| '):
470 470 # Remove bullet for line blocks and add no extra
471 471 # indention.
472 472 block['lines'][0] = block['lines'][0][2:]
473 473 else:
474 474 m = _bulletre.match(block['lines'][0])
475 475 subindent = indent + m.end() * ' '
476 476 elif block['type'] == 'field':
477 477 keywidth = block['keywidth']
478 478 key = block['key']
479 479
480 480 subindent = indent + _fieldwidth * ' '
481 481 if len(key) + 2 > _fieldwidth:
482 482 # key too large, use full line width
483 483 key = key.ljust(width)
484 484 elif keywidth + 2 < _fieldwidth:
485 485 # all keys are small, add only two spaces
486 486 key = key.ljust(keywidth + 2)
487 487 subindent = indent + (keywidth + 2) * ' '
488 488 else:
489 489 # mixed sizes, use fieldwidth for this one
490 490 key = key.ljust(_fieldwidth)
491 491 block['lines'][0] = key + block['lines'][0]
492 492 elif block['type'] == 'option':
493 493 return formatoption(block, width)
494 494
495 495 text = ' '.join(map(str.strip, block['lines']))
496 496 return util.wrap(text, width=width,
497 497 initindent=indent,
498 498 hangindent=subindent) + '\n'
499 499
500 def formathtml(blocks):
501 """Format RST blocks as HTML"""
502
503 out = []
504 headernest = ''
505 listnest = []
506
507 def openlist(start, level):
508 if not listnest or listnest[-1][0] != start:
509 listnest.append((start, level))
510 out.append('<%s>\n' % start)
511
512 blocks = [b for b in blocks if b['type'] != 'margin']
513
514 for pos, b in enumerate(blocks):
515 btype = b['type']
516 level = b['indent']
517 lines = b['lines']
518
519 if btype == 'admonition':
520 admonition = _admonitiontitles[b['admonitiontitle']]
521 text = ' '.join(map(str.strip, lines))
522 out.append('<p>\n<b>%s</b> %s\n</p>\n' % (admonition, text))
523 elif btype == 'paragraph':
524 out.append('<p>\n%s\n</p>\n' % '\n'.join(lines))
525 elif btype == 'margin':
526 pass
527 elif btype == 'literal':
528 out.append('<pre>\n%s\n</pre>\n' % '\n'.join(lines))
529 elif btype == 'section':
530 i = b['underline']
531 if i not in headernest:
532 headernest += i
533 level = headernest.index(i) + 1
534 out.append('<h%d>%s</h%d>\n' % (level, lines[0], level))
535 elif btype == 'table':
536 table = b['table']
537 t = []
538 for row in table:
539 l = []
540 for v in zip(row):
541 if not t:
542 l.append('<th>%s</th>' % v)
543 else:
544 l.append('<td>%s</td>' % v)
545 t.append(' <tr>%s</tr>\n' % ''.join(l))
546 out.append('<table>\n%s</table>\n' % ''.join(t))
547 elif btype == 'definition':
548 openlist('dl', level)
549 term = lines[0]
550 text = ' '.join(map(str.strip, lines[1:]))
551 out.append(' <dt>%s\n <dd>%s\n' % (term, text))
552 elif btype == 'bullet':
553 bullet, head = lines[0].split(' ', 1)
554 if bullet == '-':
555 openlist('ul', level)
556 else:
557 openlist('ol', level)
558 out.append(' <li> %s\n' % ' '.join([head] + lines[1:]))
559 elif btype == 'field':
560 openlist('dl', level)
561 key = b['key']
562 text = ' '.join(map(str.strip, lines))
563 out.append(' <dt>%s\n <dd>%s\n' % (key, text))
564 elif btype == 'option':
565 openlist('dl', level)
566 opt = b['optstr']
567 desc = ' '.join(map(str.strip, lines))
568 out.append(' <dt>%s\n <dd>%s\n' % (opt, desc))
569
570 # close lists if indent level of next block is lower
571 if listnest:
572 start, level = listnest[-1]
573 if pos == len(blocks) - 1:
574 out.append('</%s>\n' % start)
575 listnest.pop()
576 else:
577 nb = blocks[pos + 1]
578 ni = nb['indent']
579 if (ni < level or
580 (ni == level and
581 nb['type'] not in 'definition bullet field option')):
582 out.append('</%s>\n' % start)
583 listnest.pop()
584
585 return ''.join(out)
586
500 587 def parse(text, indent=0, keep=None):
501 588 """Parse text into a list of blocks"""
502 589 pruned = []
503 590 blocks = findblocks(text)
504 591 for b in blocks:
505 592 b['indent'] += indent
506 593 blocks = findliteralblocks(blocks)
507 594 blocks = findtables(blocks)
508 595 blocks, pruned = prunecontainers(blocks, keep or [])
509 596 blocks = findsections(blocks)
510 597 blocks = inlineliterals(blocks)
511 598 blocks = hgrole(blocks)
512 599 blocks = splitparagraphs(blocks)
513 600 blocks = updatefieldlists(blocks)
514 601 blocks = updateoptionlists(blocks)
515 602 blocks = addmargins(blocks)
516 603 blocks = prunecomments(blocks)
517 604 blocks = findadmonitions(blocks)
518 605 return blocks, pruned
519 606
520 607 def formatblocks(blocks, width):
521 608 text = ''.join(formatblock(b, width) for b in blocks)
522 609 return text
523 610
524 611 def format(text, width, indent=0, keep=None):
525 612 """Parse and format the text according to width."""
526 613 blocks, pruned = parse(text, indent, keep or [])
527 614 text = ''.join(formatblock(b, width) for b in blocks)
528 615 if keep is None:
529 616 return text
530 617 else:
531 618 return text, pruned
532 619
533 620 def getsections(blocks):
534 621 '''return a list of (section name, nesting level, blocks) tuples'''
535 622 nest = ""
536 623 level = 0
537 624 secs = []
538 625 for b in blocks:
539 626 if b['type'] == 'section':
540 627 i = b['underline']
541 628 if i not in nest:
542 629 nest += i
543 630 level = nest.index(i) + 1
544 631 nest = nest[:level]
545 632 secs.append((b['lines'][0], level, [b]))
546 633 else:
547 634 if not secs:
548 635 # add an initial empty section
549 636 secs = [('', 0, [])]
550 637 secs[-1][2].append(b)
551 638 return secs
552 639
553 640 def decorateblocks(blocks, width):
554 641 '''generate a list of (section name, line text) pairs for search'''
555 642 lines = []
556 643 for s in getsections(blocks):
557 644 section = s[0]
558 645 text = formatblocks(s[2], width)
559 646 lines.append([(section, l) for l in text.splitlines(True)])
560 647 return lines
561 648
562 649 def maketable(data, indent=0, header=False):
563 650 '''Generate an RST table for the given table data'''
564 651
565 652 widths = [max(encoding.colwidth(e) for e in c) for c in zip(*data)]
566 653 indent = ' ' * indent
567 654 div = indent + ' '.join('=' * w for w in widths) + '\n'
568 655
569 656 out = [div]
570 657 for row in data:
571 658 l = []
572 659 for w, v in zip(widths, row):
573 660 pad = ' ' * (w - encoding.colwidth(v))
574 661 l.append(v + pad)
575 662 out.append(indent + ' '.join(l) + "\n")
576 663 if header and len(data) > 1:
577 664 out.insert(2, div)
578 665 out.append(div)
579 666 return ''.join(out)
@@ -1,244 +1,247 b''
1 1 from pprint import pprint
2 2 from mercurial import minirst
3 3
4 4 def debugformat(title, text, width, **kwargs):
5 5 print "%s formatted to fit within %d characters:" % (title, width)
6 formatted = minirst.format(text, width, **kwargs)
7 html = minirst.formathtml(minirst.parse(text, **kwargs)[0])
6 8 print "-" * 70
7 formatted = minirst.format(text, width, **kwargs)
8 9 if type(formatted) == tuple:
9 10 print formatted[0]
10 11 print "-" * 70
11 12 pprint(formatted[1])
12 13 else:
13 14 print formatted
14 15 print "-" * 70
16 print html
17 print "-" * 70
15 18 print
16 19
17 20 paragraphs = """
18 21 This is some text in the first paragraph.
19 22
20 23 A small indented paragraph.
21 24 It is followed by some lines
22 25 containing random whitespace.
23 26 \n \n \nThe third and final paragraph.
24 27 """
25 28
26 29 debugformat('paragraphs', paragraphs, 60)
27 30 debugformat('paragraphs', paragraphs, 30)
28 31
29 32
30 33 definitions = """
31 34 A Term
32 35 Definition. The indented
33 36 lines make up the definition.
34 37 Another Term
35 38 Another definition. The final line in the
36 39 definition determines the indentation, so
37 40 this will be indented with four spaces.
38 41
39 42 A Nested/Indented Term
40 43 Definition.
41 44 """
42 45
43 46 debugformat('definitions', definitions, 60)
44 47 debugformat('definitions', definitions, 30)
45 48
46 49
47 50 literals = r"""
48 51 The fully minimized form is the most
49 52 convenient form::
50 53
51 54 Hello
52 55 literal
53 56 world
54 57
55 58 In the partially minimized form a paragraph
56 59 simply ends with space-double-colon. ::
57 60
58 61 ////////////////////////////////////////
59 62 long un-wrapped line in a literal block
60 63 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
61 64
62 65 ::
63 66
64 67 This literal block is started with '::',
65 68 the so-called expanded form. The paragraph
66 69 with '::' disappears in the final output.
67 70 """
68 71
69 72 debugformat('literals', literals, 60)
70 73 debugformat('literals', literals, 30)
71 74
72 75
73 76 lists = """
74 77 - This is the first list item.
75 78
76 79 Second paragraph in the first list item.
77 80
78 81 - List items need not be separated
79 82 by a blank line.
80 83 - And will be rendered without
81 84 one in any case.
82 85
83 86 We can have indented lists:
84 87
85 88 - This is an indented list item
86 89
87 90 - Another indented list item::
88 91
89 92 - A literal block in the middle
90 93 of an indented list.
91 94
92 95 (The above is not a list item since we are in the literal block.)
93 96
94 97 ::
95 98
96 99 Literal block with no indentation (apart from
97 100 the two spaces added to all literal blocks).
98 101
99 102 1. This is an enumerated list (first item).
100 103 2. Continuing with the second item.
101 104
102 105 (1) foo
103 106 (2) bar
104 107
105 108 1) Another
106 109 2) List
107 110
108 111 Line blocks are also a form of list:
109 112
110 113 | This is the first line.
111 114 The line continues here.
112 115 | This is the second line.
113 116 """
114 117
115 118 debugformat('lists', lists, 60)
116 119 debugformat('lists', lists, 30)
117 120
118 121
119 122 options = """
120 123 There is support for simple option lists,
121 124 but only with long options:
122 125
123 126 -X, --exclude filter an option with a short and long option with an argument
124 127 -I, --include an option with both a short option and a long option
125 128 --all Output all.
126 129 --both Output both (this description is
127 130 quite long).
128 131 --long Output all day long.
129 132
130 133 --par This option has two paragraphs in its description.
131 134 This is the first.
132 135
133 136 This is the second. Blank lines may be omitted between
134 137 options (as above) or left in (as here).
135 138
136 139
137 140 The next paragraph looks like an option list, but lacks the two-space
138 141 marker after the option. It is treated as a normal paragraph:
139 142
140 143 --foo bar baz
141 144 """
142 145
143 146 debugformat('options', options, 60)
144 147 debugformat('options', options, 30)
145 148
146 149
147 150 fields = """
148 151 :a: First item.
149 152 :ab: Second item. Indentation and wrapping
150 153 is handled automatically.
151 154
152 155 Next list:
153 156
154 157 :small: The larger key below triggers full indentation here.
155 158 :much too large: This key is big enough to get its own line.
156 159 """
157 160
158 161 debugformat('fields', fields, 60)
159 162 debugformat('fields', fields, 30)
160 163
161 164 containers = """
162 165 Normal output.
163 166
164 167 .. container:: debug
165 168
166 169 Initial debug output.
167 170
168 171 .. container:: verbose
169 172
170 173 Verbose output.
171 174
172 175 .. container:: debug
173 176
174 177 Debug output.
175 178 """
176 179
177 180 debugformat('containers (normal)', containers, 60)
178 181 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
179 182 debugformat('containers (debug)', containers, 60, keep=['debug'])
180 183 debugformat('containers (verbose debug)', containers, 60,
181 184 keep=['verbose', 'debug'])
182 185
183 186 roles = """Please see :hg:`add`."""
184 187 debugformat('roles', roles, 60)
185 188
186 189
187 190 sections = """
188 191 Title
189 192 =====
190 193
191 194 Section
192 195 -------
193 196
194 197 Subsection
195 198 ''''''''''
196 199
197 200 Markup: ``foo`` and :hg:`help`
198 201 ------------------------------
199 202 """
200 203 debugformat('sections', sections, 20)
201 204
202 205
203 206 admonitions = """
204 207 .. note::
205 208 This is a note
206 209
207 210 - Bullet 1
208 211 - Bullet 2
209 212
210 213 .. warning:: This is a warning Second
211 214 input line of warning
212 215
213 216 .. danger::
214 217 This is danger
215 218 """
216 219
217 220 debugformat('admonitions', admonitions, 30)
218 221
219 222 comments = """
220 223 Some text.
221 224
222 225 .. A comment
223 226
224 227 .. An indented comment
225 228
226 229 Some indented text.
227 230
228 231 ..
229 232
230 233 Empty comment above
231 234 """
232 235
233 236 debugformat('comments', comments, 30)
234 237
235 238
236 239 data = [['a', 'b', 'c'],
237 240 ['1', '2', '3'],
238 241 ['foo', 'bar', 'baz this list is very very very long man']]
239 242
240 243 table = minirst.maketable(data, 2, True)
241 244
242 245 print table
243 246
244 247 debugformat('table', table, 30)
@@ -1,428 +1,785 b''
1 1 paragraphs formatted to fit within 60 characters:
2 2 ----------------------------------------------------------------------
3 3 This is some text in the first paragraph.
4 4
5 5 A small indented paragraph. It is followed by some lines
6 6 containing random whitespace.
7 7
8 8 The third and final paragraph.
9 9
10 10 ----------------------------------------------------------------------
11 <p>
12 This is some text in the first paragraph.
13 </p>
14 <p>
15 A small indented paragraph.
16 It is followed by some lines
17 containing random whitespace.
18 </p>
19 <p>
20 The third and final paragraph.
21 </p>
22
23 ----------------------------------------------------------------------
11 24
12 25 paragraphs formatted to fit within 30 characters:
13 26 ----------------------------------------------------------------------
14 27 This is some text in the first
15 28 paragraph.
16 29
17 30 A small indented paragraph.
18 31 It is followed by some lines
19 32 containing random
20 33 whitespace.
21 34
22 35 The third and final paragraph.
23 36
24 37 ----------------------------------------------------------------------
38 <p>
39 This is some text in the first paragraph.
40 </p>
41 <p>
42 A small indented paragraph.
43 It is followed by some lines
44 containing random whitespace.
45 </p>
46 <p>
47 The third and final paragraph.
48 </p>
49
50 ----------------------------------------------------------------------
25 51
26 52 definitions formatted to fit within 60 characters:
27 53 ----------------------------------------------------------------------
28 54 A Term
29 55 Definition. The indented lines make up the definition.
30 56
31 57 Another Term
32 58 Another definition. The final line in the definition
33 59 determines the indentation, so this will be indented
34 60 with four spaces.
35 61
36 62 A Nested/Indented Term
37 63 Definition.
38 64
39 65 ----------------------------------------------------------------------
66 <dl>
67 <dt>A Term
68 <dd>Definition. The indented lines make up the definition.
69 <dt>Another Term
70 <dd>Another definition. The final line in the definition determines the indentation, so this will be indented with four spaces.
71 <dt>A Nested/Indented Term
72 <dd>Definition.
73 </dl>
74
75 ----------------------------------------------------------------------
40 76
41 77 definitions formatted to fit within 30 characters:
42 78 ----------------------------------------------------------------------
43 79 A Term
44 80 Definition. The indented
45 81 lines make up the
46 82 definition.
47 83
48 84 Another Term
49 85 Another definition. The
50 86 final line in the
51 87 definition determines the
52 88 indentation, so this will
53 89 be indented with four
54 90 spaces.
55 91
56 92 A Nested/Indented Term
57 93 Definition.
58 94
59 95 ----------------------------------------------------------------------
96 <dl>
97 <dt>A Term
98 <dd>Definition. The indented lines make up the definition.
99 <dt>Another Term
100 <dd>Another definition. The final line in the definition determines the indentation, so this will be indented with four spaces.
101 <dt>A Nested/Indented Term
102 <dd>Definition.
103 </dl>
104
105 ----------------------------------------------------------------------
60 106
61 107 literals formatted to fit within 60 characters:
62 108 ----------------------------------------------------------------------
63 109 The fully minimized form is the most convenient form:
64 110
65 111 Hello
66 112 literal
67 113 world
68 114
69 115 In the partially minimized form a paragraph simply ends with
70 116 space-double-colon.
71 117
72 118 ////////////////////////////////////////
73 119 long un-wrapped line in a literal block
74 120 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
75 121
76 122 This literal block is started with '::',
77 123 the so-called expanded form. The paragraph
78 124 with '::' disappears in the final output.
79 125
80 126 ----------------------------------------------------------------------
127 <p>
128 The fully minimized form is the most
129 convenient form:
130 </p>
131 <pre>
132 Hello
133 literal
134 world
135 </pre>
136 <p>
137 In the partially minimized form a paragraph
138 simply ends with space-double-colon.
139 </p>
140 <pre>
141 ////////////////////////////////////////
142 long un-wrapped line in a literal block
143 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
144 </pre>
145 <pre>
146 This literal block is started with '::',
147 the so-called expanded form. The paragraph
148 with '::' disappears in the final output.
149 </pre>
150
151 ----------------------------------------------------------------------
81 152
82 153 literals formatted to fit within 30 characters:
83 154 ----------------------------------------------------------------------
84 155 The fully minimized form is
85 156 the most convenient form:
86 157
87 158 Hello
88 159 literal
89 160 world
90 161
91 162 In the partially minimized
92 163 form a paragraph simply ends
93 164 with space-double-colon.
94 165
95 166 ////////////////////////////////////////
96 167 long un-wrapped line in a literal block
97 168 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
98 169
99 170 This literal block is started with '::',
100 171 the so-called expanded form. The paragraph
101 172 with '::' disappears in the final output.
102 173
103 174 ----------------------------------------------------------------------
175 <p>
176 The fully minimized form is the most
177 convenient form:
178 </p>
179 <pre>
180 Hello
181 literal
182 world
183 </pre>
184 <p>
185 In the partially minimized form a paragraph
186 simply ends with space-double-colon.
187 </p>
188 <pre>
189 ////////////////////////////////////////
190 long un-wrapped line in a literal block
191 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
192 </pre>
193 <pre>
194 This literal block is started with '::',
195 the so-called expanded form. The paragraph
196 with '::' disappears in the final output.
197 </pre>
198
199 ----------------------------------------------------------------------
104 200
105 201 lists formatted to fit within 60 characters:
106 202 ----------------------------------------------------------------------
107 203 - This is the first list item.
108 204
109 205 Second paragraph in the first list item.
110 206
111 207 - List items need not be separated by a blank line.
112 208 - And will be rendered without one in any case.
113 209
114 210 We can have indented lists:
115 211
116 212 - This is an indented list item
117 213 - Another indented list item:
118 214
119 215 - A literal block in the middle
120 216 of an indented list.
121 217
122 218 (The above is not a list item since we are in the literal block.)
123 219
124 220 Literal block with no indentation (apart from
125 221 the two spaces added to all literal blocks).
126 222
127 223 1. This is an enumerated list (first item).
128 224 2. Continuing with the second item.
129 225 (1) foo
130 226 (2) bar
131 227 1) Another
132 228 2) List
133 229
134 230 Line blocks are also a form of list:
135 231
136 232 This is the first line. The line continues here.
137 233 This is the second line.
138 234
139 235 ----------------------------------------------------------------------
236 <ul>
237 <li> This is the first list item.
238 <p>
239 Second paragraph in the first list item.
240 </p>
241 <li> List items need not be separated by a blank line.
242 <li> And will be rendered without one in any case.
243 </ul>
244 <p>
245 We can have indented lists:
246 </p>
247 <ul>
248 <li> This is an indented list item
249 <li> Another indented list item:
250 <pre>
251 - A literal block in the middle
252 of an indented list.
253 </pre>
254 <pre>
255 (The above is not a list item since we are in the literal block.)
256 </pre>
257 </ul>
258 <pre>
259 Literal block with no indentation (apart from
260 the two spaces added to all literal blocks).
261 </pre>
262 <ol>
263 <li> This is an enumerated list (first item).
264 <li> Continuing with the second item.
265 <li> foo
266 <li> bar
267 <li> Another
268 <li> List
269 </ol>
270 <p>
271 Line blocks are also a form of list:
272 </p>
273 <ol>
274 <li> This is the first line. The line continues here.
275 <li> This is the second line.
276 </ol>
277
278 ----------------------------------------------------------------------
140 279
141 280 lists formatted to fit within 30 characters:
142 281 ----------------------------------------------------------------------
143 282 - This is the first list item.
144 283
145 284 Second paragraph in the
146 285 first list item.
147 286
148 287 - List items need not be
149 288 separated by a blank line.
150 289 - And will be rendered without
151 290 one in any case.
152 291
153 292 We can have indented lists:
154 293
155 294 - This is an indented list
156 295 item
157 296 - Another indented list
158 297 item:
159 298
160 299 - A literal block in the middle
161 300 of an indented list.
162 301
163 302 (The above is not a list item since we are in the literal block.)
164 303
165 304 Literal block with no indentation (apart from
166 305 the two spaces added to all literal blocks).
167 306
168 307 1. This is an enumerated list
169 308 (first item).
170 309 2. Continuing with the second
171 310 item.
172 311 (1) foo
173 312 (2) bar
174 313 1) Another
175 314 2) List
176 315
177 316 Line blocks are also a form of
178 317 list:
179 318
180 319 This is the first line. The
181 320 line continues here.
182 321 This is the second line.
183 322
184 323 ----------------------------------------------------------------------
324 <ul>
325 <li> This is the first list item.
326 <p>
327 Second paragraph in the first list item.
328 </p>
329 <li> List items need not be separated by a blank line.
330 <li> And will be rendered without one in any case.
331 </ul>
332 <p>
333 We can have indented lists:
334 </p>
335 <ul>
336 <li> This is an indented list item
337 <li> Another indented list item:
338 <pre>
339 - A literal block in the middle
340 of an indented list.
341 </pre>
342 <pre>
343 (The above is not a list item since we are in the literal block.)
344 </pre>
345 </ul>
346 <pre>
347 Literal block with no indentation (apart from
348 the two spaces added to all literal blocks).
349 </pre>
350 <ol>
351 <li> This is an enumerated list (first item).
352 <li> Continuing with the second item.
353 <li> foo
354 <li> bar
355 <li> Another
356 <li> List
357 </ol>
358 <p>
359 Line blocks are also a form of list:
360 </p>
361 <ol>
362 <li> This is the first line. The line continues here.
363 <li> This is the second line.
364 </ol>
365
366 ----------------------------------------------------------------------
185 367
186 368 options formatted to fit within 60 characters:
187 369 ----------------------------------------------------------------------
188 370 There is support for simple option lists, but only with long
189 371 options:
190 372
191 373 -X --exclude filter an option with a short and long option
192 374 with an argument
193 375 -I --include an option with both a short option and
194 376 a long option
195 377 --all Output all.
196 378 --both Output both (this description is quite
197 379 long).
198 380 --long Output all day long.
199 381 --par This option has two paragraphs in its
200 382 description. This is the first.
201 383
202 384 This is the second. Blank lines may
203 385 be omitted between options (as above)
204 386 or left in (as here).
205 387
206 388 The next paragraph looks like an option list, but lacks the
207 389 two-space marker after the option. It is treated as a normal
208 390 paragraph:
209 391
210 392 --foo bar baz
211 393
212 394 ----------------------------------------------------------------------
395 <p>
396 There is support for simple option lists,
397 but only with long options:
398 </p>
399 <dl>
400 <dt>-X --exclude filter
401 <dd>an option with a short and long option with an argument
402 <dt>-I --include
403 <dd>an option with both a short option and a long option
404 <dt> --all
405 <dd>Output all.
406 <dt> --both
407 <dd>Output both (this description is quite long).
408 <dt> --long
409 <dd>Output all day long.
410 <dt> --par
411 <dd>This option has two paragraphs in its description. This is the first.
412 <p>
413 This is the second. Blank lines may be omitted between
414 options (as above) or left in (as here).
415 </p>
416 </dl>
417 <p>
418 The next paragraph looks like an option list, but lacks the two-space
419 marker after the option. It is treated as a normal paragraph:
420 </p>
421 <p>
422 --foo bar baz
423 </p>
424
425 ----------------------------------------------------------------------
213 426
214 427 options formatted to fit within 30 characters:
215 428 ----------------------------------------------------------------------
216 429 There is support for simple
217 430 option lists, but only with
218 431 long options:
219 432
220 433 -X --exclude filter an
221 434 option
222 435 with a
223 436 short
224 437 and
225 438 long
226 439 option
227 440 with an
228 441 argumen
229 442 t
230 443 -I --include an
231 444 option
232 445 with
233 446 both a
234 447 short
235 448 option
236 449 and a
237 450 long
238 451 option
239 452 --all Output
240 453 all.
241 454 --both Output
242 455 both
243 456 (this d
244 457 escript
245 458 ion is
246 459 quite
247 460 long).
248 461 --long Output
249 462 all day
250 463 long.
251 464 --par This
252 465 option
253 466 has two
254 467 paragra
255 468 phs in
256 469 its des
257 470 criptio
258 471 n. This
259 472 is the
260 473 first.
261 474
262 475 This is
263 476 the
264 477 second.
265 478 Blank
266 479 lines
267 480 may be
268 481 omitted
269 482 between
270 483 options
271 484 (as
272 485 above)
273 486 or left
274 487 in (as
275 488 here).
276 489
277 490 The next paragraph looks like
278 491 an option list, but lacks the
279 492 two-space marker after the
280 493 option. It is treated as a
281 494 normal paragraph:
282 495
283 496 --foo bar baz
284 497
285 498 ----------------------------------------------------------------------
499 <p>
500 There is support for simple option lists,
501 but only with long options:
502 </p>
503 <dl>
504 <dt>-X --exclude filter
505 <dd>an option with a short and long option with an argument
506 <dt>-I --include
507 <dd>an option with both a short option and a long option
508 <dt> --all
509 <dd>Output all.
510 <dt> --both
511 <dd>Output both (this description is quite long).
512 <dt> --long
513 <dd>Output all day long.
514 <dt> --par
515 <dd>This option has two paragraphs in its description. This is the first.
516 <p>
517 This is the second. Blank lines may be omitted between
518 options (as above) or left in (as here).
519 </p>
520 </dl>
521 <p>
522 The next paragraph looks like an option list, but lacks the two-space
523 marker after the option. It is treated as a normal paragraph:
524 </p>
525 <p>
526 --foo bar baz
527 </p>
528
529 ----------------------------------------------------------------------
286 530
287 531 fields formatted to fit within 60 characters:
288 532 ----------------------------------------------------------------------
289 533 a First item.
290 534 ab Second item. Indentation and wrapping is handled
291 535 automatically.
292 536
293 537 Next list:
294 538
295 539 small The larger key below triggers full indentation
296 540 here.
297 541 much too large
298 542 This key is big enough to get its own line.
299 543
300 544 ----------------------------------------------------------------------
545 <dl>
546 <dt>a
547 <dd>First item.
548 <dt>ab
549 <dd>Second item. Indentation and wrapping is handled automatically.
550 </dl>
551 <p>
552 Next list:
553 </p>
554 <dl>
555 <dt>small
556 <dd>The larger key below triggers full indentation here.
557 <dt>much too large
558 <dd>This key is big enough to get its own line.
559 </dl>
560
561 ----------------------------------------------------------------------
301 562
302 563 fields formatted to fit within 30 characters:
303 564 ----------------------------------------------------------------------
304 565 a First item.
305 566 ab Second item. Indentation
306 567 and wrapping is handled
307 568 automatically.
308 569
309 570 Next list:
310 571
311 572 small The larger key
312 573 below triggers
313 574 full indentation
314 575 here.
315 576 much too large
316 577 This key is big
317 578 enough to get its
318 579 own line.
319 580
320 581 ----------------------------------------------------------------------
582 <dl>
583 <dt>a
584 <dd>First item.
585 <dt>ab
586 <dd>Second item. Indentation and wrapping is handled automatically.
587 </dl>
588 <p>
589 Next list:
590 </p>
591 <dl>
592 <dt>small
593 <dd>The larger key below triggers full indentation here.
594 <dt>much too large
595 <dd>This key is big enough to get its own line.
596 </dl>
597
598 ----------------------------------------------------------------------
321 599
322 600 containers (normal) formatted to fit within 60 characters:
323 601 ----------------------------------------------------------------------
324 602 Normal output.
325 603
326 604 ----------------------------------------------------------------------
605 <p>
606 Normal output.
607 </p>
608
609 ----------------------------------------------------------------------
327 610
328 611 containers (verbose) formatted to fit within 60 characters:
329 612 ----------------------------------------------------------------------
330 613 Normal output.
331 614
332 615 Verbose output.
333 616
334 617 ----------------------------------------------------------------------
335 618 ['debug', 'debug']
336 619 ----------------------------------------------------------------------
620 <p>
621 Normal output.
622 </p>
623 <p>
624 Verbose output.
625 </p>
626
627 ----------------------------------------------------------------------
337 628
338 629 containers (debug) formatted to fit within 60 characters:
339 630 ----------------------------------------------------------------------
340 631 Normal output.
341 632
342 633 Initial debug output.
343 634
344 635 ----------------------------------------------------------------------
345 636 ['verbose']
346 637 ----------------------------------------------------------------------
638 <p>
639 Normal output.
640 </p>
641 <p>
642 Initial debug output.
643 </p>
644
645 ----------------------------------------------------------------------
347 646
348 647 containers (verbose debug) formatted to fit within 60 characters:
349 648 ----------------------------------------------------------------------
350 649 Normal output.
351 650
352 651 Initial debug output.
353 652
354 653 Verbose output.
355 654
356 655 Debug output.
357 656
358 657 ----------------------------------------------------------------------
359 658 []
360 659 ----------------------------------------------------------------------
660 <p>
661 Normal output.
662 </p>
663 <p>
664 Initial debug output.
665 </p>
666 <p>
667 Verbose output.
668 </p>
669 <p>
670 Debug output.
671 </p>
672
673 ----------------------------------------------------------------------
361 674
362 675 roles formatted to fit within 60 characters:
363 676 ----------------------------------------------------------------------
364 677 Please see "hg add".
365 678
366 679 ----------------------------------------------------------------------
680 <p>
681 Please see "hg add".
682 </p>
683
684 ----------------------------------------------------------------------
367 685
368 686 sections formatted to fit within 20 characters:
369 687 ----------------------------------------------------------------------
370 688 Title
371 689 =====
372 690
373 691 Section
374 692 -------
375 693
376 694 Subsection
377 695 ''''''''''
378 696
379 697 Markup: "foo" and "hg help"
380 698 ---------------------------
381 699
382 700 ----------------------------------------------------------------------
701 <h1>Title</h1>
702 <h2>Section</h2>
703 <h3>Subsection</h3>
704 <h2>Markup: "foo" and "hg help"</h2>
705
706 ----------------------------------------------------------------------
383 707
384 708 admonitions formatted to fit within 30 characters:
385 709 ----------------------------------------------------------------------
386 710 Note:
387 711 This is a note
388 712
389 713 - Bullet 1
390 714 - Bullet 2
391 715
392 716 Warning!
393 717 This is a warning Second
394 718 input line of warning
395 719
396 720 !Danger!
397 721 This is danger
398 722
399 723 ----------------------------------------------------------------------
724 <p>
725 <b>Note:</b> This is a note
726 </p>
727 <ul>
728 <li> Bullet 1
729 <li> Bullet 2
730 </ul>
731 <p>
732 <b>Warning!</b> This is a warning Second input line of warning
733 </p>
734 <p>
735 <b>!Danger!</b> This is danger
736 </p>
737
738 ----------------------------------------------------------------------
400 739
401 740 comments formatted to fit within 30 characters:
402 741 ----------------------------------------------------------------------
403 742 Some text.
404 743
405 744 Some indented text.
406 745
407 746 Empty comment above
408 747
409 748 ----------------------------------------------------------------------
749 <p>
750 Some text.
751 </p>
752 <p>
753 Some indented text.
754 </p>
755 <p>
756 Empty comment above
757 </p>
758
759 ----------------------------------------------------------------------
410 760
411 761 === === ========================================
412 762 a b c
413 763 === === ========================================
414 764 1 2 3
415 765 foo bar baz this list is very very very long man
416 766 === === ========================================
417 767
418 768 table formatted to fit within 30 characters:
419 769 ----------------------------------------------------------------------
420 770 a b c
421 771 ------------------------------
422 772 1 2 3
423 773 foo bar baz this list is
424 774 very very very long
425 775 man
426 776
427 777 ----------------------------------------------------------------------
778 <table>
779 <tr><th>a</th><th>b</th><th>c</th></tr>
780 <tr><td>1</td><td>2</td><td>3</td></tr>
781 <tr><td>foo</td><td>bar</td><td>baz this list is very very very long man</td></tr>
782 </table>
428 783
784 ----------------------------------------------------------------------
785
General Comments 0
You need to be logged in to leave comments. Login now