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