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