comparison mercurial/commands.py @ 18746:c0087d48ec3a

help: move the majority of the help command to the help module We move the logic for generating the unformatted ReST source to the help module, in order to eventually avoid calling commands.help_() from hgweb. No functionality change.
author Dan Villiom Podlaski Christiansen <danchr@gmail.com>
date Sat, 09 Feb 2013 21:51:21 +0000
parents 6b786dc88612
children 56dd55da2f7d 87441497ecaa
comparison
equal deleted inserted replaced
18745:3c7c25fa58e0 18746:c0087d48ec3a
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 from node import hex, bin, nullid, nullrev, short 8 from node import hex, bin, nullid, nullrev, short
9 from lock import release 9 from lock import release
10 from i18n import _, gettext 10 from i18n import _
11 import os, re, difflib, time, tempfile, errno 11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks 12 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery 13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect 14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver 15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod 16 import merge as mergemod
17 import minirst, revset, fileset 17 import minirst, revset, fileset
3212 [('e', 'extension', None, _('show only help for extensions')), 3212 [('e', 'extension', None, _('show only help for extensions')),
3213 ('c', 'command', None, _('show only help for commands')), 3213 ('c', 'command', None, _('show only help for commands')),
3214 ('k', 'keyword', '', _('show topics matching keyword')), 3214 ('k', 'keyword', '', _('show topics matching keyword')),
3215 ], 3215 ],
3216 _('[-ec] [TOPIC]')) 3216 _('[-ec] [TOPIC]'))
3217 def help_(ui, name=None, unknowncmd=False, full=True, **opts): 3217 def help_(ui, name=None, **opts):
3218 """show help for a given topic or a help overview 3218 """show help for a given topic or a help overview
3219 3219
3220 With no arguments, print a list of commands with short help messages. 3220 With no arguments, print a list of commands with short help messages.
3221 3221
3222 Given a topic, extension, or command name, print help for that 3222 Given a topic, extension, or command name, print help for that
3225 Returns 0 if successful. 3225 Returns 0 if successful.
3226 """ 3226 """
3227 3227
3228 textwidth = min(ui.termwidth(), 80) - 2 3228 textwidth = min(ui.termwidth(), 80) - 2
3229 3229
3230 def helpcmd(name):
3231 try:
3232 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3233 except error.AmbiguousCommand, inst:
3234 # py3k fix: except vars can't be used outside the scope of the
3235 # except block, nor can be used inside a lambda. python issue4617
3236 prefix = inst.args[0]
3237 select = lambda c: c.lstrip('^').startswith(prefix)
3238 rst = helplist(select)
3239 return rst
3240
3241 rst = []
3242
3243 # check if it's an invalid alias and display its error if it is
3244 if getattr(entry[0], 'badalias', False):
3245 if not unknowncmd:
3246 ui.pushbuffer()
3247 entry[0](ui)
3248 rst.append(ui.popbuffer())
3249 return rst
3250
3251 # synopsis
3252 if len(entry) > 2:
3253 if entry[2].startswith('hg'):
3254 rst.append("%s\n" % entry[2])
3255 else:
3256 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3257 else:
3258 rst.append('hg %s\n' % aliases[0])
3259 # aliases
3260 if full and not ui.quiet and len(aliases) > 1:
3261 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3262 rst.append('\n')
3263
3264 # description
3265 doc = gettext(entry[0].__doc__)
3266 if not doc:
3267 doc = _("(no help text available)")
3268 if util.safehasattr(entry[0], 'definition'): # aliased command
3269 if entry[0].definition.startswith('!'): # shell alias
3270 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3271 else:
3272 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3273 doc = doc.splitlines(True)
3274 if ui.quiet or not full:
3275 rst.append(doc[0])
3276 else:
3277 rst.extend(doc)
3278 rst.append('\n')
3279
3280 # check if this command shadows a non-trivial (multi-line)
3281 # extension help text
3282 try:
3283 mod = extensions.find(name)
3284 doc = gettext(mod.__doc__) or ''
3285 if '\n' in doc.strip():
3286 msg = _('use "hg help -e %s" to show help for '
3287 'the %s extension') % (name, name)
3288 rst.append('\n%s\n' % msg)
3289 except KeyError:
3290 pass
3291
3292 # options
3293 if not ui.quiet and entry[1]:
3294 rst.append('\n%s\n\n' % _("options:"))
3295 rst.append(help.optrst(entry[1], ui.verbose))
3296
3297 if ui.verbose:
3298 rst.append('\n%s\n\n' % _("global options:"))
3299 rst.append(help.optrst(globalopts, ui.verbose))
3300
3301 if not ui.verbose:
3302 if not full:
3303 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3304 % name)
3305 elif not ui.quiet:
3306 omitted = _('use "hg -v help %s" to show more complete'
3307 ' help and the global options') % name
3308 notomitted = _('use "hg -v help %s" to show'
3309 ' the global options') % name
3310 help.indicateomitted(rst, omitted, notomitted)
3311
3312 return rst
3313
3314
3315 def helplist(select=None):
3316 # list of commands
3317 if name == "shortlist":
3318 header = _('basic commands:\n\n')
3319 else:
3320 header = _('list of commands:\n\n')
3321
3322 h = {}
3323 cmds = {}
3324 for c, e in table.iteritems():
3325 f = c.split("|", 1)[0]
3326 if select and not select(f):
3327 continue
3328 if (not select and name != 'shortlist' and
3329 e[0].__module__ != __name__):
3330 continue
3331 if name == "shortlist" and not f.startswith("^"):
3332 continue
3333 f = f.lstrip("^")
3334 if not ui.debugflag and f.startswith("debug"):
3335 continue
3336 doc = e[0].__doc__
3337 if doc and 'DEPRECATED' in doc and not ui.verbose:
3338 continue
3339 doc = gettext(doc)
3340 if not doc:
3341 doc = _("(no help text available)")
3342 h[f] = doc.splitlines()[0].rstrip()
3343 cmds[f] = c.lstrip("^")
3344
3345 rst = []
3346 if not h:
3347 if not ui.quiet:
3348 rst.append(_('no commands defined\n'))
3349 return rst
3350
3351 if not ui.quiet:
3352 rst.append(header)
3353 fns = sorted(h)
3354 for f in fns:
3355 if ui.verbose:
3356 commands = cmds[f].replace("|",", ")
3357 rst.append(" :%s: %s\n" % (commands, h[f]))
3358 else:
3359 rst.append(' :%s: %s\n' % (f, h[f]))
3360
3361 if not name:
3362 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3363 if exts:
3364 rst.append('\n')
3365 rst.extend(exts)
3366
3367 rst.append(_("\nadditional help topics:\n\n"))
3368 topics = []
3369 for names, header, doc in help.helptable:
3370 topics.append((names[0], header))
3371 for t, desc in topics:
3372 rst.append(" :%s: %s\n" % (t, desc))
3373
3374 optlist = []
3375 if not ui.quiet:
3376 if ui.verbose:
3377 optlist.append((_("global options:"), globalopts))
3378 if name == 'shortlist':
3379 optlist.append((_('use "hg help" for the full list '
3380 'of commands'), ()))
3381 else:
3382 if name == 'shortlist':
3383 msg = _('use "hg help" for the full list of commands '
3384 'or "hg -v" for details')
3385 elif name and not full:
3386 msg = _('use "hg help %s" to show the full help '
3387 'text') % name
3388 else:
3389 msg = _('use "hg -v help%s" to show builtin aliases and '
3390 'global options') % (name and " " + name or "")
3391 optlist.append((msg, ()))
3392
3393 if optlist:
3394 for title, options in optlist:
3395 rst.append('\n%s\n' % title)
3396 if options:
3397 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3398 return rst
3399
3400 def helptopic(name):
3401 for names, header, doc in help.helptable:
3402 if name in names:
3403 break
3404 else:
3405 raise error.UnknownCommand(name)
3406
3407 rst = ["%s\n\n" % header]
3408 # description
3409 if not doc:
3410 rst.append(" %s\n" % _("(no help text available)"))
3411 if util.safehasattr(doc, '__call__'):
3412 rst += [" %s\n" % l for l in doc().splitlines()]
3413
3414 if not ui.verbose:
3415 omitted = (_('use "hg help -v %s" to show more complete help') %
3416 name)
3417 help.indicateomitted(rst, omitted)
3418
3419 try:
3420 cmdutil.findcmd(name, table)
3421 rst.append(_('\nuse "hg help -c %s" to see help for '
3422 'the %s command\n') % (name, name))
3423 except error.UnknownCommand:
3424 pass
3425 return rst
3426
3427 def helpext(name):
3428 try:
3429 mod = extensions.find(name)
3430 doc = gettext(mod.__doc__) or _('no help text available')
3431 except KeyError:
3432 mod = None
3433 doc = extensions.disabledext(name)
3434 if not doc:
3435 raise error.UnknownCommand(name)
3436
3437 if '\n' not in doc:
3438 head, tail = doc, ""
3439 else:
3440 head, tail = doc.split('\n', 1)
3441 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3442 if tail:
3443 rst.extend(tail.splitlines(True))
3444 rst.append('\n')
3445
3446 if not ui.verbose:
3447 omitted = (_('use "hg help -v %s" to show more complete help') %
3448 name)
3449 help.indicateomitted(rst, omitted)
3450
3451 if mod:
3452 try:
3453 ct = mod.cmdtable
3454 except AttributeError:
3455 ct = {}
3456 modcmds = set([c.split('|', 1)[0] for c in ct])
3457 rst.extend(helplist(modcmds.__contains__))
3458 else:
3459 rst.append(_('use "hg help extensions" for information on enabling '
3460 'extensions\n'))
3461 return rst
3462
3463 def helpextcmd(name):
3464 cmd, ext, mod = extensions.disabledcmd(ui, name,
3465 ui.configbool('ui', 'strict'))
3466 doc = gettext(mod.__doc__).splitlines()[0]
3467
3468 rst = help.listexts(_("'%s' is provided by the following "
3469 "extension:") % cmd, {ext: doc}, indent=4)
3470 rst.append('\n')
3471 rst.append(_('use "hg help extensions" for information on enabling '
3472 'extensions\n'))
3473 return rst
3474
3475
3476 rst = []
3477 kw = opts.get('keyword')
3478 if kw:
3479 matches = help.topicmatch(kw)
3480 for t, title in (('topics', _('Topics')),
3481 ('commands', _('Commands')),
3482 ('extensions', _('Extensions')),
3483 ('extensioncommands', _('Extension Commands'))):
3484 if matches[t]:
3485 rst.append('%s:\n\n' % title)
3486 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3487 rst.append('\n')
3488 elif name and name != 'shortlist':
3489 i = None
3490 if unknowncmd:
3491 queries = (helpextcmd,)
3492 elif opts.get('extension'):
3493 queries = (helpext,)
3494 elif opts.get('command'):
3495 queries = (helpcmd,)
3496 else:
3497 queries = (helptopic, helpcmd, helpext, helpextcmd)
3498 for f in queries:
3499 try:
3500 rst = f(name)
3501 i = None
3502 break
3503 except error.UnknownCommand, inst:
3504 i = inst
3505 if i:
3506 raise i
3507 else:
3508 # program name
3509 if not ui.quiet:
3510 rst = [_("Mercurial Distributed SCM\n"), '\n']
3511 rst.extend(helplist())
3512
3513 keep = ui.verbose and ['verbose'] or [] 3230 keep = ui.verbose and ['verbose'] or []
3514 text = ''.join(rst) 3231 text = help.help_(ui, name, **opts)
3232
3515 formatted, pruned = minirst.format(text, textwidth, keep=keep) 3233 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3516 if 'verbose' in pruned: 3234 if 'verbose' in pruned:
3517 keep.append('omitted') 3235 keep.append('omitted')
3518 else: 3236 else:
3519 keep.append('notomitted') 3237 keep.append('notomitted')