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