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