Mercurial > hg
comparison mercurial/dispatch.py @ 37134:6890b7e991a4
help: supporting both help and doc for aliases
This allows an alias to be definted like:
[alias]
lj = log -Tjson
lj:help = [-r REV]
lj:doc = Shows the revision log in JSON format.
Differential Revision: https://phab.mercurial-scm.org/D2678
author | Rodrigo Damazio <rdamazio@google.com> |
---|---|
date | Sun, 04 Mar 2018 17:11:33 -0500 |
parents | a8a902d7176e |
children | aa55c5354b8f |
comparison
equal
deleted
inserted
replaced
37133:a2a6755a3def | 37134:6890b7e991a4 |
---|---|
448 regex = '|'.join(replacemap.keys()).replace('$', br'\$') | 448 regex = '|'.join(replacemap.keys()).replace('$', br'\$') |
449 r = re.compile(regex) | 449 r = re.compile(regex) |
450 return r.sub(lambda x: replacemap[x.group()], cmd) | 450 return r.sub(lambda x: replacemap[x.group()], cmd) |
451 | 451 |
452 class cmdalias(object): | 452 class cmdalias(object): |
453 def __init__(self, name, definition, cmdtable, source): | 453 def __init__(self, ui, name, definition, cmdtable, source): |
454 self.name = self.cmd = name | 454 self.name = self.cmd = name |
455 self.cmdname = '' | 455 self.cmdname = '' |
456 self.definition = definition | 456 self.definition = definition |
457 self.fn = None | 457 self.fn = None |
458 self.givenargs = [] | 458 self.givenargs = [] |
475 if not self.definition: | 475 if not self.definition: |
476 self.badalias = _("no definition for alias '%s'") % self.name | 476 self.badalias = _("no definition for alias '%s'") % self.name |
477 return | 477 return |
478 | 478 |
479 if self.definition.startswith('!'): | 479 if self.definition.startswith('!'): |
480 shdef = self.definition[1:] | |
480 self.shell = True | 481 self.shell = True |
481 def fn(ui, *args): | 482 def fn(ui, *args): |
482 env = {'HG_ARGS': ' '.join((self.name,) + args)} | 483 env = {'HG_ARGS': ' '.join((self.name,) + args)} |
483 def _checkvar(m): | 484 def _checkvar(m): |
484 if m.groups()[0] == '$': | 485 if m.groups()[0] == '$': |
488 else: | 489 else: |
489 ui.debug("No argument found for substitution " | 490 ui.debug("No argument found for substitution " |
490 "of %i variable in alias '%s' definition.\n" | 491 "of %i variable in alias '%s' definition.\n" |
491 % (int(m.groups()[0]), self.name)) | 492 % (int(m.groups()[0]), self.name)) |
492 return '' | 493 return '' |
493 cmd = re.sub(br'\$(\d+|\$)', _checkvar, self.definition[1:]) | 494 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef) |
494 cmd = aliasinterpolate(self.name, args, cmd) | 495 cmd = aliasinterpolate(self.name, args, cmd) |
495 return ui.system(cmd, environ=env, | 496 return ui.system(cmd, environ=env, |
496 blockedtag='alias_%s' % self.name) | 497 blockedtag='alias_%s' % self.name) |
497 self.fn = fn | 498 self.fn = fn |
499 self._populatehelp(ui, name, shdef, self.fn) | |
498 return | 500 return |
499 | 501 |
500 try: | 502 try: |
501 args = pycompat.shlexsplit(self.definition) | 503 args = pycompat.shlexsplit(self.definition) |
502 except ValueError as inst: | 504 except ValueError as inst: |
514 self.givenargs = args | 516 self.givenargs = args |
515 | 517 |
516 try: | 518 try: |
517 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1] | 519 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1] |
518 if len(tableentry) > 2: | 520 if len(tableentry) > 2: |
519 self.fn, self.opts, self.help = tableentry | 521 self.fn, self.opts, cmdhelp = tableentry |
520 else: | 522 else: |
521 self.fn, self.opts = tableentry | 523 self.fn, self.opts = tableentry |
522 | 524 cmdhelp = None |
523 if self.help.startswith("hg " + cmd): | 525 |
524 # drop prefix in old-style help lines so hg shows the alias | 526 self._populatehelp(ui, name, cmd, self.fn, cmdhelp) |
525 self.help = self.help[4 + len(cmd):] | |
526 self.__doc__ = self.fn.__doc__ | |
527 | 527 |
528 except error.UnknownCommand: | 528 except error.UnknownCommand: |
529 self.badalias = (_("alias '%s' resolves to unknown command '%s'") | 529 self.badalias = (_("alias '%s' resolves to unknown command '%s'") |
530 % (self.name, cmd)) | 530 % (self.name, cmd)) |
531 self.unknowncmd = True | 531 self.unknowncmd = True |
532 except error.AmbiguousCommand: | 532 except error.AmbiguousCommand: |
533 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'") | 533 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'") |
534 % (self.name, cmd)) | 534 % (self.name, cmd)) |
535 | |
536 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None): | |
537 self.help = ui.config('alias', '%s:help' % name, defaulthelp or '') | |
538 if self.help and self.help.startswith("hg " + cmd): | |
539 # drop prefix in old-style help lines so hg shows the alias | |
540 self.help = self.help[4 + len(cmd):] | |
541 | |
542 self.__doc__ = ui.config('alias', '%s:doc' % name, fn.__doc__) | |
535 | 543 |
536 @property | 544 @property |
537 def args(self): | 545 def args(self): |
538 args = pycompat.maplist(util.expandpath, self.givenargs) | 546 args = pycompat.maplist(util.expandpath, self.givenargs) |
539 return aliasargs(self.fn, args) | 547 return aliasargs(self.fn, args) |
575 raise | 583 raise |
576 | 584 |
577 class lazyaliasentry(object): | 585 class lazyaliasentry(object): |
578 """like a typical command entry (func, opts, help), but is lazy""" | 586 """like a typical command entry (func, opts, help), but is lazy""" |
579 | 587 |
580 def __init__(self, name, definition, cmdtable, source): | 588 def __init__(self, ui, name, definition, cmdtable, source): |
589 self.ui = ui | |
581 self.name = name | 590 self.name = name |
582 self.definition = definition | 591 self.definition = definition |
583 self.cmdtable = cmdtable.copy() | 592 self.cmdtable = cmdtable.copy() |
584 self.source = source | 593 self.source = source |
585 | 594 |
586 @util.propertycache | 595 @util.propertycache |
587 def _aliasdef(self): | 596 def _aliasdef(self): |
588 return cmdalias(self.name, self.definition, self.cmdtable, self.source) | 597 return cmdalias(self.ui, self.name, self.definition, self.cmdtable, |
598 self.source) | |
589 | 599 |
590 def __getitem__(self, n): | 600 def __getitem__(self, n): |
591 aliasdef = self._aliasdef | 601 aliasdef = self._aliasdef |
592 if n == 0: | 602 if n == 0: |
593 return aliasdef | 603 return aliasdef |
607 | 617 |
608 def addaliases(ui, cmdtable): | 618 def addaliases(ui, cmdtable): |
609 # aliases are processed after extensions have been loaded, so they | 619 # aliases are processed after extensions have been loaded, so they |
610 # may use extension commands. Aliases can also use other alias definitions, | 620 # may use extension commands. Aliases can also use other alias definitions, |
611 # but only if they have been defined prior to the current definition. | 621 # but only if they have been defined prior to the current definition. |
612 for alias, definition in ui.configitems('alias'): | 622 for alias, definition in ui.configitems('alias', ignoresub=True): |
613 try: | 623 try: |
614 if cmdtable[alias].definition == definition: | 624 if cmdtable[alias].definition == definition: |
615 continue | 625 continue |
616 except (KeyError, AttributeError): | 626 except (KeyError, AttributeError): |
617 # definition might not exist or it might not be a cmdalias | 627 # definition might not exist or it might not be a cmdalias |
618 pass | 628 pass |
619 | 629 |
620 source = ui.configsource('alias', alias) | 630 source = ui.configsource('alias', alias) |
621 entry = lazyaliasentry(alias, definition, cmdtable, source) | 631 entry = lazyaliasentry(ui, alias, definition, cmdtable, source) |
622 cmdtable[alias] = entry | 632 cmdtable[alias] = entry |
623 | 633 |
624 def _parse(ui, args): | 634 def _parse(ui, args): |
625 options = {} | 635 options = {} |
626 cmdoptions = {} | 636 cmdoptions = {} |