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