##// END OF EJS Templates
minirst: improved support for option lists....
Erik Zielke -
r13011:4936a04b default
parent child Browse files
Show More
@@ -1,434 +1,482 b''
1 # minirst.py - minimal reStructuredText parser
1 # minirst.py - minimal reStructuredText parser
2 #
2 #
3 # Copyright 2009, 2010 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2009, 2010 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """simplified reStructuredText parser.
8 """simplified reStructuredText parser.
9
9
10 This parser knows just enough about reStructuredText to parse the
10 This parser knows just enough about reStructuredText to parse the
11 Mercurial docstrings.
11 Mercurial docstrings.
12
12
13 It cheats in a major way: nested blocks are not really nested. They
13 It cheats in a major way: nested blocks are not really nested. They
14 are just indented blocks that look like they are nested. This relies
14 are just indented blocks that look like they are nested. This relies
15 on the user to keep the right indentation for the blocks.
15 on the user to keep the right indentation for the blocks.
16
16
17 Remember to update http://mercurial.selenic.com/wiki/HelpStyleGuide
17 Remember to update http://mercurial.selenic.com/wiki/HelpStyleGuide
18 when adding support for new constructs.
18 when adding support for new constructs.
19 """
19 """
20
20
21 import re, sys
21 import re, sys
22 import util, encoding
22 import util, encoding
23 from i18n import _
23 from i18n import _
24
24
25
25
26 def replace(text, substs):
26 def replace(text, substs):
27 utext = text.decode(encoding.encoding)
27 utext = text.decode(encoding.encoding)
28 for f, t in substs:
28 for f, t in substs:
29 utext = utext.replace(f, t)
29 utext = utext.replace(f, t)
30 return utext.encode(encoding.encoding)
30 return utext.encode(encoding.encoding)
31
31
32
32
33 _blockre = re.compile(r"\n(?:\s*\n)+")
33 _blockre = re.compile(r"\n(?:\s*\n)+")
34
34
35 def findblocks(text):
35 def findblocks(text):
36 """Find continuous blocks of lines in text.
36 """Find continuous blocks of lines in text.
37
37
38 Returns a list of dictionaries representing the blocks. Each block
38 Returns a list of dictionaries representing the blocks. Each block
39 has an 'indent' field and a 'lines' field.
39 has an 'indent' field and a 'lines' field.
40 """
40 """
41 blocks = []
41 blocks = []
42 for b in _blockre.split(text.strip()):
42 for b in _blockre.split(text.strip()):
43 lines = b.splitlines()
43 lines = b.splitlines()
44 indent = min((len(l) - len(l.lstrip())) for l in lines)
44 indent = min((len(l) - len(l.lstrip())) for l in lines)
45 lines = [l[indent:] for l in lines]
45 lines = [l[indent:] for l in lines]
46 blocks.append(dict(indent=indent, lines=lines))
46 blocks.append(dict(indent=indent, lines=lines))
47 return blocks
47 return blocks
48
48
49
49
50 def findliteralblocks(blocks):
50 def findliteralblocks(blocks):
51 """Finds literal blocks and adds a 'type' field to the blocks.
51 """Finds literal blocks and adds a 'type' field to the blocks.
52
52
53 Literal blocks are given the type 'literal', all other blocks are
53 Literal blocks are given the type 'literal', all other blocks are
54 given type the 'paragraph'.
54 given type the 'paragraph'.
55 """
55 """
56 i = 0
56 i = 0
57 while i < len(blocks):
57 while i < len(blocks):
58 # Searching for a block that looks like this:
58 # Searching for a block that looks like this:
59 #
59 #
60 # +------------------------------+
60 # +------------------------------+
61 # | paragraph |
61 # | paragraph |
62 # | (ends with "::") |
62 # | (ends with "::") |
63 # +------------------------------+
63 # +------------------------------+
64 # +---------------------------+
64 # +---------------------------+
65 # | indented literal block |
65 # | indented literal block |
66 # +---------------------------+
66 # +---------------------------+
67 blocks[i]['type'] = 'paragraph'
67 blocks[i]['type'] = 'paragraph'
68 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
68 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
69 indent = blocks[i]['indent']
69 indent = blocks[i]['indent']
70 adjustment = blocks[i + 1]['indent'] - indent
70 adjustment = blocks[i + 1]['indent'] - indent
71
71
72 if blocks[i]['lines'] == ['::']:
72 if blocks[i]['lines'] == ['::']:
73 # Expanded form: remove block
73 # Expanded form: remove block
74 del blocks[i]
74 del blocks[i]
75 i -= 1
75 i -= 1
76 elif blocks[i]['lines'][-1].endswith(' ::'):
76 elif blocks[i]['lines'][-1].endswith(' ::'):
77 # Partially minimized form: remove space and both
77 # Partially minimized form: remove space and both
78 # colons.
78 # colons.
79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
80 else:
80 else:
81 # Fully minimized form: remove just one colon.
81 # Fully minimized form: remove just one colon.
82 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
82 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
83
83
84 # List items are formatted with a hanging indent. We must
84 # List items are formatted with a hanging indent. We must
85 # correct for this here while we still have the original
85 # correct for this here while we still have the original
86 # information on the indentation of the subsequent literal
86 # information on the indentation of the subsequent literal
87 # blocks available.
87 # blocks available.
88 m = _bulletre.match(blocks[i]['lines'][0])
88 m = _bulletre.match(blocks[i]['lines'][0])
89 if m:
89 if m:
90 indent += m.end()
90 indent += m.end()
91 adjustment -= m.end()
91 adjustment -= m.end()
92
92
93 # Mark the following indented blocks.
93 # Mark the following indented blocks.
94 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
94 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
95 blocks[i + 1]['type'] = 'literal'
95 blocks[i + 1]['type'] = 'literal'
96 blocks[i + 1]['indent'] -= adjustment
96 blocks[i + 1]['indent'] -= adjustment
97 i += 1
97 i += 1
98 i += 1
98 i += 1
99 return blocks
99 return blocks
100
100
101 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
101 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
102 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
102 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
103 r'((.*) +)(.*)$')
103 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
104 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
104 _definitionre = re.compile(r'[^ ]')
105 _definitionre = re.compile(r'[^ ]')
105
106
106 def splitparagraphs(blocks):
107 def splitparagraphs(blocks):
107 """Split paragraphs into lists."""
108 """Split paragraphs into lists."""
108 # Tuples with (list type, item regexp, single line items?). Order
109 # Tuples with (list type, item regexp, single line items?). Order
109 # matters: definition lists has the least specific regexp and must
110 # matters: definition lists has the least specific regexp and must
110 # come last.
111 # come last.
111 listtypes = [('bullet', _bulletre, True),
112 listtypes = [('bullet', _bulletre, True),
112 ('option', _optionre, True),
113 ('option', _optionre, True),
113 ('field', _fieldre, True),
114 ('field', _fieldre, True),
114 ('definition', _definitionre, False)]
115 ('definition', _definitionre, False)]
115
116
116 def match(lines, i, itemre, singleline):
117 def match(lines, i, itemre, singleline):
117 """Does itemre match an item at line i?
118 """Does itemre match an item at line i?
118
119
119 A list item can be followed by an idented line or another list
120 A list item can be followed by an idented line or another list
120 item (but only if singleline is True).
121 item (but only if singleline is True).
121 """
122 """
122 line1 = lines[i]
123 line1 = lines[i]
123 line2 = i + 1 < len(lines) and lines[i + 1] or ''
124 line2 = i + 1 < len(lines) and lines[i + 1] or ''
124 if not itemre.match(line1):
125 if not itemre.match(line1):
125 return False
126 return False
126 if singleline:
127 if singleline:
127 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
128 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
128 else:
129 else:
129 return line2.startswith(' ')
130 return line2.startswith(' ')
130
131
131 i = 0
132 i = 0
132 while i < len(blocks):
133 while i < len(blocks):
133 if blocks[i]['type'] == 'paragraph':
134 if blocks[i]['type'] == 'paragraph':
134 lines = blocks[i]['lines']
135 lines = blocks[i]['lines']
135 for type, itemre, singleline in listtypes:
136 for type, itemre, singleline in listtypes:
136 if match(lines, 0, itemre, singleline):
137 if match(lines, 0, itemre, singleline):
137 items = []
138 items = []
138 for j, line in enumerate(lines):
139 for j, line in enumerate(lines):
139 if match(lines, j, itemre, singleline):
140 if match(lines, j, itemre, singleline):
140 items.append(dict(type=type, lines=[],
141 items.append(dict(type=type, lines=[],
141 indent=blocks[i]['indent']))
142 indent=blocks[i]['indent']))
142 items[-1]['lines'].append(line)
143 items[-1]['lines'].append(line)
143 blocks[i:i + 1] = items
144 blocks[i:i + 1] = items
144 break
145 break
145 i += 1
146 i += 1
146 return blocks
147 return blocks
147
148
148
149
149 _fieldwidth = 12
150 _fieldwidth = 12
150
151
151 def updatefieldlists(blocks):
152 def updatefieldlists(blocks):
152 """Find key and maximum key width for field lists."""
153 """Find key and maximum key width for field lists."""
153 i = 0
154 i = 0
154 while i < len(blocks):
155 while i < len(blocks):
155 if blocks[i]['type'] != 'field':
156 if blocks[i]['type'] != 'field':
156 i += 1
157 i += 1
157 continue
158 continue
158
159
159 keywidth = 0
160 keywidth = 0
160 j = i
161 j = i
161 while j < len(blocks) and blocks[j]['type'] == 'field':
162 while j < len(blocks) and blocks[j]['type'] == 'field':
162 m = _fieldre.match(blocks[j]['lines'][0])
163 m = _fieldre.match(blocks[j]['lines'][0])
163 key, rest = m.groups()
164 key, rest = m.groups()
164 blocks[j]['lines'][0] = rest
165 blocks[j]['lines'][0] = rest
165 blocks[j]['key'] = key
166 blocks[j]['key'] = key
166 keywidth = max(keywidth, len(key))
167 keywidth = max(keywidth, len(key))
167 j += 1
168 j += 1
168
169
169 for block in blocks[i:j]:
170 for block in blocks[i:j]:
170 block['keywidth'] = keywidth
171 block['keywidth'] = keywidth
171 i = j + 1
172 i = j + 1
172
173
173 return blocks
174 return blocks
174
175
175
176
177 def updateoptionlists(blocks):
178 i = 0
179 while i < len(blocks):
180 if blocks[i]['type'] != 'option':
181 i += 1
182 continue
183
184 optstrwidth = 0
185 j = i
186 while j < len(blocks) and blocks[j]['type'] == 'option':
187 m = _optionre.match(blocks[j]['lines'][0])
188
189 shortoption = m.group(2)
190 group3 = m.group(3)
191 longoption = group3[2:].strip()
192 desc = m.group(6).strip()
193 longoptionarg = m.group(5).strip()
194 blocks[j]['lines'][0] = desc
195
196 noshortop = ''
197 if not shortoption:
198 noshortop = ' '
199
200 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
201 ("%s--%s %s") % (noshortop, longoption,
202 longoptionarg))
203 opt = opt.rstrip()
204 blocks[j]['optstr'] = opt
205 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
206 j += 1
207
208 for block in blocks[i:j]:
209 block['optstrwidth'] = optstrwidth
210 i = j + 1
211 return blocks
212
176 def prunecontainers(blocks, keep):
213 def prunecontainers(blocks, keep):
177 """Prune unwanted containers.
214 """Prune unwanted containers.
178
215
179 The blocks must have a 'type' field, i.e., they should have been
216 The blocks must have a 'type' field, i.e., they should have been
180 run through findliteralblocks first.
217 run through findliteralblocks first.
181 """
218 """
182 pruned = []
219 pruned = []
183 i = 0
220 i = 0
184 while i + 1 < len(blocks):
221 while i + 1 < len(blocks):
185 # Searching for a block that looks like this:
222 # Searching for a block that looks like this:
186 #
223 #
187 # +-------+---------------------------+
224 # +-------+---------------------------+
188 # | ".. container ::" type |
225 # | ".. container ::" type |
189 # +---+ |
226 # +---+ |
190 # | blocks |
227 # | blocks |
191 # +-------------------------------+
228 # +-------------------------------+
192 if (blocks[i]['type'] == 'paragraph' and
229 if (blocks[i]['type'] == 'paragraph' and
193 blocks[i]['lines'][0].startswith('.. container::')):
230 blocks[i]['lines'][0].startswith('.. container::')):
194 indent = blocks[i]['indent']
231 indent = blocks[i]['indent']
195 adjustment = blocks[i + 1]['indent'] - indent
232 adjustment = blocks[i + 1]['indent'] - indent
196 containertype = blocks[i]['lines'][0][15:]
233 containertype = blocks[i]['lines'][0][15:]
197 prune = containertype not in keep
234 prune = containertype not in keep
198 if prune:
235 if prune:
199 pruned.append(containertype)
236 pruned.append(containertype)
200
237
201 # Always delete "..container:: type" block
238 # Always delete "..container:: type" block
202 del blocks[i]
239 del blocks[i]
203 j = i
240 j = i
204 while j < len(blocks) and blocks[j]['indent'] > indent:
241 while j < len(blocks) and blocks[j]['indent'] > indent:
205 if prune:
242 if prune:
206 del blocks[j]
243 del blocks[j]
207 i -= 1 # adjust outer index
244 i -= 1 # adjust outer index
208 else:
245 else:
209 blocks[j]['indent'] -= adjustment
246 blocks[j]['indent'] -= adjustment
210 j += 1
247 j += 1
211 i += 1
248 i += 1
212 return blocks, pruned
249 return blocks, pruned
213
250
214
251
215 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
252 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
216
253
217 def findsections(blocks):
254 def findsections(blocks):
218 """Finds sections.
255 """Finds sections.
219
256
220 The blocks must have a 'type' field, i.e., they should have been
257 The blocks must have a 'type' field, i.e., they should have been
221 run through findliteralblocks first.
258 run through findliteralblocks first.
222 """
259 """
223 for block in blocks:
260 for block in blocks:
224 # Searching for a block that looks like this:
261 # Searching for a block that looks like this:
225 #
262 #
226 # +------------------------------+
263 # +------------------------------+
227 # | Section title |
264 # | Section title |
228 # | ------------- |
265 # | ------------- |
229 # +------------------------------+
266 # +------------------------------+
230 if (block['type'] == 'paragraph' and
267 if (block['type'] == 'paragraph' and
231 len(block['lines']) == 2 and
268 len(block['lines']) == 2 and
232 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
269 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
233 _sectionre.match(block['lines'][1])):
270 _sectionre.match(block['lines'][1])):
234 block['underline'] = block['lines'][1][0]
271 block['underline'] = block['lines'][1][0]
235 block['type'] = 'section'
272 block['type'] = 'section'
236 del block['lines'][1]
273 del block['lines'][1]
237 return blocks
274 return blocks
238
275
239
276
240 def inlineliterals(blocks):
277 def inlineliterals(blocks):
241 substs = [('``', '"')]
278 substs = [('``', '"')]
242 for b in blocks:
279 for b in blocks:
243 if b['type'] in ('paragraph', 'section'):
280 if b['type'] in ('paragraph', 'section'):
244 b['lines'] = [replace(l, substs) for l in b['lines']]
281 b['lines'] = [replace(l, substs) for l in b['lines']]
245 return blocks
282 return blocks
246
283
247
284
248 def hgrole(blocks):
285 def hgrole(blocks):
249 substs = [(':hg:`', '"hg '), ('`', '"')]
286 substs = [(':hg:`', '"hg '), ('`', '"')]
250 for b in blocks:
287 for b in blocks:
251 if b['type'] in ('paragraph', 'section'):
288 if b['type'] in ('paragraph', 'section'):
252 # Turn :hg:`command` into "hg command". This also works
289 # Turn :hg:`command` into "hg command". This also works
253 # when there is a line break in the command and relies on
290 # when there is a line break in the command and relies on
254 # the fact that we have no stray back-quotes in the input
291 # the fact that we have no stray back-quotes in the input
255 # (run the blocks through inlineliterals first).
292 # (run the blocks through inlineliterals first).
256 b['lines'] = [replace(l, substs) for l in b['lines']]
293 b['lines'] = [replace(l, substs) for l in b['lines']]
257 return blocks
294 return blocks
258
295
259
296
260 def addmargins(blocks):
297 def addmargins(blocks):
261 """Adds empty blocks for vertical spacing.
298 """Adds empty blocks for vertical spacing.
262
299
263 This groups bullets, options, and definitions together with no vertical
300 This groups bullets, options, and definitions together with no vertical
264 space between them, and adds an empty block between all other blocks.
301 space between them, and adds an empty block between all other blocks.
265 """
302 """
266 i = 1
303 i = 1
267 while i < len(blocks):
304 while i < len(blocks):
268 if (blocks[i]['type'] == blocks[i - 1]['type'] and
305 if (blocks[i]['type'] == blocks[i - 1]['type'] and
269 blocks[i]['type'] in ('bullet', 'option', 'field')):
306 blocks[i]['type'] in ('bullet', 'option', 'field')):
270 i += 1
307 i += 1
271 else:
308 else:
272 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
309 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
273 i += 2
310 i += 2
274 return blocks
311 return blocks
275
312
276 def prunecomments(blocks):
313 def prunecomments(blocks):
277 """Remove comments."""
314 """Remove comments."""
278 i = 0
315 i = 0
279 while i < len(blocks):
316 while i < len(blocks):
280 b = blocks[i]
317 b = blocks[i]
281 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
318 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
282 b['lines'] == ['..']):
319 b['lines'] == ['..']):
283 del blocks[i]
320 del blocks[i]
284 if i < len(blocks) and blocks[i]['type'] == 'margin':
321 if i < len(blocks) and blocks[i]['type'] == 'margin':
285 del blocks[i]
322 del blocks[i]
286 else:
323 else:
287 i += 1
324 i += 1
288 return blocks
325 return blocks
289
326
290 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
327 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
291 r"error|hint|important|note|tip|warning)::",
328 r"error|hint|important|note|tip|warning)::",
292 flags=re.IGNORECASE)
329 flags=re.IGNORECASE)
293
330
294 def findadmonitions(blocks):
331 def findadmonitions(blocks):
295 """
332 """
296 Makes the type of the block an admonition block if
333 Makes the type of the block an admonition block if
297 the first line is an admonition directive
334 the first line is an admonition directive
298 """
335 """
299 i = 0
336 i = 0
300 while i < len(blocks):
337 while i < len(blocks):
301 m = _admonitionre.match(blocks[i]['lines'][0])
338 m = _admonitionre.match(blocks[i]['lines'][0])
302 if m:
339 if m:
303 blocks[i]['type'] = 'admonition'
340 blocks[i]['type'] = 'admonition'
304 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
341 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
305
342
306 firstline = blocks[i]['lines'][0][m.end() + 1:]
343 firstline = blocks[i]['lines'][0][m.end() + 1:]
307 if firstline:
344 if firstline:
308 blocks[i]['lines'].insert(1, ' ' + firstline)
345 blocks[i]['lines'].insert(1, ' ' + firstline)
309
346
310 blocks[i]['admonitiontitle'] = admonitiontitle
347 blocks[i]['admonitiontitle'] = admonitiontitle
311 del blocks[i]['lines'][0]
348 del blocks[i]['lines'][0]
312 i = i + 1
349 i = i + 1
313 return blocks
350 return blocks
314
351
315 _admonitiontitles = {'attention': _('Attention:'),
352 _admonitiontitles = {'attention': _('Attention:'),
316 'caution': _('Caution:'),
353 'caution': _('Caution:'),
317 'danger': _('!Danger!') ,
354 'danger': _('!Danger!') ,
318 'error': _('Error:'),
355 'error': _('Error:'),
319 'hint': _('Hint:'),
356 'hint': _('Hint:'),
320 'important': _('Important:'),
357 'important': _('Important:'),
321 'note': _('Note:'),
358 'note': _('Note:'),
322 'tip': _('Tip:'),
359 'tip': _('Tip:'),
323 'warning': _('Warning!')}
360 'warning': _('Warning!')}
324
361
362 def formatoption(block, width):
363 desc = ' '.join(map(str.strip, block['lines']))
364 colwidth = encoding.colwidth(block['optstr'])
365 usablewidth = width - 1
366 hanging = block['optstrwidth']
367 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
368 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
369 return ' %s' % (util.wrap(desc, usablewidth,
370 initindent=initindent,
371 hangindent=hangindent))
372
325 def formatblock(block, width):
373 def formatblock(block, width):
326 """Format a block according to width."""
374 """Format a block according to width."""
327 if width <= 0:
375 if width <= 0:
328 width = 78
376 width = 78
329 indent = ' ' * block['indent']
377 indent = ' ' * block['indent']
330 if block['type'] == 'admonition':
378 if block['type'] == 'admonition':
331 admonition = _admonitiontitles[block['admonitiontitle']]
379 admonition = _admonitiontitles[block['admonitiontitle']]
332 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
380 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
333
381
334 defindent = indent + hang * ' '
382 defindent = indent + hang * ' '
335 text = ' '.join(map(str.strip, block['lines']))
383 text = ' '.join(map(str.strip, block['lines']))
336 return '%s\n%s' % (indent + admonition, util.wrap(text, width=width,
384 return '%s\n%s' % (indent + admonition, util.wrap(text, width=width,
337 initindent=defindent,
385 initindent=defindent,
338 hangindent=defindent))
386 hangindent=defindent))
339 if block['type'] == 'margin':
387 if block['type'] == 'margin':
340 return ''
388 return ''
341 if block['type'] == 'literal':
389 if block['type'] == 'literal':
342 indent += ' '
390 indent += ' '
343 return indent + ('\n' + indent).join(block['lines'])
391 return indent + ('\n' + indent).join(block['lines'])
344 if block['type'] == 'section':
392 if block['type'] == 'section':
345 underline = encoding.colwidth(block['lines'][0]) * block['underline']
393 underline = encoding.colwidth(block['lines'][0]) * block['underline']
346 return "%s%s\n%s%s" % (indent, block['lines'][0],indent, underline)
394 return "%s%s\n%s%s" % (indent, block['lines'][0],indent, underline)
347 if block['type'] == 'definition':
395 if block['type'] == 'definition':
348 term = indent + block['lines'][0]
396 term = indent + block['lines'][0]
349 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
397 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
350 defindent = indent + hang * ' '
398 defindent = indent + hang * ' '
351 text = ' '.join(map(str.strip, block['lines'][1:]))
399 text = ' '.join(map(str.strip, block['lines'][1:]))
352 return '%s\n%s' % (term, util.wrap(text, width=width,
400 return '%s\n%s' % (term, util.wrap(text, width=width,
353 initindent=defindent,
401 initindent=defindent,
354 hangindent=defindent))
402 hangindent=defindent))
355 subindent = indent
403 subindent = indent
356 if block['type'] == 'bullet':
404 if block['type'] == 'bullet':
357 if block['lines'][0].startswith('| '):
405 if block['lines'][0].startswith('| '):
358 # Remove bullet for line blocks and add no extra
406 # Remove bullet for line blocks and add no extra
359 # indention.
407 # indention.
360 block['lines'][0] = block['lines'][0][2:]
408 block['lines'][0] = block['lines'][0][2:]
361 else:
409 else:
362 m = _bulletre.match(block['lines'][0])
410 m = _bulletre.match(block['lines'][0])
363 subindent = indent + m.end() * ' '
411 subindent = indent + m.end() * ' '
364 elif block['type'] == 'field':
412 elif block['type'] == 'field':
365 keywidth = block['keywidth']
413 keywidth = block['keywidth']
366 key = block['key']
414 key = block['key']
367
415
368 subindent = indent + _fieldwidth * ' '
416 subindent = indent + _fieldwidth * ' '
369 if len(key) + 2 > _fieldwidth:
417 if len(key) + 2 > _fieldwidth:
370 # key too large, use full line width
418 # key too large, use full line width
371 key = key.ljust(width)
419 key = key.ljust(width)
372 elif keywidth + 2 < _fieldwidth:
420 elif keywidth + 2 < _fieldwidth:
373 # all keys are small, add only two spaces
421 # all keys are small, add only two spaces
374 key = key.ljust(keywidth + 2)
422 key = key.ljust(keywidth + 2)
375 subindent = indent + (keywidth + 2) * ' '
423 subindent = indent + (keywidth + 2) * ' '
376 else:
424 else:
377 # mixed sizes, use fieldwidth for this one
425 # mixed sizes, use fieldwidth for this one
378 key = key.ljust(_fieldwidth)
426 key = key.ljust(_fieldwidth)
379 block['lines'][0] = key + block['lines'][0]
427 block['lines'][0] = key + block['lines'][0]
380 elif block['type'] == 'option':
428 elif block['type'] == 'option':
381 m = _optionre.match(block['lines'][0])
429 return formatoption(block, width)
382 option, arg, rest = m.groups()
383 subindent = indent + (len(option) + len(arg)) * ' '
384
430
385 text = ' '.join(map(str.strip, block['lines']))
431 text = ' '.join(map(str.strip, block['lines']))
386 return util.wrap(text, width=width,
432 return util.wrap(text, width=width,
387 initindent=indent,
433 initindent=indent,
388 hangindent=subindent)
434 hangindent=subindent)
389
435
390
436
391 def format(text, width, indent=0, keep=None):
437 def format(text, width, indent=0, keep=None):
392 """Parse and format the text according to width."""
438 """Parse and format the text according to width."""
393 blocks = findblocks(text)
439 blocks = findblocks(text)
394 for b in blocks:
440 for b in blocks:
395 b['indent'] += indent
441 b['indent'] += indent
396 blocks = findliteralblocks(blocks)
442 blocks = findliteralblocks(blocks)
397 blocks, pruned = prunecontainers(blocks, keep or [])
443 blocks, pruned = prunecontainers(blocks, keep or [])
398 blocks = findsections(blocks)
444 blocks = findsections(blocks)
399 blocks = inlineliterals(blocks)
445 blocks = inlineliterals(blocks)
400 blocks = hgrole(blocks)
446 blocks = hgrole(blocks)
401 blocks = splitparagraphs(blocks)
447 blocks = splitparagraphs(blocks)
402 blocks = updatefieldlists(blocks)
448 blocks = updatefieldlists(blocks)
449 blocks = updateoptionlists(blocks)
403 blocks = addmargins(blocks)
450 blocks = addmargins(blocks)
404 blocks = prunecomments(blocks)
451 blocks = prunecomments(blocks)
405 blocks = findadmonitions(blocks)
452 blocks = findadmonitions(blocks)
406 text = '\n'.join(formatblock(b, width) for b in blocks)
453 text = '\n'.join(formatblock(b, width) for b in blocks)
407 if keep is None:
454 if keep is None:
408 return text
455 return text
409 else:
456 else:
410 return text, pruned
457 return text, pruned
411
458
412
459
413 if __name__ == "__main__":
460 if __name__ == "__main__":
414 from pprint import pprint
461 from pprint import pprint
415
462
416 def debug(func, *args):
463 def debug(func, *args):
417 blocks = func(*args)
464 blocks = func(*args)
418 print "*** after %s:" % func.__name__
465 print "*** after %s:" % func.__name__
419 pprint(blocks)
466 pprint(blocks)
420 print
467 print
421 return blocks
468 return blocks
422
469
423 text = open(sys.argv[1]).read()
470 text = open(sys.argv[1]).read()
424 blocks = debug(findblocks, text)
471 blocks = debug(findblocks, text)
425 blocks = debug(findliteralblocks, blocks)
472 blocks = debug(findliteralblocks, blocks)
426 blocks, pruned = debug(prunecontainers, blocks, sys.argv[2:])
473 blocks, pruned = debug(prunecontainers, blocks, sys.argv[2:])
427 blocks = debug(inlineliterals, blocks)
474 blocks = debug(inlineliterals, blocks)
428 blocks = debug(splitparagraphs, blocks)
475 blocks = debug(splitparagraphs, blocks)
429 blocks = debug(updatefieldlists, blocks)
476 blocks = debug(updatefieldlists, blocks)
477 blocks = debug(updateoptionlists, blocks)
430 blocks = debug(findsections, blocks)
478 blocks = debug(findsections, blocks)
431 blocks = debug(addmargins, blocks)
479 blocks = debug(addmargins, blocks)
432 blocks = debug(prunecomments, blocks)
480 blocks = debug(prunecomments, blocks)
433 blocks = debug(findadmonitions, blocks)
481 blocks = debug(findadmonitions, blocks)
434 print '\n'.join(formatblock(b, 30) for b in blocks)
482 print '\n'.join(formatblock(b, 30) for b in blocks)
@@ -1,392 +1,392 b''
1
1
2 $ cat >> $HGRCPATH <<EOF
2 $ cat >> $HGRCPATH <<EOF
3 > [extensions]
3 > [extensions]
4 > convert=
4 > convert=
5 > [convert]
5 > [convert]
6 > hg.saverev=False
6 > hg.saverev=False
7 > EOF
7 > EOF
8 $ hg help convert
8 $ hg help convert
9 hg convert [OPTION]... SOURCE [DEST [REVMAP]]
9 hg convert [OPTION]... SOURCE [DEST [REVMAP]]
10
10
11 convert a foreign SCM repository to a Mercurial one.
11 convert a foreign SCM repository to a Mercurial one.
12
12
13 Accepted source formats [identifiers]:
13 Accepted source formats [identifiers]:
14
14
15 - Mercurial [hg]
15 - Mercurial [hg]
16 - CVS [cvs]
16 - CVS [cvs]
17 - Darcs [darcs]
17 - Darcs [darcs]
18 - git [git]
18 - git [git]
19 - Subversion [svn]
19 - Subversion [svn]
20 - Monotone [mtn]
20 - Monotone [mtn]
21 - GNU Arch [gnuarch]
21 - GNU Arch [gnuarch]
22 - Bazaar [bzr]
22 - Bazaar [bzr]
23 - Perforce [p4]
23 - Perforce [p4]
24
24
25 Accepted destination formats [identifiers]:
25 Accepted destination formats [identifiers]:
26
26
27 - Mercurial [hg]
27 - Mercurial [hg]
28 - Subversion [svn] (history on branches is not preserved)
28 - Subversion [svn] (history on branches is not preserved)
29
29
30 If no revision is given, all revisions will be converted. Otherwise,
30 If no revision is given, all revisions will be converted. Otherwise,
31 convert will only import up to the named revision (given in a format
31 convert will only import up to the named revision (given in a format
32 understood by the source).
32 understood by the source).
33
33
34 If no destination directory name is specified, it defaults to the basename
34 If no destination directory name is specified, it defaults to the basename
35 of the source with "-hg" appended. If the destination repository doesn't
35 of the source with "-hg" appended. If the destination repository doesn't
36 exist, it will be created.
36 exist, it will be created.
37
37
38 By default, all sources except Mercurial will use --branchsort. Mercurial
38 By default, all sources except Mercurial will use --branchsort. Mercurial
39 uses --sourcesort to preserve original revision numbers order. Sort modes
39 uses --sourcesort to preserve original revision numbers order. Sort modes
40 have the following effects:
40 have the following effects:
41
41
42 --branchsort convert from parent to child revision when possible, which
42 --branchsort convert from parent to child revision when possible, which
43 means branches are usually converted one after the other. It
43 means branches are usually converted one after the other.
44 generates more compact repositories.
44 It generates more compact repositories.
45 --datesort sort revisions by date. Converted repositories have good-
45 --datesort sort revisions by date. Converted repositories have good-
46 looking changelogs but are often an order of magnitude
46 looking changelogs but are often an order of magnitude
47 larger than the same ones generated by --branchsort.
47 larger than the same ones generated by --branchsort.
48 --sourcesort try to preserve source revisions order, only supported by
48 --sourcesort try to preserve source revisions order, only supported by
49 Mercurial sources.
49 Mercurial sources.
50
50
51 If "REVMAP" isn't given, it will be put in a default location
51 If "REVMAP" isn't given, it will be put in a default location
52 ("<dest>/.hg/shamap" by default). The "REVMAP" is a simple text file that
52 ("<dest>/.hg/shamap" by default). The "REVMAP" is a simple text file that
53 maps each source commit ID to the destination ID for that revision, like
53 maps each source commit ID to the destination ID for that revision, like
54 so:
54 so:
55
55
56 <source ID> <destination ID>
56 <source ID> <destination ID>
57
57
58 If the file doesn't exist, it's automatically created. It's updated on
58 If the file doesn't exist, it's automatically created. It's updated on
59 each commit copied, so "hg convert" can be interrupted and can be run
59 each commit copied, so "hg convert" can be interrupted and can be run
60 repeatedly to copy new commits.
60 repeatedly to copy new commits.
61
61
62 The authormap is a simple text file that maps each source commit author to
62 The authormap is a simple text file that maps each source commit author to
63 a destination commit author. It is handy for source SCMs that use unix
63 a destination commit author. It is handy for source SCMs that use unix
64 logins to identify authors (eg: CVS). One line per author mapping and the
64 logins to identify authors (eg: CVS). One line per author mapping and the
65 line format is:
65 line format is:
66
66
67 source author = destination author
67 source author = destination author
68
68
69 Empty lines and lines starting with a "#" are ignored.
69 Empty lines and lines starting with a "#" are ignored.
70
70
71 The filemap is a file that allows filtering and remapping of files and
71 The filemap is a file that allows filtering and remapping of files and
72 directories. Each line can contain one of the following directives:
72 directories. Each line can contain one of the following directives:
73
73
74 include path/to/file-or-dir
74 include path/to/file-or-dir
75
75
76 exclude path/to/file-or-dir
76 exclude path/to/file-or-dir
77
77
78 rename path/to/source path/to/destination
78 rename path/to/source path/to/destination
79
79
80 Comment lines start with "#". A specified path matches if it equals the
80 Comment lines start with "#". A specified path matches if it equals the
81 full relative name of a file or one of its parent directories. The
81 full relative name of a file or one of its parent directories. The
82 "include" or "exclude" directive with the longest matching path applies,
82 "include" or "exclude" directive with the longest matching path applies,
83 so line order does not matter.
83 so line order does not matter.
84
84
85 The "include" directive causes a file, or all files under a directory, to
85 The "include" directive causes a file, or all files under a directory, to
86 be included in the destination repository, and the exclusion of all other
86 be included in the destination repository, and the exclusion of all other
87 files and directories not explicitly included. The "exclude" directive
87 files and directories not explicitly included. The "exclude" directive
88 causes files or directories to be omitted. The "rename" directive renames
88 causes files or directories to be omitted. The "rename" directive renames
89 a file or directory if it is converted. To rename from a subdirectory into
89 a file or directory if it is converted. To rename from a subdirectory into
90 the root of the repository, use "." as the path to rename to.
90 the root of the repository, use "." as the path to rename to.
91
91
92 The splicemap is a file that allows insertion of synthetic history,
92 The splicemap is a file that allows insertion of synthetic history,
93 letting you specify the parents of a revision. This is useful if you want
93 letting you specify the parents of a revision. This is useful if you want
94 to e.g. give a Subversion merge two parents, or graft two disconnected
94 to e.g. give a Subversion merge two parents, or graft two disconnected
95 series of history together. Each entry contains a key, followed by a
95 series of history together. Each entry contains a key, followed by a
96 space, followed by one or two comma-separated values:
96 space, followed by one or two comma-separated values:
97
97
98 key parent1, parent2
98 key parent1, parent2
99
99
100 The key is the revision ID in the source revision control system whose
100 The key is the revision ID in the source revision control system whose
101 parents should be modified (same format as a key in .hg/shamap). The
101 parents should be modified (same format as a key in .hg/shamap). The
102 values are the revision IDs (in either the source or destination revision
102 values are the revision IDs (in either the source or destination revision
103 control system) that should be used as the new parents for that node. For
103 control system) that should be used as the new parents for that node. For
104 example, if you have merged "release-1.0" into "trunk", then you should
104 example, if you have merged "release-1.0" into "trunk", then you should
105 specify the revision on "trunk" as the first parent and the one on the
105 specify the revision on "trunk" as the first parent and the one on the
106 "release-1.0" branch as the second.
106 "release-1.0" branch as the second.
107
107
108 The branchmap is a file that allows you to rename a branch when it is
108 The branchmap is a file that allows you to rename a branch when it is
109 being brought in from whatever external repository. When used in
109 being brought in from whatever external repository. When used in
110 conjunction with a splicemap, it allows for a powerful combination to help
110 conjunction with a splicemap, it allows for a powerful combination to help
111 fix even the most badly mismanaged repositories and turn them into nicely
111 fix even the most badly mismanaged repositories and turn them into nicely
112 structured Mercurial repositories. The branchmap contains lines of the
112 structured Mercurial repositories. The branchmap contains lines of the
113 form:
113 form:
114
114
115 original_branch_name new_branch_name
115 original_branch_name new_branch_name
116
116
117 where "original_branch_name" is the name of the branch in the source
117 where "original_branch_name" is the name of the branch in the source
118 repository, and "new_branch_name" is the name of the branch is the
118 repository, and "new_branch_name" is the name of the branch is the
119 destination repository. No whitespace is allowed in the branch names. This
119 destination repository. No whitespace is allowed in the branch names. This
120 can be used to (for instance) move code in one repository from "default"
120 can be used to (for instance) move code in one repository from "default"
121 to a named branch.
121 to a named branch.
122
122
123 Mercurial Source
123 Mercurial Source
124 ''''''''''''''''
124 ''''''''''''''''
125
125
126 The Mercurial source recognizes the following configuration options, which
126 The Mercurial source recognizes the following configuration options, which
127 you can set on the command line with "--config":
127 you can set on the command line with "--config":
128
128
129 convert.hg.ignoreerrors
129 convert.hg.ignoreerrors
130 ignore integrity errors when reading. Use it to fix Mercurial
130 ignore integrity errors when reading. Use it to fix Mercurial
131 repositories with missing revlogs, by converting from and to
131 repositories with missing revlogs, by converting from and to
132 Mercurial. Default is False.
132 Mercurial. Default is False.
133 convert.hg.saverev
133 convert.hg.saverev
134 store original. revision ID in changeset (forces target IDs to
134 store original. revision ID in changeset (forces target IDs to
135 change). It takes and boolean argument and defaults to False.
135 change). It takes and boolean argument and defaults to False.
136 convert.hg.startrev
136 convert.hg.startrev
137 convert start revision and its descendants. It takes a hg
137 convert start revision and its descendants. It takes a hg
138 revision identifier and defaults to 0.
138 revision identifier and defaults to 0.
139
139
140 CVS Source
140 CVS Source
141 ''''''''''
141 ''''''''''
142
142
143 CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
143 CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
144 indicate the starting point of what will be converted. Direct access to
144 indicate the starting point of what will be converted. Direct access to
145 the repository files is not needed, unless of course the repository is
145 the repository files is not needed, unless of course the repository is
146 ":local:". The conversion uses the top level directory in the sandbox to
146 ":local:". The conversion uses the top level directory in the sandbox to
147 find the CVS repository, and then uses CVS rlog commands to find files to
147 find the CVS repository, and then uses CVS rlog commands to find files to
148 convert. This means that unless a filemap is given, all files under the
148 convert. This means that unless a filemap is given, all files under the
149 starting directory will be converted, and that any directory
149 starting directory will be converted, and that any directory
150 reorganization in the CVS sandbox is ignored.
150 reorganization in the CVS sandbox is ignored.
151
151
152 The following options can be used with "--config":
152 The following options can be used with "--config":
153
153
154 convert.cvsps.cache
154 convert.cvsps.cache
155 Set to False to disable remote log caching, for testing and
155 Set to False to disable remote log caching, for testing and
156 debugging purposes. Default is True.
156 debugging purposes. Default is True.
157 convert.cvsps.fuzz
157 convert.cvsps.fuzz
158 Specify the maximum time (in seconds) that is allowed between
158 Specify the maximum time (in seconds) that is allowed between
159 commits with identical user and log message in a single
159 commits with identical user and log message in a single
160 changeset. When very large files were checked in as part of a
160 changeset. When very large files were checked in as part of a
161 changeset then the default may not be long enough. The default
161 changeset then the default may not be long enough. The default
162 is 60.
162 is 60.
163 convert.cvsps.mergeto
163 convert.cvsps.mergeto
164 Specify a regular expression to which commit log messages are
164 Specify a regular expression to which commit log messages are
165 matched. If a match occurs, then the conversion process will
165 matched. If a match occurs, then the conversion process will
166 insert a dummy revision merging the branch on which this log
166 insert a dummy revision merging the branch on which this log
167 message occurs to the branch indicated in the regex. Default
167 message occurs to the branch indicated in the regex. Default
168 is "{{mergetobranch ([-\w]+)}}"
168 is "{{mergetobranch ([-\w]+)}}"
169 convert.cvsps.mergefrom
169 convert.cvsps.mergefrom
170 Specify a regular expression to which commit log messages are
170 Specify a regular expression to which commit log messages are
171 matched. If a match occurs, then the conversion process will
171 matched. If a match occurs, then the conversion process will
172 add the most recent revision on the branch indicated in the
172 add the most recent revision on the branch indicated in the
173 regex as the second parent of the changeset. Default is
173 regex as the second parent of the changeset. Default is
174 "{{mergefrombranch ([-\w]+)}}"
174 "{{mergefrombranch ([-\w]+)}}"
175 hook.cvslog
175 hook.cvslog
176 Specify a Python function to be called at the end of gathering
176 Specify a Python function to be called at the end of gathering
177 the CVS log. The function is passed a list with the log
177 the CVS log. The function is passed a list with the log
178 entries, and can modify the entries in-place, or add or delete
178 entries, and can modify the entries in-place, or add or delete
179 them.
179 them.
180 hook.cvschangesets
180 hook.cvschangesets
181 Specify a Python function to be called after the changesets
181 Specify a Python function to be called after the changesets
182 are calculated from the the CVS log. The function is passed a
182 are calculated from the the CVS log. The function is passed a
183 list with the changeset entries, and can modify the changesets
183 list with the changeset entries, and can modify the changesets
184 in-place, or add or delete them.
184 in-place, or add or delete them.
185
185
186 An additional "debugcvsps" Mercurial command allows the builtin changeset
186 An additional "debugcvsps" Mercurial command allows the builtin changeset
187 merging code to be run without doing a conversion. Its parameters and
187 merging code to be run without doing a conversion. Its parameters and
188 output are similar to that of cvsps 2.1. Please see the command help for
188 output are similar to that of cvsps 2.1. Please see the command help for
189 more details.
189 more details.
190
190
191 Subversion Source
191 Subversion Source
192 '''''''''''''''''
192 '''''''''''''''''
193
193
194 Subversion source detects classical trunk/branches/tags layouts. By
194 Subversion source detects classical trunk/branches/tags layouts. By
195 default, the supplied "svn://repo/path/" source URL is converted as a
195 default, the supplied "svn://repo/path/" source URL is converted as a
196 single branch. If "svn://repo/path/trunk" exists it replaces the default
196 single branch. If "svn://repo/path/trunk" exists it replaces the default
197 branch. If "svn://repo/path/branches" exists, its subdirectories are
197 branch. If "svn://repo/path/branches" exists, its subdirectories are
198 listed as possible branches. If "svn://repo/path/tags" exists, it is
198 listed as possible branches. If "svn://repo/path/tags" exists, it is
199 looked for tags referencing converted branches. Default "trunk",
199 looked for tags referencing converted branches. Default "trunk",
200 "branches" and "tags" values can be overridden with following options. Set
200 "branches" and "tags" values can be overridden with following options. Set
201 them to paths relative to the source URL, or leave them blank to disable
201 them to paths relative to the source URL, or leave them blank to disable
202 auto detection.
202 auto detection.
203
203
204 The following options can be set with "--config":
204 The following options can be set with "--config":
205
205
206 convert.svn.branches
206 convert.svn.branches
207 specify the directory containing branches. The defaults is
207 specify the directory containing branches. The defaults is
208 "branches".
208 "branches".
209 convert.svn.tags
209 convert.svn.tags
210 specify the directory containing tags. The default is "tags".
210 specify the directory containing tags. The default is "tags".
211 convert.svn.trunk
211 convert.svn.trunk
212 specify the name of the trunk branch The defauls is "trunk".
212 specify the name of the trunk branch The defauls is "trunk".
213
213
214 Source history can be retrieved starting at a specific revision, instead
214 Source history can be retrieved starting at a specific revision, instead
215 of being integrally converted. Only single branch conversions are
215 of being integrally converted. Only single branch conversions are
216 supported.
216 supported.
217
217
218 convert.svn.startrev
218 convert.svn.startrev
219 specify start Subversion revision number. The default is 0.
219 specify start Subversion revision number. The default is 0.
220
220
221 Perforce Source
221 Perforce Source
222 '''''''''''''''
222 '''''''''''''''
223
223
224 The Perforce (P4) importer can be given a p4 depot path or a client
224 The Perforce (P4) importer can be given a p4 depot path or a client
225 specification as source. It will convert all files in the source to a flat
225 specification as source. It will convert all files in the source to a flat
226 Mercurial repository, ignoring labels, branches and integrations. Note
226 Mercurial repository, ignoring labels, branches and integrations. Note
227 that when a depot path is given you then usually should specify a target
227 that when a depot path is given you then usually should specify a target
228 directory, because otherwise the target may be named "...-hg".
228 directory, because otherwise the target may be named "...-hg".
229
229
230 It is possible to limit the amount of source history to be converted by
230 It is possible to limit the amount of source history to be converted by
231 specifying an initial Perforce revision:
231 specifying an initial Perforce revision:
232
232
233 convert.p4.startrev
233 convert.p4.startrev
234 specify initial Perforce revision, a Perforce changelist
234 specify initial Perforce revision, a Perforce changelist
235 number).
235 number).
236
236
237 Mercurial Destination
237 Mercurial Destination
238 '''''''''''''''''''''
238 '''''''''''''''''''''
239
239
240 The following options are supported:
240 The following options are supported:
241
241
242 convert.hg.clonebranches
242 convert.hg.clonebranches
243 dispatch source branches in separate clones. The default is
243 dispatch source branches in separate clones. The default is
244 False.
244 False.
245 convert.hg.tagsbranch
245 convert.hg.tagsbranch
246 branch name for tag revisions, defaults to "default".
246 branch name for tag revisions, defaults to "default".
247 convert.hg.usebranchnames
247 convert.hg.usebranchnames
248 preserve branch names. The default is True
248 preserve branch names. The default is True
249
249
250 options:
250 options:
251
251
252 -s --source-type TYPE source repository type
252 -s --source-type TYPE source repository type
253 -d --dest-type TYPE destination repository type
253 -d --dest-type TYPE destination repository type
254 -r --rev REV import up to target revision REV
254 -r --rev REV import up to target revision REV
255 -A --authormap FILE remap usernames using this file
255 -A --authormap FILE remap usernames using this file
256 --filemap FILE remap file names using contents of file
256 --filemap FILE remap file names using contents of file
257 --splicemap FILE splice synthesized history into place
257 --splicemap FILE splice synthesized history into place
258 --branchmap FILE change branch names while converting
258 --branchmap FILE change branch names while converting
259 --branchsort try to sort changesets by branches
259 --branchsort try to sort changesets by branches
260 --datesort try to sort changesets by date
260 --datesort try to sort changesets by date
261 --sourcesort preserve source changesets order
261 --sourcesort preserve source changesets order
262
262
263 use "hg -v help convert" to show global options
263 use "hg -v help convert" to show global options
264 $ hg init a
264 $ hg init a
265 $ cd a
265 $ cd a
266 $ echo a > a
266 $ echo a > a
267 $ hg ci -d'0 0' -Ama
267 $ hg ci -d'0 0' -Ama
268 adding a
268 adding a
269 $ hg cp a b
269 $ hg cp a b
270 $ hg ci -d'1 0' -mb
270 $ hg ci -d'1 0' -mb
271 $ hg rm a
271 $ hg rm a
272 $ hg ci -d'2 0' -mc
272 $ hg ci -d'2 0' -mc
273 $ hg mv b a
273 $ hg mv b a
274 $ hg ci -d'3 0' -md
274 $ hg ci -d'3 0' -md
275 $ echo a >> a
275 $ echo a >> a
276 $ hg ci -d'4 0' -me
276 $ hg ci -d'4 0' -me
277 $ cd ..
277 $ cd ..
278 $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded'
278 $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded'
279 assuming destination a-hg
279 assuming destination a-hg
280 initializing destination a-hg repository
280 initializing destination a-hg repository
281 scanning source...
281 scanning source...
282 sorting...
282 sorting...
283 converting...
283 converting...
284 4 a
284 4 a
285 3 b
285 3 b
286 2 c
286 2 c
287 1 d
287 1 d
288 0 e
288 0 e
289 $ hg --cwd a-hg pull ../a
289 $ hg --cwd a-hg pull ../a
290 pulling from ../a
290 pulling from ../a
291 searching for changes
291 searching for changes
292 no changes found
292 no changes found
293 $ touch bogusfile
293 $ touch bogusfile
294
294
295 should fail
295 should fail
296
296
297 $ hg convert a bogusfile
297 $ hg convert a bogusfile
298 initializing destination bogusfile repository
298 initializing destination bogusfile repository
299 abort: cannot create new bundle repository
299 abort: cannot create new bundle repository
300 [255]
300 [255]
301 $ mkdir bogusdir
301 $ mkdir bogusdir
302 $ chmod 000 bogusdir
302 $ chmod 000 bogusdir
303
303
304 should fail
304 should fail
305
305
306 $ hg convert a bogusdir
306 $ hg convert a bogusdir
307 abort: Permission denied: bogusdir
307 abort: Permission denied: bogusdir
308 [255]
308 [255]
309
309
310 should succeed
310 should succeed
311
311
312 $ chmod 700 bogusdir
312 $ chmod 700 bogusdir
313 $ hg convert a bogusdir
313 $ hg convert a bogusdir
314 initializing destination bogusdir repository
314 initializing destination bogusdir repository
315 scanning source...
315 scanning source...
316 sorting...
316 sorting...
317 converting...
317 converting...
318 4 a
318 4 a
319 3 b
319 3 b
320 2 c
320 2 c
321 1 d
321 1 d
322 0 e
322 0 e
323
323
324 test pre and post conversion actions
324 test pre and post conversion actions
325
325
326 $ echo 'include b' > filemap
326 $ echo 'include b' > filemap
327 $ hg convert --debug --filemap filemap a partialb | \
327 $ hg convert --debug --filemap filemap a partialb | \
328 > grep 'run hg'
328 > grep 'run hg'
329 run hg source pre-conversion action
329 run hg source pre-conversion action
330 run hg sink pre-conversion action
330 run hg sink pre-conversion action
331 run hg sink post-conversion action
331 run hg sink post-conversion action
332 run hg source post-conversion action
332 run hg source post-conversion action
333
333
334 converting empty dir should fail "nicely
334 converting empty dir should fail "nicely
335
335
336 $ mkdir emptydir
336 $ mkdir emptydir
337
337
338 override $PATH to ensure p4 not visible; use $PYTHON in case we're
338 override $PATH to ensure p4 not visible; use $PYTHON in case we're
339 running from a devel copy, not a temp installation
339 running from a devel copy, not a temp installation
340
340
341 $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg convert emptydir
341 $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg convert emptydir
342 assuming destination emptydir-hg
342 assuming destination emptydir-hg
343 initializing destination emptydir-hg repository
343 initializing destination emptydir-hg repository
344 emptydir does not look like a CVS checkout
344 emptydir does not look like a CVS checkout
345 emptydir does not look like a Git repository
345 emptydir does not look like a Git repository
346 emptydir does not look like a Subversion repository
346 emptydir does not look like a Subversion repository
347 emptydir is not a local Mercurial repository
347 emptydir is not a local Mercurial repository
348 emptydir does not look like a darcs repository
348 emptydir does not look like a darcs repository
349 emptydir does not look like a monotone repository
349 emptydir does not look like a monotone repository
350 emptydir does not look like a GNU Arch repository
350 emptydir does not look like a GNU Arch repository
351 emptydir does not look like a Bazaar repository
351 emptydir does not look like a Bazaar repository
352 cannot find required "p4" tool
352 cannot find required "p4" tool
353 abort: emptydir: missing or unsupported repository
353 abort: emptydir: missing or unsupported repository
354 [255]
354 [255]
355
355
356 convert with imaginary source type
356 convert with imaginary source type
357
357
358 $ hg convert --source-type foo a a-foo
358 $ hg convert --source-type foo a a-foo
359 initializing destination a-foo repository
359 initializing destination a-foo repository
360 abort: foo: invalid source repository type
360 abort: foo: invalid source repository type
361 [255]
361 [255]
362
362
363 convert with imaginary sink type
363 convert with imaginary sink type
364
364
365 $ hg convert --dest-type foo a a-foo
365 $ hg convert --dest-type foo a a-foo
366 abort: foo: invalid destination repository type
366 abort: foo: invalid destination repository type
367 [255]
367 [255]
368
368
369 testing: convert must not produce duplicate entries in fncache
369 testing: convert must not produce duplicate entries in fncache
370
370
371 $ hg convert a b
371 $ hg convert a b
372 initializing destination b repository
372 initializing destination b repository
373 scanning source...
373 scanning source...
374 sorting...
374 sorting...
375 converting...
375 converting...
376 4 a
376 4 a
377 3 b
377 3 b
378 2 c
378 2 c
379 1 d
379 1 d
380 0 e
380 0 e
381
381
382 contents of fncache file:
382 contents of fncache file:
383
383
384 $ cat b/.hg/store/fncache
384 $ cat b/.hg/store/fncache
385 data/a.i
385 data/a.i
386 data/b.i
386 data/b.i
387
387
388 test bogus URL
388 test bogus URL
389
389
390 $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz
390 $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz
391 abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository
391 abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository
392 [255]
392 [255]
@@ -1,230 +1,233 b''
1 from pprint import pprint
1 from pprint import pprint
2 from mercurial import minirst
2 from mercurial import minirst
3
3
4 def debugformat(title, text, width, **kwargs):
4 def debugformat(title, text, width, **kwargs):
5 print "%s formatted to fit within %d characters:" % (title, width)
5 print "%s formatted to fit within %d characters:" % (title, width)
6 print "-" * 70
6 print "-" * 70
7 formatted = minirst.format(text, width, **kwargs)
7 formatted = minirst.format(text, width, **kwargs)
8 if type(formatted) == tuple:
8 if type(formatted) == tuple:
9 print formatted[0]
9 print formatted[0]
10 print "-" * 70
10 print "-" * 70
11 pprint(formatted[1])
11 pprint(formatted[1])
12 else:
12 else:
13 print formatted
13 print formatted
14 print "-" * 70
14 print "-" * 70
15 print
15 print
16
16
17 paragraphs = """
17 paragraphs = """
18 This is some text in the first paragraph.
18 This is some text in the first paragraph.
19
19
20 A small indented paragraph.
20 A small indented paragraph.
21 It is followed by some lines
21 It is followed by some lines
22 containing random whitespace.
22 containing random whitespace.
23 \n \n \nThe third and final paragraph.
23 \n \n \nThe third and final paragraph.
24 """
24 """
25
25
26 debugformat('paragraphs', paragraphs, 60)
26 debugformat('paragraphs', paragraphs, 60)
27 debugformat('paragraphs', paragraphs, 30)
27 debugformat('paragraphs', paragraphs, 30)
28
28
29
29
30 definitions = """
30 definitions = """
31 A Term
31 A Term
32 Definition. The indented
32 Definition. The indented
33 lines make up the definition.
33 lines make up the definition.
34 Another Term
34 Another Term
35 Another definition. The final line in the
35 Another definition. The final line in the
36 definition determines the indentation, so
36 definition determines the indentation, so
37 this will be indented with four spaces.
37 this will be indented with four spaces.
38
38
39 A Nested/Indented Term
39 A Nested/Indented Term
40 Definition.
40 Definition.
41 """
41 """
42
42
43 debugformat('definitions', definitions, 60)
43 debugformat('definitions', definitions, 60)
44 debugformat('definitions', definitions, 30)
44 debugformat('definitions', definitions, 30)
45
45
46
46
47 literals = r"""
47 literals = r"""
48 The fully minimized form is the most
48 The fully minimized form is the most
49 convenient form::
49 convenient form::
50
50
51 Hello
51 Hello
52 literal
52 literal
53 world
53 world
54
54
55 In the partially minimized form a paragraph
55 In the partially minimized form a paragraph
56 simply ends with space-double-colon. ::
56 simply ends with space-double-colon. ::
57
57
58 ////////////////////////////////////////
58 ////////////////////////////////////////
59 long un-wrapped line in a literal block
59 long un-wrapped line in a literal block
60 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
60 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
61
61
62 ::
62 ::
63
63
64 This literal block is started with '::',
64 This literal block is started with '::',
65 the so-called expanded form. The paragraph
65 the so-called expanded form. The paragraph
66 with '::' disappears in the final output.
66 with '::' disappears in the final output.
67 """
67 """
68
68
69 debugformat('literals', literals, 60)
69 debugformat('literals', literals, 60)
70 debugformat('literals', literals, 30)
70 debugformat('literals', literals, 30)
71
71
72
72
73 lists = """
73 lists = """
74 - This is the first list item.
74 - This is the first list item.
75
75
76 Second paragraph in the first list item.
76 Second paragraph in the first list item.
77
77
78 - List items need not be separated
78 - List items need not be separated
79 by a blank line.
79 by a blank line.
80 - And will be rendered without
80 - And will be rendered without
81 one in any case.
81 one in any case.
82
82
83 We can have indented lists:
83 We can have indented lists:
84
84
85 - This is an indented list item
85 - This is an indented list item
86
86
87 - Another indented list item::
87 - Another indented list item::
88
88
89 - A literal block in the middle
89 - A literal block in the middle
90 of an indented list.
90 of an indented list.
91
91
92 (The above is not a list item since we are in the literal block.)
92 (The above is not a list item since we are in the literal block.)
93
93
94 ::
94 ::
95
95
96 Literal block with no indentation (apart from
96 Literal block with no indentation (apart from
97 the two spaces added to all literal blocks).
97 the two spaces added to all literal blocks).
98
98
99 1. This is an enumerated list (first item).
99 1. This is an enumerated list (first item).
100 2. Continuing with the second item.
100 2. Continuing with the second item.
101
101
102 (1) foo
102 (1) foo
103 (2) bar
103 (2) bar
104
104
105 1) Another
105 1) Another
106 2) List
106 2) List
107
107
108 Line blocks are also a form of list:
108 Line blocks are also a form of list:
109
109
110 | This is the first line.
110 | This is the first line.
111 The line continues here.
111 The line continues here.
112 | This is the second line.
112 | This is the second line.
113 """
113 """
114
114
115 debugformat('lists', lists, 60)
115 debugformat('lists', lists, 60)
116 debugformat('lists', lists, 30)
116 debugformat('lists', lists, 30)
117
117
118
118
119 options = """
119 options = """
120 There is support for simple option lists,
120 There is support for simple option lists,
121 but only with long options:
121 but only with long options:
122
122
123 --all Output all.
123 -X, --exclude filter an option with a short and long option with an argument
124 --both Output both (this description is
124 -I, --include an option with both a short option and a long option
125 quite long).
125 --all Output all.
126 --long Output all day long.
126 --both Output both (this description is
127 quite long).
128 --long Output all day long.
127
129
128 --par This option has two paragraphs in its description.
130 --par This option has two paragraphs in its description.
129 This is the first.
131 This is the first.
130
132
131 This is the second. Blank lines may be omitted between
133 This is the second. Blank lines may be omitted between
132 options (as above) or left in (as here).
134 options (as above) or left in (as here).
135
133
136
134 The next paragraph looks like an option list, but lacks the two-space
137 The next paragraph looks like an option list, but lacks the two-space
135 marker after the option. It is treated as a normal paragraph:
138 marker after the option. It is treated as a normal paragraph:
136
139
137 --foo bar baz
140 --foo bar baz
138 """
141 """
139
142
140 debugformat('options', options, 60)
143 debugformat('options', options, 60)
141 debugformat('options', options, 30)
144 debugformat('options', options, 30)
142
145
143
146
144 fields = """
147 fields = """
145 :a: First item.
148 :a: First item.
146 :ab: Second item. Indentation and wrapping
149 :ab: Second item. Indentation and wrapping
147 is handled automatically.
150 is handled automatically.
148
151
149 Next list:
152 Next list:
150
153
151 :small: The larger key below triggers full indentation here.
154 :small: The larger key below triggers full indentation here.
152 :much too large: This key is big enough to get its own line.
155 :much too large: This key is big enough to get its own line.
153 """
156 """
154
157
155 debugformat('fields', fields, 60)
158 debugformat('fields', fields, 60)
156 debugformat('fields', fields, 30)
159 debugformat('fields', fields, 30)
157
160
158 containers = """
161 containers = """
159 Normal output.
162 Normal output.
160
163
161 .. container:: debug
164 .. container:: debug
162
165
163 Initial debug output.
166 Initial debug output.
164
167
165 .. container:: verbose
168 .. container:: verbose
166
169
167 Verbose output.
170 Verbose output.
168
171
169 .. container:: debug
172 .. container:: debug
170
173
171 Debug output.
174 Debug output.
172 """
175 """
173
176
174 debugformat('containers (normal)', containers, 60)
177 debugformat('containers (normal)', containers, 60)
175 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
178 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
176 debugformat('containers (debug)', containers, 60, keep=['debug'])
179 debugformat('containers (debug)', containers, 60, keep=['debug'])
177 debugformat('containers (verbose debug)', containers, 60,
180 debugformat('containers (verbose debug)', containers, 60,
178 keep=['verbose', 'debug'])
181 keep=['verbose', 'debug'])
179
182
180 roles = """Please see :hg:`add`."""
183 roles = """Please see :hg:`add`."""
181 debugformat('roles', roles, 60)
184 debugformat('roles', roles, 60)
182
185
183
186
184 sections = """
187 sections = """
185 Title
188 Title
186 =====
189 =====
187
190
188 Section
191 Section
189 -------
192 -------
190
193
191 Subsection
194 Subsection
192 ''''''''''
195 ''''''''''
193
196
194 Markup: ``foo`` and :hg:`help`
197 Markup: ``foo`` and :hg:`help`
195 ------------------------------
198 ------------------------------
196 """
199 """
197 debugformat('sections', sections, 20)
200 debugformat('sections', sections, 20)
198
201
199
202
200 admonitions = """
203 admonitions = """
201 .. note::
204 .. note::
202 This is a note
205 This is a note
203
206
204 - Bullet 1
207 - Bullet 1
205 - Bullet 2
208 - Bullet 2
206
209
207 .. warning:: This is a warning Second
210 .. warning:: This is a warning Second
208 input line of warning
211 input line of warning
209
212
210 .. danger::
213 .. danger::
211 This is danger
214 This is danger
212 """
215 """
213
216
214 debugformat('admonitions', admonitions, 30)
217 debugformat('admonitions', admonitions, 30)
215
218
216 comments = """
219 comments = """
217 Some text.
220 Some text.
218
221
219 .. A comment
222 .. A comment
220
223
221 .. An indented comment
224 .. An indented comment
222
225
223 Some indented text.
226 Some indented text.
224
227
225 ..
228 ..
226
229
227 Empty comment above
230 Empty comment above
228 """
231 """
229
232
230 debugformat('comments', comments, 30)
233 debugformat('comments', comments, 30)
@@ -1,345 +1,390 b''
1 paragraphs formatted to fit within 60 characters:
1 paragraphs formatted to fit within 60 characters:
2 ----------------------------------------------------------------------
2 ----------------------------------------------------------------------
3 This is some text in the first paragraph.
3 This is some text in the first paragraph.
4
4
5 A small indented paragraph. It is followed by some lines
5 A small indented paragraph. It is followed by some lines
6 containing random whitespace.
6 containing random whitespace.
7
7
8 The third and final paragraph.
8 The third and final paragraph.
9 ----------------------------------------------------------------------
9 ----------------------------------------------------------------------
10
10
11 paragraphs formatted to fit within 30 characters:
11 paragraphs formatted to fit within 30 characters:
12 ----------------------------------------------------------------------
12 ----------------------------------------------------------------------
13 This is some text in the first
13 This is some text in the first
14 paragraph.
14 paragraph.
15
15
16 A small indented paragraph.
16 A small indented paragraph.
17 It is followed by some lines
17 It is followed by some lines
18 containing random
18 containing random
19 whitespace.
19 whitespace.
20
20
21 The third and final paragraph.
21 The third and final paragraph.
22 ----------------------------------------------------------------------
22 ----------------------------------------------------------------------
23
23
24 definitions formatted to fit within 60 characters:
24 definitions formatted to fit within 60 characters:
25 ----------------------------------------------------------------------
25 ----------------------------------------------------------------------
26 A Term
26 A Term
27 Definition. The indented lines make up the definition.
27 Definition. The indented lines make up the definition.
28
28
29 Another Term
29 Another Term
30 Another definition. The final line in the definition
30 Another definition. The final line in the definition
31 determines the indentation, so this will be indented
31 determines the indentation, so this will be indented
32 with four spaces.
32 with four spaces.
33
33
34 A Nested/Indented Term
34 A Nested/Indented Term
35 Definition.
35 Definition.
36 ----------------------------------------------------------------------
36 ----------------------------------------------------------------------
37
37
38 definitions formatted to fit within 30 characters:
38 definitions formatted to fit within 30 characters:
39 ----------------------------------------------------------------------
39 ----------------------------------------------------------------------
40 A Term
40 A Term
41 Definition. The indented
41 Definition. The indented
42 lines make up the
42 lines make up the
43 definition.
43 definition.
44
44
45 Another Term
45 Another Term
46 Another definition. The
46 Another definition. The
47 final line in the
47 final line in the
48 definition determines the
48 definition determines the
49 indentation, so this will
49 indentation, so this will
50 be indented with four
50 be indented with four
51 spaces.
51 spaces.
52
52
53 A Nested/Indented Term
53 A Nested/Indented Term
54 Definition.
54 Definition.
55 ----------------------------------------------------------------------
55 ----------------------------------------------------------------------
56
56
57 literals formatted to fit within 60 characters:
57 literals formatted to fit within 60 characters:
58 ----------------------------------------------------------------------
58 ----------------------------------------------------------------------
59 The fully minimized form is the most convenient form:
59 The fully minimized form is the most convenient form:
60
60
61 Hello
61 Hello
62 literal
62 literal
63 world
63 world
64
64
65 In the partially minimized form a paragraph simply ends with
65 In the partially minimized form a paragraph simply ends with
66 space-double-colon.
66 space-double-colon.
67
67
68 ////////////////////////////////////////
68 ////////////////////////////////////////
69 long un-wrapped line in a literal block
69 long un-wrapped line in a literal block
70 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
70 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
71
71
72 This literal block is started with '::',
72 This literal block is started with '::',
73 the so-called expanded form. The paragraph
73 the so-called expanded form. The paragraph
74 with '::' disappears in the final output.
74 with '::' disappears in the final output.
75 ----------------------------------------------------------------------
75 ----------------------------------------------------------------------
76
76
77 literals formatted to fit within 30 characters:
77 literals formatted to fit within 30 characters:
78 ----------------------------------------------------------------------
78 ----------------------------------------------------------------------
79 The fully minimized form is
79 The fully minimized form is
80 the most convenient form:
80 the most convenient form:
81
81
82 Hello
82 Hello
83 literal
83 literal
84 world
84 world
85
85
86 In the partially minimized
86 In the partially minimized
87 form a paragraph simply ends
87 form a paragraph simply ends
88 with space-double-colon.
88 with space-double-colon.
89
89
90 ////////////////////////////////////////
90 ////////////////////////////////////////
91 long un-wrapped line in a literal block
91 long un-wrapped line in a literal block
92 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
92 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
93
93
94 This literal block is started with '::',
94 This literal block is started with '::',
95 the so-called expanded form. The paragraph
95 the so-called expanded form. The paragraph
96 with '::' disappears in the final output.
96 with '::' disappears in the final output.
97 ----------------------------------------------------------------------
97 ----------------------------------------------------------------------
98
98
99 lists formatted to fit within 60 characters:
99 lists formatted to fit within 60 characters:
100 ----------------------------------------------------------------------
100 ----------------------------------------------------------------------
101 - This is the first list item.
101 - This is the first list item.
102
102
103 Second paragraph in the first list item.
103 Second paragraph in the first list item.
104
104
105 - List items need not be separated by a blank line.
105 - List items need not be separated by a blank line.
106 - And will be rendered without one in any case.
106 - And will be rendered without one in any case.
107
107
108 We can have indented lists:
108 We can have indented lists:
109
109
110 - This is an indented list item
110 - This is an indented list item
111 - Another indented list item:
111 - Another indented list item:
112
112
113 - A literal block in the middle
113 - A literal block in the middle
114 of an indented list.
114 of an indented list.
115
115
116 (The above is not a list item since we are in the literal block.)
116 (The above is not a list item since we are in the literal block.)
117
117
118 Literal block with no indentation (apart from
118 Literal block with no indentation (apart from
119 the two spaces added to all literal blocks).
119 the two spaces added to all literal blocks).
120
120
121 1. This is an enumerated list (first item).
121 1. This is an enumerated list (first item).
122 2. Continuing with the second item.
122 2. Continuing with the second item.
123 (1) foo
123 (1) foo
124 (2) bar
124 (2) bar
125 1) Another
125 1) Another
126 2) List
126 2) List
127
127
128 Line blocks are also a form of list:
128 Line blocks are also a form of list:
129
129
130 This is the first line. The line continues here.
130 This is the first line. The line continues here.
131 This is the second line.
131 This is the second line.
132 ----------------------------------------------------------------------
132 ----------------------------------------------------------------------
133
133
134 lists formatted to fit within 30 characters:
134 lists formatted to fit within 30 characters:
135 ----------------------------------------------------------------------
135 ----------------------------------------------------------------------
136 - This is the first list item.
136 - This is the first list item.
137
137
138 Second paragraph in the
138 Second paragraph in the
139 first list item.
139 first list item.
140
140
141 - List items need not be
141 - List items need not be
142 separated by a blank line.
142 separated by a blank line.
143 - And will be rendered without
143 - And will be rendered without
144 one in any case.
144 one in any case.
145
145
146 We can have indented lists:
146 We can have indented lists:
147
147
148 - This is an indented list
148 - This is an indented list
149 item
149 item
150 - Another indented list
150 - Another indented list
151 item:
151 item:
152
152
153 - A literal block in the middle
153 - A literal block in the middle
154 of an indented list.
154 of an indented list.
155
155
156 (The above is not a list item since we are in the literal block.)
156 (The above is not a list item since we are in the literal block.)
157
157
158 Literal block with no indentation (apart from
158 Literal block with no indentation (apart from
159 the two spaces added to all literal blocks).
159 the two spaces added to all literal blocks).
160
160
161 1. This is an enumerated list
161 1. This is an enumerated list
162 (first item).
162 (first item).
163 2. Continuing with the second
163 2. Continuing with the second
164 item.
164 item.
165 (1) foo
165 (1) foo
166 (2) bar
166 (2) bar
167 1) Another
167 1) Another
168 2) List
168 2) List
169
169
170 Line blocks are also a form of
170 Line blocks are also a form of
171 list:
171 list:
172
172
173 This is the first line. The
173 This is the first line. The
174 line continues here.
174 line continues here.
175 This is the second line.
175 This is the second line.
176 ----------------------------------------------------------------------
176 ----------------------------------------------------------------------
177
177
178 options formatted to fit within 60 characters:
178 options formatted to fit within 60 characters:
179 ----------------------------------------------------------------------
179 ----------------------------------------------------------------------
180 There is support for simple option lists, but only with long
180 There is support for simple option lists, but only with long
181 options:
181 options:
182
182
183 --all Output all.
183 -X --exclude filter an option with a short and long option
184 --both Output both (this description is quite long).
184 with an argument
185 --long Output all day long.
185 -I --include an option with both a short option and
186 --par This option has two paragraphs in its
186 a long option
187 description. This is the first.
187 --all Output all.
188 --both Output both (this description is quite
189 long).
190 --long Output all day long.
191 --par This option has two paragraphs in its
192 description. This is the first.
188
193
189 This is the second. Blank lines may be omitted
194 This is the second. Blank lines may
190 between options (as above) or left in (as here).
195 be omitted between options (as above)
196 or left in (as here).
191
197
192 The next paragraph looks like an option list, but lacks the
198 The next paragraph looks like an option list, but lacks the
193 two-space marker after the option. It is treated as a normal
199 two-space marker after the option. It is treated as a normal
194 paragraph:
200 paragraph:
195
201
196 --foo bar baz
202 --foo bar baz
197 ----------------------------------------------------------------------
203 ----------------------------------------------------------------------
198
204
199 options formatted to fit within 30 characters:
205 options formatted to fit within 30 characters:
200 ----------------------------------------------------------------------
206 ----------------------------------------------------------------------
201 There is support for simple
207 There is support for simple
202 option lists, but only with
208 option lists, but only with
203 long options:
209 long options:
204
210
205 --all Output all.
211 -X --exclude filter an
206 --both Output both (this
212 option
207 description is
213 with a
208 quite long).
214 short
209 --long Output all day
215 and
210 long.
216 long
211 --par This option has two
217 option
212 paragraphs in its
218 with an
213 description. This
219 argumen
214 is the first.
220 t
221 -I --include an
222 option
223 with
224 both a
225 short
226 option
227 and a
228 long
229 option
230 --all Output
231 all.
232 --both Output
233 both
234 (this d
235 escript
236 ion is
237 quite
238 long).
239 --long Output
240 all day
241 long.
242 --par This
243 option
244 has two
245 paragra
246 phs in
247 its des
248 criptio
249 n. This
250 is the
251 first.
215
252
216 This is the second.
253 This is
217 Blank lines may be
254 the
218 omitted between
255 second.
219 options (as above)
256 Blank
220 or left in (as
257 lines
221 here).
258 may be
259 omitted
260 between
261 options
262 (as
263 above)
264 or left
265 in (as
266 here).
222
267
223 The next paragraph looks like
268 The next paragraph looks like
224 an option list, but lacks the
269 an option list, but lacks the
225 two-space marker after the
270 two-space marker after the
226 option. It is treated as a
271 option. It is treated as a
227 normal paragraph:
272 normal paragraph:
228
273
229 --foo bar baz
274 --foo bar baz
230 ----------------------------------------------------------------------
275 ----------------------------------------------------------------------
231
276
232 fields formatted to fit within 60 characters:
277 fields formatted to fit within 60 characters:
233 ----------------------------------------------------------------------
278 ----------------------------------------------------------------------
234 a First item.
279 a First item.
235 ab Second item. Indentation and wrapping is handled
280 ab Second item. Indentation and wrapping is handled
236 automatically.
281 automatically.
237
282
238 Next list:
283 Next list:
239
284
240 small The larger key below triggers full indentation
285 small The larger key below triggers full indentation
241 here.
286 here.
242 much too large
287 much too large
243 This key is big enough to get its own line.
288 This key is big enough to get its own line.
244 ----------------------------------------------------------------------
289 ----------------------------------------------------------------------
245
290
246 fields formatted to fit within 30 characters:
291 fields formatted to fit within 30 characters:
247 ----------------------------------------------------------------------
292 ----------------------------------------------------------------------
248 a First item.
293 a First item.
249 ab Second item. Indentation
294 ab Second item. Indentation
250 and wrapping is handled
295 and wrapping is handled
251 automatically.
296 automatically.
252
297
253 Next list:
298 Next list:
254
299
255 small The larger key
300 small The larger key
256 below triggers
301 below triggers
257 full indentation
302 full indentation
258 here.
303 here.
259 much too large
304 much too large
260 This key is big
305 This key is big
261 enough to get its
306 enough to get its
262 own line.
307 own line.
263 ----------------------------------------------------------------------
308 ----------------------------------------------------------------------
264
309
265 containers (normal) formatted to fit within 60 characters:
310 containers (normal) formatted to fit within 60 characters:
266 ----------------------------------------------------------------------
311 ----------------------------------------------------------------------
267 Normal output.
312 Normal output.
268 ----------------------------------------------------------------------
313 ----------------------------------------------------------------------
269
314
270 containers (verbose) formatted to fit within 60 characters:
315 containers (verbose) formatted to fit within 60 characters:
271 ----------------------------------------------------------------------
316 ----------------------------------------------------------------------
272 Normal output.
317 Normal output.
273
318
274 Verbose output.
319 Verbose output.
275 ----------------------------------------------------------------------
320 ----------------------------------------------------------------------
276 ['debug', 'debug']
321 ['debug', 'debug']
277 ----------------------------------------------------------------------
322 ----------------------------------------------------------------------
278
323
279 containers (debug) formatted to fit within 60 characters:
324 containers (debug) formatted to fit within 60 characters:
280 ----------------------------------------------------------------------
325 ----------------------------------------------------------------------
281 Normal output.
326 Normal output.
282
327
283 Initial debug output.
328 Initial debug output.
284 ----------------------------------------------------------------------
329 ----------------------------------------------------------------------
285 ['verbose']
330 ['verbose']
286 ----------------------------------------------------------------------
331 ----------------------------------------------------------------------
287
332
288 containers (verbose debug) formatted to fit within 60 characters:
333 containers (verbose debug) formatted to fit within 60 characters:
289 ----------------------------------------------------------------------
334 ----------------------------------------------------------------------
290 Normal output.
335 Normal output.
291
336
292 Initial debug output.
337 Initial debug output.
293
338
294 Verbose output.
339 Verbose output.
295
340
296 Debug output.
341 Debug output.
297 ----------------------------------------------------------------------
342 ----------------------------------------------------------------------
298 []
343 []
299 ----------------------------------------------------------------------
344 ----------------------------------------------------------------------
300
345
301 roles formatted to fit within 60 characters:
346 roles formatted to fit within 60 characters:
302 ----------------------------------------------------------------------
347 ----------------------------------------------------------------------
303 Please see "hg add".
348 Please see "hg add".
304 ----------------------------------------------------------------------
349 ----------------------------------------------------------------------
305
350
306 sections formatted to fit within 20 characters:
351 sections formatted to fit within 20 characters:
307 ----------------------------------------------------------------------
352 ----------------------------------------------------------------------
308 Title
353 Title
309 =====
354 =====
310
355
311 Section
356 Section
312 -------
357 -------
313
358
314 Subsection
359 Subsection
315 ''''''''''
360 ''''''''''
316
361
317 Markup: "foo" and "hg help"
362 Markup: "foo" and "hg help"
318 ---------------------------
363 ---------------------------
319 ----------------------------------------------------------------------
364 ----------------------------------------------------------------------
320
365
321 admonitions formatted to fit within 30 characters:
366 admonitions formatted to fit within 30 characters:
322 ----------------------------------------------------------------------
367 ----------------------------------------------------------------------
323 Note:
368 Note:
324 This is a note
369 This is a note
325
370
326 - Bullet 1
371 - Bullet 1
327 - Bullet 2
372 - Bullet 2
328
373
329 Warning!
374 Warning!
330 This is a warning Second
375 This is a warning Second
331 input line of warning
376 input line of warning
332
377
333 !Danger!
378 !Danger!
334 This is danger
379 This is danger
335 ----------------------------------------------------------------------
380 ----------------------------------------------------------------------
336
381
337 comments formatted to fit within 30 characters:
382 comments formatted to fit within 30 characters:
338 ----------------------------------------------------------------------
383 ----------------------------------------------------------------------
339 Some text.
384 Some text.
340
385
341 Some indented text.
386 Some indented text.
342
387
343 Empty comment above
388 Empty comment above
344 ----------------------------------------------------------------------
389 ----------------------------------------------------------------------
345
390
General Comments 0
You need to be logged in to leave comments. Login now