diff -r 3c7c25fa58e0 -r c0087d48ec3a mercurial/help.py --- a/mercurial/help.py Sat Feb 09 21:51:21 2013 +0000 +++ b/mercurial/help.py Sat Feb 09 21:51:21 2013 +0000 @@ -6,9 +6,10 @@ # GNU General Public License version 2 or any later version. from i18n import gettext, _ -import itertools, sys, os +import itertools, sys, os, error import extensions, revset, fileset, templatekw, templatefilters, filemerge import encoding, util, minirst +import cmdutil def listexts(header, exts, indent=1): '''return a text listing of the given extensions''' @@ -206,3 +207,297 @@ addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols) addtopicsymbols('templates', '.. keywordsmarker', templatekw.dockeywords) addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters) + +def help_(ui, name, unknowncmd=False, full=True, **opts): + ''' + Generate the help for 'name' as unformatted restructured text. If + 'name' is None, describe the commands available. + ''' + + import commands # avoid cycle + + def helpcmd(name): + try: + aliases, entry = cmdutil.findcmd(name, commands.table, + strict=unknowncmd) + except error.AmbiguousCommand, inst: + # py3k fix: except vars can't be used outside the scope of the + # except block, nor can be used inside a lambda. python issue4617 + prefix = inst.args[0] + select = lambda c: c.lstrip('^').startswith(prefix) + rst = helplist(select) + return rst + + rst = [] + + # check if it's an invalid alias and display its error if it is + if getattr(entry[0], 'badalias', False): + if not unknowncmd: + ui.pushbuffer() + entry[0](ui) + rst.append(ui.popbuffer()) + return rst + + # synopsis + if len(entry) > 2: + if entry[2].startswith('hg'): + rst.append("%s\n" % entry[2]) + else: + rst.append('hg %s %s\n' % (aliases[0], entry[2])) + else: + rst.append('hg %s\n' % aliases[0]) + # aliases + if full and not ui.quiet and len(aliases) > 1: + rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:])) + rst.append('\n') + + # description + doc = gettext(entry[0].__doc__) + if not doc: + doc = _("(no help text available)") + if util.safehasattr(entry[0], 'definition'): # aliased command + if entry[0].definition.startswith('!'): # shell alias + doc = _('shell alias for::\n\n %s') % entry[0].definition[1:] + else: + doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc) + doc = doc.splitlines(True) + if ui.quiet or not full: + rst.append(doc[0]) + else: + rst.extend(doc) + rst.append('\n') + + # check if this command shadows a non-trivial (multi-line) + # extension help text + try: + mod = extensions.find(name) + doc = gettext(mod.__doc__) or '' + if '\n' in doc.strip(): + msg = _('use "hg help -e %s" to show help for ' + 'the %s extension') % (name, name) + rst.append('\n%s\n' % msg) + except KeyError: + pass + + # options + if not ui.quiet and entry[1]: + rst.append('\n%s\n\n' % _("options:")) + rst.append(optrst(entry[1], ui.verbose)) + + if ui.verbose: + rst.append('\n%s\n\n' % _("global options:")) + rst.append(optrst(commands.globalopts, ui.verbose)) + + if not ui.verbose: + if not full: + rst.append(_('\nuse "hg help %s" to show the full help text\n') + % name) + elif not ui.quiet: + omitted = _('use "hg -v help %s" to show more complete' + ' help and the global options') % name + notomitted = _('use "hg -v help %s" to show' + ' the global options') % name + indicateomitted(rst, omitted, notomitted) + + return rst + + + def helplist(select=None): + # list of commands + if name == "shortlist": + header = _('basic commands:\n\n') + else: + header = _('list of commands:\n\n') + + h = {} + cmds = {} + for c, e in commands.table.iteritems(): + f = c.split("|", 1)[0] + if select and not select(f): + continue + if (not select and name != 'shortlist' and + e[0].__module__ != commands.__name__): + continue + if name == "shortlist" and not f.startswith("^"): + continue + f = f.lstrip("^") + if not ui.debugflag and f.startswith("debug"): + continue + doc = e[0].__doc__ + if doc and 'DEPRECATED' in doc and not ui.verbose: + continue + doc = gettext(doc) + if not doc: + doc = _("(no help text available)") + h[f] = doc.splitlines()[0].rstrip() + cmds[f] = c.lstrip("^") + + rst = [] + if not h: + if not ui.quiet: + rst.append(_('no commands defined\n')) + return rst + + if not ui.quiet: + rst.append(header) + fns = sorted(h) + for f in fns: + if ui.verbose: + commacmds = cmds[f].replace("|",", ") + rst.append(" :%s: %s\n" % (commacmds, h[f])) + else: + rst.append(' :%s: %s\n' % (f, h[f])) + + if not name: + exts = listexts(_('enabled extensions:'), extensions.enabled()) + if exts: + rst.append('\n') + rst.extend(exts) + + rst.append(_("\nadditional help topics:\n\n")) + topics = [] + for names, header, doc in helptable: + topics.append((names[0], header)) + for t, desc in topics: + rst.append(" :%s: %s\n" % (t, desc)) + + optlist = [] + if not ui.quiet: + if ui.verbose: + optlist.append((_("global options:"), commands.globalopts)) + if name == 'shortlist': + optlist.append((_('use "hg help" for the full list ' + 'of commands'), ())) + else: + if name == 'shortlist': + msg = _('use "hg help" for the full list of commands ' + 'or "hg -v" for details') + elif name and not full: + msg = _('use "hg help %s" to show the full help ' + 'text') % name + else: + msg = _('use "hg -v help%s" to show builtin aliases and ' + 'global options') % (name and " " + name or "") + optlist.append((msg, ())) + + if optlist: + for title, options in optlist: + rst.append('\n%s\n' % title) + if options: + rst.append('\n%s\n' % optrst(options, ui.verbose)) + return rst + + def helptopic(name): + for names, header, doc in helptable: + if name in names: + break + else: + raise error.UnknownCommand(name) + + rst = ["%s\n\n" % header] + # description + if not doc: + rst.append(" %s\n" % _("(no help text available)")) + if util.safehasattr(doc, '__call__'): + rst += [" %s\n" % l for l in doc().splitlines()] + + if not ui.verbose: + omitted = (_('use "hg help -v %s" to show more complete help') % + name) + indicateomitted(rst, omitted) + + try: + cmdutil.findcmd(name, commands.table) + rst.append(_('\nuse "hg help -c %s" to see help for ' + 'the %s command\n') % (name, name)) + except error.UnknownCommand: + pass + return rst + + def helpext(name): + try: + mod = extensions.find(name) + doc = gettext(mod.__doc__) or _('no help text available') + except KeyError: + mod = None + doc = extensions.disabledext(name) + if not doc: + raise error.UnknownCommand(name) + + if '\n' not in doc: + head, tail = doc, "" + else: + head, tail = doc.split('\n', 1) + rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)] + if tail: + rst.extend(tail.splitlines(True)) + rst.append('\n') + + if not ui.verbose: + omitted = (_('use "hg help -v %s" to show more complete help') % + name) + indicateomitted(rst, omitted) + + if mod: + try: + ct = mod.cmdtable + except AttributeError: + ct = {} + modcmds = set([c.split('|', 1)[0] for c in ct]) + rst.extend(helplist(modcmds.__contains__)) + else: + rst.append(_('use "hg help extensions" for information on enabling ' + 'extensions\n')) + return rst + + def helpextcmd(name): + cmd, ext, mod = extensions.disabledcmd(ui, name, + ui.configbool('ui', 'strict')) + doc = gettext(mod.__doc__).splitlines()[0] + + rst = listexts(_("'%s' is provided by the following " + "extension:") % cmd, {ext: doc}, indent=4) + rst.append('\n') + rst.append(_('use "hg help extensions" for information on enabling ' + 'extensions\n')) + return rst + + + rst = [] + kw = opts.get('keyword') + if kw: + matches = topicmatch(kw) + for t, title in (('topics', _('Topics')), + ('commands', _('Commands')), + ('extensions', _('Extensions')), + ('extensioncommands', _('Extension Commands'))): + if matches[t]: + rst.append('%s:\n\n' % title) + rst.extend(minirst.maketable(sorted(matches[t]), 1)) + rst.append('\n') + elif name and name != 'shortlist': + i = None + if unknowncmd: + queries = (helpextcmd,) + elif opts.get('extension'): + queries = (helpext,) + elif opts.get('command'): + queries = (helpcmd,) + else: + queries = (helptopic, helpcmd, helpext, helpextcmd) + for f in queries: + try: + rst = f(name) + i = None + break + except error.UnknownCommand, inst: + i = inst + if i: + raise i + else: + # program name + if not ui.quiet: + rst = [_("Mercurial Distributed SCM\n"), '\n'] + rst.extend(helplist()) + + return ''.join(rst)