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