##// END OF EJS Templates
help: inline minirst.format()...
Yuya Nishihara -
r39344:9b800601 default
parent child Browse files
Show More
@@ -1,690 +1,693 b''
1 1 # help.py - help data for mercurial
2 2 #
3 3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import itertools
11 11 import os
12 12 import textwrap
13 13
14 14 from .i18n import (
15 15 _,
16 16 gettext,
17 17 )
18 18 from . import (
19 19 cmdutil,
20 20 encoding,
21 21 error,
22 22 extensions,
23 23 fancyopts,
24 24 filemerge,
25 25 fileset,
26 26 minirst,
27 27 pycompat,
28 28 revset,
29 29 templatefilters,
30 30 templatefuncs,
31 31 templatekw,
32 32 util,
33 33 )
34 34 from .hgweb import (
35 35 webcommands,
36 36 )
37 37
38 38 _exclkeywords = {
39 39 "(ADVANCED)",
40 40 "(DEPRECATED)",
41 41 "(EXPERIMENTAL)",
42 42 # i18n: "(ADVANCED)" is a keyword, must be translated consistently
43 43 _("(ADVANCED)"),
44 44 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
45 45 _("(DEPRECATED)"),
46 46 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
47 47 _("(EXPERIMENTAL)"),
48 48 }
49 49
50 50 def listexts(header, exts, indent=1, showdeprecated=False):
51 51 '''return a text listing of the given extensions'''
52 52 rst = []
53 53 if exts:
54 54 for name, desc in sorted(exts.iteritems()):
55 55 if not showdeprecated and any(w in desc for w in _exclkeywords):
56 56 continue
57 57 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
58 58 if rst:
59 59 rst.insert(0, '\n%s\n\n' % header)
60 60 return rst
61 61
62 62 def extshelp(ui):
63 63 rst = loaddoc('extensions')(ui).splitlines(True)
64 64 rst.extend(listexts(
65 65 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
66 66 rst.extend(listexts(_('disabled extensions:'), extensions.disabled(),
67 67 showdeprecated=ui.verbose))
68 68 doc = ''.join(rst)
69 69 return doc
70 70
71 71 def optrst(header, options, verbose):
72 72 data = []
73 73 multioccur = False
74 74 for option in options:
75 75 if len(option) == 5:
76 76 shortopt, longopt, default, desc, optlabel = option
77 77 else:
78 78 shortopt, longopt, default, desc = option
79 79 optlabel = _("VALUE") # default label
80 80
81 81 if not verbose and any(w in desc for w in _exclkeywords):
82 82 continue
83 83
84 84 so = ''
85 85 if shortopt:
86 86 so = '-' + shortopt
87 87 lo = '--' + longopt
88 88
89 89 if isinstance(default, fancyopts.customopt):
90 90 default = default.getdefaultvalue()
91 91 if default and not callable(default):
92 92 # default is of unknown type, and in Python 2 we abused
93 93 # the %s-shows-repr property to handle integers etc. To
94 94 # match that behavior on Python 3, we do str(default) and
95 95 # then convert it to bytes.
96 96 desc += _(" (default: %s)") % pycompat.bytestr(default)
97 97
98 98 if isinstance(default, list):
99 99 lo += " %s [+]" % optlabel
100 100 multioccur = True
101 101 elif (default is not None) and not isinstance(default, bool):
102 102 lo += " %s" % optlabel
103 103
104 104 data.append((so, lo, desc))
105 105
106 106 if multioccur:
107 107 header += (_(" ([+] can be repeated)"))
108 108
109 109 rst = ['\n%s:\n\n' % header]
110 110 rst.extend(minirst.maketable(data, 1))
111 111
112 112 return ''.join(rst)
113 113
114 114 def indicateomitted(rst, omitted, notomitted=None):
115 115 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
116 116 if notomitted:
117 117 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
118 118
119 119 def filtercmd(ui, cmd, kw, doc):
120 120 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
121 121 return True
122 122 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
123 123 return True
124 124 return False
125 125
126 126 def topicmatch(ui, commands, kw):
127 127 """Return help topics matching kw.
128 128
129 129 Returns {'section': [(name, summary), ...], ...} where section is
130 130 one of topics, commands, extensions, or extensioncommands.
131 131 """
132 132 kw = encoding.lower(kw)
133 133 def lowercontains(container):
134 134 return kw in encoding.lower(container) # translated in helptable
135 135 results = {'topics': [],
136 136 'commands': [],
137 137 'extensions': [],
138 138 'extensioncommands': [],
139 139 }
140 140 for names, header, doc in helptable:
141 141 # Old extensions may use a str as doc.
142 142 if (sum(map(lowercontains, names))
143 143 or lowercontains(header)
144 144 or (callable(doc) and lowercontains(doc(ui)))):
145 145 results['topics'].append((names[0], header))
146 146 for cmd, entry in commands.table.iteritems():
147 147 if len(entry) == 3:
148 148 summary = entry[2]
149 149 else:
150 150 summary = ''
151 151 # translate docs *before* searching there
152 152 docs = _(pycompat.getdoc(entry[0])) or ''
153 153 if kw in cmd or lowercontains(summary) or lowercontains(docs):
154 154 doclines = docs.splitlines()
155 155 if doclines:
156 156 summary = doclines[0]
157 157 cmdname = cmdutil.parsealiases(cmd)[0]
158 158 if filtercmd(ui, cmdname, kw, docs):
159 159 continue
160 160 results['commands'].append((cmdname, summary))
161 161 for name, docs in itertools.chain(
162 162 extensions.enabled(False).iteritems(),
163 163 extensions.disabled().iteritems()):
164 164 if not docs:
165 165 continue
166 166 name = name.rpartition('.')[-1]
167 167 if lowercontains(name) or lowercontains(docs):
168 168 # extension docs are already translated
169 169 results['extensions'].append((name, docs.splitlines()[0]))
170 170 try:
171 171 mod = extensions.load(ui, name, '')
172 172 except ImportError:
173 173 # debug message would be printed in extensions.load()
174 174 continue
175 175 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
176 176 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
177 177 cmdname = cmdutil.parsealiases(cmd)[0]
178 178 cmddoc = pycompat.getdoc(entry[0])
179 179 if cmddoc:
180 180 cmddoc = gettext(cmddoc).splitlines()[0]
181 181 else:
182 182 cmddoc = _('(no help text available)')
183 183 if filtercmd(ui, cmdname, kw, cmddoc):
184 184 continue
185 185 results['extensioncommands'].append((cmdname, cmddoc))
186 186 return results
187 187
188 188 def loaddoc(topic, subdir=None):
189 189 """Return a delayed loader for help/topic.txt."""
190 190
191 191 def loader(ui):
192 192 docdir = os.path.join(util.datapath, 'help')
193 193 if subdir:
194 194 docdir = os.path.join(docdir, subdir)
195 195 path = os.path.join(docdir, topic + ".txt")
196 196 doc = gettext(util.readfile(path))
197 197 for rewriter in helphooks.get(topic, []):
198 198 doc = rewriter(ui, topic, doc)
199 199 return doc
200 200
201 201 return loader
202 202
203 203 internalstable = sorted([
204 204 (['bundle2'], _('Bundle2'),
205 205 loaddoc('bundle2', subdir='internals')),
206 206 (['bundles'], _('Bundles'),
207 207 loaddoc('bundles', subdir='internals')),
208 208 (['censor'], _('Censor'),
209 209 loaddoc('censor', subdir='internals')),
210 210 (['changegroups'], _('Changegroups'),
211 211 loaddoc('changegroups', subdir='internals')),
212 212 (['config'], _('Config Registrar'),
213 213 loaddoc('config', subdir='internals')),
214 214 (['requirements'], _('Repository Requirements'),
215 215 loaddoc('requirements', subdir='internals')),
216 216 (['revlogs'], _('Revision Logs'),
217 217 loaddoc('revlogs', subdir='internals')),
218 218 (['wireprotocol'], _('Wire Protocol'),
219 219 loaddoc('wireprotocol', subdir='internals')),
220 220 ])
221 221
222 222 def internalshelp(ui):
223 223 """Generate the index for the "internals" topic."""
224 224 lines = ['To access a subtopic, use "hg help internals.{subtopic-name}"\n',
225 225 '\n']
226 226 for names, header, doc in internalstable:
227 227 lines.append(' :%s: %s\n' % (names[0], header))
228 228
229 229 return ''.join(lines)
230 230
231 231 helptable = sorted([
232 232 (['bundlespec'], _("Bundle File Formats"), loaddoc('bundlespec')),
233 233 (['color'], _("Colorizing Outputs"), loaddoc('color')),
234 234 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
235 235 (['deprecated'], _("Deprecated Features"), loaddoc('deprecated')),
236 236 (["dates"], _("Date Formats"), loaddoc('dates')),
237 237 (["flags"], _("Command-line flags"), loaddoc('flags')),
238 238 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
239 239 (['environment', 'env'], _('Environment Variables'),
240 240 loaddoc('environment')),
241 241 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
242 242 _('Specifying Revisions'), loaddoc('revisions')),
243 243 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
244 244 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
245 245 (['merge-tools', 'mergetools', 'mergetool'], _('Merge Tools'),
246 246 loaddoc('merge-tools')),
247 247 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
248 248 loaddoc('templates')),
249 249 (['urls'], _('URL Paths'), loaddoc('urls')),
250 250 (["extensions"], _("Using Additional Features"), extshelp),
251 251 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
252 252 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
253 253 (["glossary"], _("Glossary"), loaddoc('glossary')),
254 254 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
255 255 loaddoc('hgignore')),
256 256 (["phases"], _("Working with Phases"), loaddoc('phases')),
257 257 (['scripting'], _('Using Mercurial from scripts and automation'),
258 258 loaddoc('scripting')),
259 259 (['internals'], _("Technical implementation topics"),
260 260 internalshelp),
261 261 (['pager'], _("Pager Support"), loaddoc('pager')),
262 262 ])
263 263
264 264 # Maps topics with sub-topics to a list of their sub-topics.
265 265 subtopics = {
266 266 'internals': internalstable,
267 267 }
268 268
269 269 # Map topics to lists of callable taking the current topic help and
270 270 # returning the updated version
271 271 helphooks = {}
272 272
273 273 def addtopichook(topic, rewriter):
274 274 helphooks.setdefault(topic, []).append(rewriter)
275 275
276 276 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
277 277 """Extract docstring from the items key to function mapping, build a
278 278 single documentation block and use it to overwrite the marker in doc.
279 279 """
280 280 entries = []
281 281 for name in sorted(items):
282 282 text = (pycompat.getdoc(items[name]) or '').rstrip()
283 283 if (not text
284 284 or not ui.verbose and any(w in text for w in _exclkeywords)):
285 285 continue
286 286 text = gettext(text)
287 287 if dedent:
288 288 # Abuse latin1 to use textwrap.dedent() on bytes.
289 289 text = textwrap.dedent(text.decode('latin1')).encode('latin1')
290 290 lines = text.splitlines()
291 291 doclines = [(lines[0])]
292 292 for l in lines[1:]:
293 293 # Stop once we find some Python doctest
294 294 if l.strip().startswith('>>>'):
295 295 break
296 296 if dedent:
297 297 doclines.append(l.rstrip())
298 298 else:
299 299 doclines.append(' ' + l.strip())
300 300 entries.append('\n'.join(doclines))
301 301 entries = '\n\n'.join(entries)
302 302 return doc.replace(marker, entries)
303 303
304 304 def addtopicsymbols(topic, marker, symbols, dedent=False):
305 305 def add(ui, topic, doc):
306 306 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
307 307 addtopichook(topic, add)
308 308
309 309 addtopicsymbols('bundlespec', '.. bundlecompressionmarker',
310 310 util.bundlecompressiontopics())
311 311 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
312 312 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
313 313 filemerge.internalsdoc)
314 314 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
315 315 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
316 316 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
317 317 addtopicsymbols('templates', '.. functionsmarker', templatefuncs.funcs)
318 318 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
319 319 dedent=True)
320 320
321 321 def help_(ui, commands, name, unknowncmd=False, full=True, subtopic=None,
322 322 **opts):
323 323 '''
324 324 Generate the help for 'name' as unformatted restructured text. If
325 325 'name' is None, describe the commands available.
326 326 '''
327 327
328 328 opts = pycompat.byteskwargs(opts)
329 329
330 330 def helpcmd(name, subtopic=None):
331 331 try:
332 332 aliases, entry = cmdutil.findcmd(name, commands.table,
333 333 strict=unknowncmd)
334 334 except error.AmbiguousCommand as inst:
335 335 # py3k fix: except vars can't be used outside the scope of the
336 336 # except block, nor can be used inside a lambda. python issue4617
337 337 prefix = inst.args[0]
338 338 select = lambda c: cmdutil.parsealiases(c)[0].startswith(prefix)
339 339 rst = helplist(select)
340 340 return rst
341 341
342 342 rst = []
343 343
344 344 # check if it's an invalid alias and display its error if it is
345 345 if getattr(entry[0], 'badalias', None):
346 346 rst.append(entry[0].badalias + '\n')
347 347 if entry[0].unknowncmd:
348 348 try:
349 349 rst.extend(helpextcmd(entry[0].cmdname))
350 350 except error.UnknownCommand:
351 351 pass
352 352 return rst
353 353
354 354 # synopsis
355 355 if len(entry) > 2:
356 356 if entry[2].startswith('hg'):
357 357 rst.append("%s\n" % entry[2])
358 358 else:
359 359 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
360 360 else:
361 361 rst.append('hg %s\n' % aliases[0])
362 362 # aliases
363 363 if full and not ui.quiet and len(aliases) > 1:
364 364 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
365 365 rst.append('\n')
366 366
367 367 # description
368 368 doc = gettext(pycompat.getdoc(entry[0]))
369 369 if not doc:
370 370 doc = _("(no help text available)")
371 371 if util.safehasattr(entry[0], 'definition'): # aliased command
372 372 source = entry[0].source
373 373 if entry[0].definition.startswith('!'): # shell alias
374 374 doc = (_('shell alias for: %s\n\n%s\n\ndefined by: %s\n') %
375 375 (entry[0].definition[1:], doc, source))
376 376 else:
377 377 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
378 378 (entry[0].definition, doc, source))
379 379 doc = doc.splitlines(True)
380 380 if ui.quiet or not full:
381 381 rst.append(doc[0])
382 382 else:
383 383 rst.extend(doc)
384 384 rst.append('\n')
385 385
386 386 # check if this command shadows a non-trivial (multi-line)
387 387 # extension help text
388 388 try:
389 389 mod = extensions.find(name)
390 390 doc = gettext(pycompat.getdoc(mod)) or ''
391 391 if '\n' in doc.strip():
392 392 msg = _("(use 'hg help -e %s' to show help for "
393 393 "the %s extension)") % (name, name)
394 394 rst.append('\n%s\n' % msg)
395 395 except KeyError:
396 396 pass
397 397
398 398 # options
399 399 if not ui.quiet and entry[1]:
400 400 rst.append(optrst(_("options"), entry[1], ui.verbose))
401 401
402 402 if ui.verbose:
403 403 rst.append(optrst(_("global options"),
404 404 commands.globalopts, ui.verbose))
405 405
406 406 if not ui.verbose:
407 407 if not full:
408 408 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
409 409 % name)
410 410 elif not ui.quiet:
411 411 rst.append(_('\n(some details hidden, use --verbose '
412 412 'to show complete help)'))
413 413
414 414 return rst
415 415
416 416
417 417 def helplist(select=None, **opts):
418 418 # list of commands
419 419 if name == "shortlist":
420 420 header = _('basic commands:\n\n')
421 421 elif name == "debug":
422 422 header = _('debug commands (internal and unsupported):\n\n')
423 423 else:
424 424 header = _('list of commands:\n\n')
425 425
426 426 h = {}
427 427 cmds = {}
428 428 for c, e in commands.table.iteritems():
429 429 fs = cmdutil.parsealiases(c)
430 430 f = fs[0]
431 431 p = ''
432 432 if c.startswith("^"):
433 433 p = '^'
434 434 if select and not select(p + f):
435 435 continue
436 436 if (not select and name != 'shortlist' and
437 437 e[0].__module__ != commands.__name__):
438 438 continue
439 439 if name == "shortlist" and not p:
440 440 continue
441 441 doc = pycompat.getdoc(e[0])
442 442 if filtercmd(ui, f, name, doc):
443 443 continue
444 444 doc = gettext(doc)
445 445 if not doc:
446 446 doc = _("(no help text available)")
447 447 h[f] = doc.splitlines()[0].rstrip()
448 448 cmds[f] = '|'.join(fs)
449 449
450 450 rst = []
451 451 if not h:
452 452 if not ui.quiet:
453 453 rst.append(_('no commands defined\n'))
454 454 return rst
455 455
456 456 if not ui.quiet:
457 457 rst.append(header)
458 458 fns = sorted(h)
459 459 for f in fns:
460 460 if ui.verbose:
461 461 commacmds = cmds[f].replace("|",", ")
462 462 rst.append(" :%s: %s\n" % (commacmds, h[f]))
463 463 else:
464 464 rst.append(' :%s: %s\n' % (f, h[f]))
465 465
466 466 ex = opts.get
467 467 anyopts = (ex(r'keyword') or not (ex(r'command') or ex(r'extension')))
468 468 if not name and anyopts:
469 469 exts = listexts(_('enabled extensions:'), extensions.enabled())
470 470 if exts:
471 471 rst.append('\n')
472 472 rst.extend(exts)
473 473
474 474 rst.append(_("\nadditional help topics:\n\n"))
475 475 topics = []
476 476 for names, header, doc in helptable:
477 477 topics.append((names[0], header))
478 478 for t, desc in topics:
479 479 rst.append(" :%s: %s\n" % (t, desc))
480 480
481 481 if ui.quiet:
482 482 pass
483 483 elif ui.verbose:
484 484 rst.append('\n%s\n' % optrst(_("global options"),
485 485 commands.globalopts, ui.verbose))
486 486 if name == 'shortlist':
487 487 rst.append(_("\n(use 'hg help' for the full list "
488 488 "of commands)\n"))
489 489 else:
490 490 if name == 'shortlist':
491 491 rst.append(_("\n(use 'hg help' for the full list of commands "
492 492 "or 'hg -v' for details)\n"))
493 493 elif name and not full:
494 494 rst.append(_("\n(use 'hg help %s' to show the full help "
495 495 "text)\n") % name)
496 496 elif name and cmds and name in cmds.keys():
497 497 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
498 498 "aliases and global options)\n") % name)
499 499 else:
500 500 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
501 501 "and global options)\n")
502 502 % (name and " " + name or ""))
503 503 return rst
504 504
505 505 def helptopic(name, subtopic=None):
506 506 # Look for sub-topic entry first.
507 507 header, doc = None, None
508 508 if subtopic and name in subtopics:
509 509 for names, header, doc in subtopics[name]:
510 510 if subtopic in names:
511 511 break
512 512
513 513 if not header:
514 514 for names, header, doc in helptable:
515 515 if name in names:
516 516 break
517 517 else:
518 518 raise error.UnknownCommand(name)
519 519
520 520 rst = [minirst.section(header)]
521 521
522 522 # description
523 523 if not doc:
524 524 rst.append(" %s\n" % _("(no help text available)"))
525 525 if callable(doc):
526 526 rst += [" %s\n" % l for l in doc(ui).splitlines()]
527 527
528 528 if not ui.verbose:
529 529 omitted = _('(some details hidden, use --verbose'
530 530 ' to show complete help)')
531 531 indicateomitted(rst, omitted)
532 532
533 533 try:
534 534 cmdutil.findcmd(name, commands.table)
535 535 rst.append(_("\nuse 'hg help -c %s' to see help for "
536 536 "the %s command\n") % (name, name))
537 537 except error.UnknownCommand:
538 538 pass
539 539 return rst
540 540
541 541 def helpext(name, subtopic=None):
542 542 try:
543 543 mod = extensions.find(name)
544 544 doc = gettext(pycompat.getdoc(mod)) or _('no help text available')
545 545 except KeyError:
546 546 mod = None
547 547 doc = extensions.disabledext(name)
548 548 if not doc:
549 549 raise error.UnknownCommand(name)
550 550
551 551 if '\n' not in doc:
552 552 head, tail = doc, ""
553 553 else:
554 554 head, tail = doc.split('\n', 1)
555 555 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
556 556 if tail:
557 557 rst.extend(tail.splitlines(True))
558 558 rst.append('\n')
559 559
560 560 if not ui.verbose:
561 561 omitted = _('(some details hidden, use --verbose'
562 562 ' to show complete help)')
563 563 indicateomitted(rst, omitted)
564 564
565 565 if mod:
566 566 try:
567 567 ct = mod.cmdtable
568 568 except AttributeError:
569 569 ct = {}
570 570 modcmds = set([c.partition('|')[0] for c in ct])
571 571 rst.extend(helplist(modcmds.__contains__))
572 572 else:
573 573 rst.append(_("(use 'hg help extensions' for information on enabling"
574 574 " extensions)\n"))
575 575 return rst
576 576
577 577 def helpextcmd(name, subtopic=None):
578 578 cmd, ext, doc = extensions.disabledcmd(ui, name,
579 579 ui.configbool('ui', 'strict'))
580 580 doc = doc.splitlines()[0]
581 581
582 582 rst = listexts(_("'%s' is provided by the following "
583 583 "extension:") % cmd, {ext: doc}, indent=4,
584 584 showdeprecated=True)
585 585 rst.append('\n')
586 586 rst.append(_("(use 'hg help extensions' for information on enabling "
587 587 "extensions)\n"))
588 588 return rst
589 589
590 590
591 591 rst = []
592 592 kw = opts.get('keyword')
593 593 if kw or name is None and any(opts[o] for o in opts):
594 594 matches = topicmatch(ui, commands, name or '')
595 595 helpareas = []
596 596 if opts.get('extension'):
597 597 helpareas += [('extensions', _('Extensions'))]
598 598 if opts.get('command'):
599 599 helpareas += [('commands', _('Commands'))]
600 600 if not helpareas:
601 601 helpareas = [('topics', _('Topics')),
602 602 ('commands', _('Commands')),
603 603 ('extensions', _('Extensions')),
604 604 ('extensioncommands', _('Extension Commands'))]
605 605 for t, title in helpareas:
606 606 if matches[t]:
607 607 rst.append('%s:\n\n' % title)
608 608 rst.extend(minirst.maketable(sorted(matches[t]), 1))
609 609 rst.append('\n')
610 610 if not rst:
611 611 msg = _('no matches')
612 612 hint = _("try 'hg help' for a list of topics")
613 613 raise error.Abort(msg, hint=hint)
614 614 elif name and name != 'shortlist':
615 615 queries = []
616 616 if unknowncmd:
617 617 queries += [helpextcmd]
618 618 if opts.get('extension'):
619 619 queries += [helpext]
620 620 if opts.get('command'):
621 621 queries += [helpcmd]
622 622 if not queries:
623 623 queries = (helptopic, helpcmd, helpext, helpextcmd)
624 624 for f in queries:
625 625 try:
626 626 rst = f(name, subtopic)
627 627 break
628 628 except error.UnknownCommand:
629 629 pass
630 630 else:
631 631 if unknowncmd:
632 632 raise error.UnknownCommand(name)
633 633 else:
634 634 msg = _('no such help topic: %s') % name
635 635 hint = _("try 'hg help --keyword %s'") % name
636 636 raise error.Abort(msg, hint=hint)
637 637 else:
638 638 # program name
639 639 if not ui.quiet:
640 640 rst = [_("Mercurial Distributed SCM\n"), '\n']
641 641 rst.extend(helplist(None, **pycompat.strkwargs(opts)))
642 642
643 643 return ''.join(rst)
644 644
645 645 def formattedhelp(ui, commands, name, keep=None, unknowncmd=False, full=True,
646 646 **opts):
647 647 """get help for a given topic (as a dotted name) as rendered rst
648 648
649 649 Either returns the rendered help text or raises an exception.
650 650 """
651 651 if keep is None:
652 652 keep = []
653 653 else:
654 654 keep = list(keep) # make a copy so we can mutate this later
655 655 fullname = name
656 656 section = None
657 657 subtopic = None
658 658 if name and '.' in name:
659 659 name, remaining = name.split('.', 1)
660 660 remaining = encoding.lower(remaining)
661 661 if '.' in remaining:
662 662 subtopic, section = remaining.split('.', 1)
663 663 else:
664 664 if name in subtopics:
665 665 subtopic = remaining
666 666 else:
667 667 section = remaining
668 668 textwidth = ui.configint('ui', 'textwidth')
669 669 termwidth = ui.termwidth() - 2
670 670 if textwidth <= 0 or termwidth < textwidth:
671 671 textwidth = termwidth
672 672 text = help_(ui, commands, name,
673 673 subtopic=subtopic, unknowncmd=unknowncmd, full=full, **opts)
674 674
675 formatted, pruned = minirst.format(text, textwidth, keep=keep,
676 section=section)
675 blocks, pruned = minirst.parse(text, keep=keep)
676 if section:
677 blocks = minirst.filtersections(blocks, section)
678 formatted = minirst.formatplain(blocks, textwidth)
677 679
678 680 # We could have been given a weird ".foo" section without a name
679 681 # to look for, or we could have simply failed to found "foo.bar"
680 682 # because bar isn't a section of foo
681 683 if section and not (formatted and name):
682 684 raise error.Abort(_("help section not found: %s") % fullname)
683 685
684 686 if 'verbose' in pruned:
685 687 keep.append('omitted')
686 688 else:
687 689 keep.append('notomitted')
688 formatted, pruned = minirst.format(text, textwidth, keep=keep,
689 section=section)
690 return formatted
690 blocks, pruned = minirst.parse(text, keep=keep)
691 if section:
692 blocks = minirst.filtersections(blocks, section)
693 return minirst.formatplain(blocks, textwidth)
General Comments 0
You need to be logged in to leave comments. Login now