diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -427,7 +427,7 @@ continue # Same for aliases. - if ui.config('alias', name): + if ui.config('alias', name, None): continue ui.setconfig('alias', name, 'show %s' % view, source='show') diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -114,7 +114,7 @@ coreconfigitem = getitemregister(coreitems) coreconfigitem('alias', '.*', - default=None, + default=dynamicdefault, generic=True, ) coreconfigitem('annotate', 'nodates', diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py --- a/mercurial/dispatch.py +++ b/mercurial/dispatch.py @@ -450,7 +450,7 @@ return r.sub(lambda x: replacemap[x.group()], cmd) class cmdalias(object): - def __init__(self, name, definition, cmdtable, source): + def __init__(self, ui, name, definition, cmdtable, source): self.name = self.cmd = name self.cmdname = '' self.definition = definition @@ -477,6 +477,7 @@ return if self.definition.startswith('!'): + shdef = self.definition[1:] self.shell = True def fn(ui, *args): env = {'HG_ARGS': ' '.join((self.name,) + args)} @@ -490,11 +491,12 @@ "of %i variable in alias '%s' definition.\n" % (int(m.groups()[0]), self.name)) return '' - cmd = re.sub(br'\$(\d+|\$)', _checkvar, self.definition[1:]) + cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef) cmd = aliasinterpolate(self.name, args, cmd) return ui.system(cmd, environ=env, blockedtag='alias_%s' % self.name) self.fn = fn + self._populatehelp(ui, name, shdef, self.fn) return try: @@ -516,14 +518,12 @@ try: tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1] if len(tableentry) > 2: - self.fn, self.opts, self.help = tableentry + self.fn, self.opts, cmdhelp = tableentry else: self.fn, self.opts = tableentry + cmdhelp = None - if self.help.startswith("hg " + cmd): - # drop prefix in old-style help lines so hg shows the alias - self.help = self.help[4 + len(cmd):] - self.__doc__ = self.fn.__doc__ + self._populatehelp(ui, name, cmd, self.fn, cmdhelp) except error.UnknownCommand: self.badalias = (_("alias '%s' resolves to unknown command '%s'") @@ -533,6 +533,14 @@ self.badalias = (_("alias '%s' resolves to ambiguous command '%s'") % (self.name, cmd)) + def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None): + self.help = ui.config('alias', '%s:help' % name, defaulthelp or '') + if self.help and self.help.startswith("hg " + cmd): + # drop prefix in old-style help lines so hg shows the alias + self.help = self.help[4 + len(cmd):] + + self.__doc__ = ui.config('alias', '%s:doc' % name, fn.__doc__) + @property def args(self): args = pycompat.maplist(util.expandpath, self.givenargs) @@ -577,7 +585,8 @@ class lazyaliasentry(object): """like a typical command entry (func, opts, help), but is lazy""" - def __init__(self, name, definition, cmdtable, source): + def __init__(self, ui, name, definition, cmdtable, source): + self.ui = ui self.name = name self.definition = definition self.cmdtable = cmdtable.copy() @@ -585,7 +594,8 @@ @util.propertycache def _aliasdef(self): - return cmdalias(self.name, self.definition, self.cmdtable, self.source) + return cmdalias(self.ui, self.name, self.definition, self.cmdtable, + self.source) def __getitem__(self, n): aliasdef = self._aliasdef @@ -609,7 +619,7 @@ # aliases are processed after extensions have been loaded, so they # may use extension commands. Aliases can also use other alias definitions, # but only if they have been defined prior to the current definition. - for alias, definition in ui.configitems('alias'): + for alias, definition in ui.configitems('alias', ignoresub=True): try: if cmdtable[alias].definition == definition: continue @@ -618,7 +628,7 @@ pass source = ui.configsource('alias', alias) - entry = lazyaliasentry(alias, definition, cmdtable, source) + entry = lazyaliasentry(ui, alias, definition, cmdtable, source) cmdtable[alias] = entry def _parse(ui, args): diff --git a/mercurial/help.py b/mercurial/help.py --- a/mercurial/help.py +++ b/mercurial/help.py @@ -370,8 +370,8 @@ if util.safehasattr(entry[0], 'definition'): # aliased command source = entry[0].source if entry[0].definition.startswith('!'): # shell alias - doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') % - (entry[0].definition[1:], source)) + doc = (_('shell alias for: %s\n\n%s\n\ndefined by: %s\n') % + (entry[0].definition[1:], doc, source)) else: doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') % (entry[0].definition, doc, source)) diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -739,11 +739,7 @@ def configitems(self, section, untrusted=False, ignoresub=False): items = self._data(untrusted).items(section) if ignoresub: - newitems = {} - for k, v in items: - if ':' not in k: - newitems[k] = v - items = list(newitems.iteritems()) + items = [i for i in items if ':' not in i[0]] if self.debugflag and not untrusted and self._reportuntrusted: for k, v in self._ucfg.items(section): if self._tcfg.get(section, k) != v: diff --git a/tests/test-alias.t b/tests/test-alias.t --- a/tests/test-alias.t +++ b/tests/test-alias.t @@ -4,9 +4,13 @@ > # should clobber ci but not commit (issue2993) > ci = version > myinit = init + > myinit:doc = This is my documented alias for init. + > myinit:help = [OPTIONS] [BLA] [BLE] > mycommit = commit + > mycommit:doc = This is my alias with only doc. > optionalrepo = showconfig alias.myinit > cleanstatus = status -c + > cleanstatus:help = [ONLYHELPHERE] > unknown = bargle > ambiguous = s > recursive = recursive @@ -20,9 +24,13 @@ > no--config = status --config a.config=1 > mylog = log > lognull = log -r null + > lognull:doc = Logs the null rev + > lognull:help = foo bar baz > shortlog = log --template '{rev} {node|short} | {date|isodate}\n' > positional = log --template '{\$2} {\$1} | {date|isodate}\n' > dln = lognull --debug + > recursivedoc = dln + > recursivedoc:doc = Logs the null rev in debug mode > nousage = rollback > put = export -r 0 -o "\$FOO/%R.diff" > blank = !printf '\n' @@ -53,11 +61,148 @@ > log = -v > EOF - basic $ hg myinit alias +help + + $ hg help -c | grep myinit + myinit This is my documented alias for init. + $ hg help -c | grep mycommit + mycommit This is my alias with only doc. + $ hg help -c | grep cleanstatus + cleanstatus show changed files in the working directory + $ hg help -c | grep lognull + lognull Logs the null rev + $ hg help -c | grep dln + dln Logs the null rev + $ hg help -c | grep recursivedoc + recursivedoc Logs the null rev in debug mode + $ hg help myinit + hg myinit [OPTIONS] [BLA] [BLE] + + alias for: hg init + + This is my documented alias for init. + + defined by: * (glob) + */* (glob) (?) + */* (glob) (?) + */* (glob) (?) + + options: + + -e --ssh CMD specify ssh command to use + --remotecmd CMD specify hg command to run on the remote side + --insecure do not verify server certificate (ignoring web.cacerts + config) + + (some details hidden, use --verbose to show complete help) + + $ hg help mycommit + hg mycommit [OPTION]... [FILE]... + + alias for: hg commit + + This is my alias with only doc. + + defined by: * (glob) + */* (glob) (?) + */* (glob) (?) + */* (glob) (?) + + options ([+] can be repeated): + + -A --addremove mark new/missing files as added/removed before + committing + --close-branch mark a branch head as closed + --amend amend the parent of the working directory + -s --secret use the secret phase for committing + -e --edit invoke editor on commit messages + -i --interactive use interactive mode + -I --include PATTERN [+] include names matching the given patterns + -X --exclude PATTERN [+] exclude names matching the given patterns + -m --message TEXT use text as commit message + -l --logfile FILE read commit message from file + -d --date DATE record the specified date as commit date + -u --user USER record the specified user as committer + -S --subrepos recurse into subrepositories + + (some details hidden, use --verbose to show complete help) + + $ hg help cleanstatus + hg cleanstatus [ONLYHELPHERE] + + alias for: hg status -c + + show changed files in the working directory + + Show status of files in the repository. If names are given, only files + that match are shown. Files that are clean or ignored or the source of a + copy/move operation, are not listed unless -c/--clean, -i/--ignored, + -C/--copies or -A/--all are given. Unless options described with "show + only ..." are given, the options -mardu are used. + + Option -q/--quiet hides untracked (unknown and ignored) files unless + explicitly requested with -u/--unknown or -i/--ignored. + + Note: + 'hg status' may appear to disagree with diff if permissions have + changed or a merge has occurred. The standard diff format does not + report permission changes and diff only reports changes relative to one + merge parent. + + If one revision is given, it is used as the base revision. If two + revisions are given, the differences between them are shown. The --change + option can also be used as a shortcut to list the changed files of a + revision from its first parent. + + The codes used to show the status of files are: + + M = modified + A = added + R = removed + C = clean + ! = missing (deleted by non-hg command, but still tracked) + ? = not tracked + I = ignored + = origin of the previous file (with --copies) + + Returns 0 on success. + + defined by: * (glob) + */* (glob) (?) + */* (glob) (?) + */* (glob) (?) + + options ([+] can be repeated): + + -A --all show status of all files + -m --modified show only modified files + -a --added show only added files + -r --removed show only removed files + -d --deleted show only deleted (but tracked) files + -c --clean show only files without changes + -u --unknown show only unknown (not tracked) files + -i --ignored show only ignored files + -n --no-status hide status prefix + -C --copies show source of copied files + -0 --print0 end filenames with NUL, for use with xargs + --rev REV [+] show difference from revision + --change REV list the changed files of a revision + -I --include PATTERN [+] include names matching the given patterns + -X --exclude PATTERN [+] exclude names matching the given patterns + -S --subrepos recurse into subrepositories + + (some details hidden, use --verbose to show complete help) + + $ hg help recursivedoc | head -n 5 + hg recursivedoc foo bar baz + + alias for: hg dln + + Logs the null rev in debug mode unknown @@ -440,6 +585,10 @@ > rebate = !echo this is \$HG_ARGS > EOF #endif + $ cat >> .hg/hgrc < rebate:doc = This is my alias which just prints something. + > rebate:help = [MYARGS] + > EOF $ hg reba hg: command 'reba' is ambiguous: rebase rebate @@ -449,6 +598,24 @@ $ hg rebat --foo-bar this is rebate --foo-bar +help for a shell alias + + $ hg help -c | grep rebate + rebate This is my alias which just prints something. + $ hg help rebate + hg rebate [MYARGS] + + shell alias for: echo this is $HG_ARGS + + This is my alias which just prints something. + + defined by:* (glob) + */* (glob) (?) + */* (glob) (?) + */* (glob) (?) + + (some details hidden, use --verbose to show complete help) + invalid arguments $ hg rt foo diff --git a/tests/test-help.t b/tests/test-help.t --- a/tests/test-help.t +++ b/tests/test-help.t @@ -777,9 +777,9 @@ $ hg help shellalias hg shellalias - shell alias for: - - echo hi + shell alias for: echo hi + + (no help text available) defined by: helpext