hint: add a simple framework for registering hint messages

Summary:
This allows us to have a unified way to print hint messages at the end of a
command. It would be helpful for feature discovery in general.

Reviewed By: mjpieters

Differential Revision: D7392132

fbshipit-source-id: 8b4e94cc2176266652459ecca3428bd86d95bfe2
This commit is contained in:
Jun Wu 2018-04-07 00:36:43 -07:00 committed by Saurabh Singh
parent bdbf60f28d
commit 14783221f6
8 changed files with 136 additions and 0 deletions

View File

@ -113,6 +113,7 @@ _defaultstyles = {
'formatvariant.config.special': 'yellow',
'formatvariant.config.default': 'green',
'formatvariant.default': '',
'hint.prefix': 'yellow',
'histedit.remaining': 'red bold',
'ui.prompt': 'yellow',
'log.changeset': 'yellow',

View File

@ -603,6 +603,9 @@ coreconfigitem('fsmonitor', 'warn_when_unused',
coreconfigitem('fsmonitor', 'warn_update_file_count',
default=50000,
)
coreconfigitem('hint', 'ack',
default=list,
)
coreconfigitem('hooks', '.*',
default=dynamicdefault,
generic=True,

View File

@ -31,6 +31,7 @@ from . import (
fancyopts,
help,
hg,
hintutil,
hook,
profiling,
pycompat,
@ -693,6 +694,7 @@ def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
# run post-hook, passing command result
hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
result=ret, pats=cmdpats, opts=cmdoptions)
hintutil.show(lui)
except Exception:
# run failure hook and re-raise
hook.hook(lui, repo, "fail-%s" % cmd, False, args=" ".join(fullargs),

View File

@ -374,6 +374,7 @@ def loadall(ui, whitelist=None):
commands,
filemerge,
fileset,
hintutil,
revset,
templatefilters,
templatekw,
@ -395,6 +396,7 @@ def loadall(ui, whitelist=None):
('templatefilter', templatefilters, 'loadfilter'),
('templatefunc', templater, 'loadfunction'),
('templatekeyword', templatekw, 'loadkeyword'),
('hint', hintutil, 'loadhint'),
]
_loadextra(ui, newindex, extraloaders)

View File

@ -863,6 +863,20 @@ Supported arguments:
``color``
Set branch edges color in hexadecimal RGB notation.
``hint``
--------
Some commands show hints about features, like::
hint[import]: use 'hg import' to import commits exported by 'hg export'
They can be silenced by ``hg hint --ack import``, which writes the
``hint.ack`` config in user hgrc.
``ack``
A list of hint IDs that were acknowledged so they will not
be shown again. If set to ``*``, silence all hints.
``hooks``
---------

50
mercurial/hintutil.py Normal file
View File

@ -0,0 +1,50 @@
# hint.py - utilities to register hint messages
#
# Copyright 2018 Facebook Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from .i18n import _
hinttable = {}
messages = []
triggered = set()
def loadhint(ui, extname, registrarobj):
for name, func in registrarobj._table.iteritems():
hinttable[name] = func
def trigger(name, *args, **kwargs):
"""Trigger a hint message. It will be shown at the end of the command."""
func = hinttable.get(name)
if func and name not in triggered:
triggered.add(name)
msg = func(*args, **kwargs)
if msg:
messages.append((name, msg.rstrip()))
def _prefix(ui, name):
"""Return "hint[%s]" % name, colored"""
return ui.label(_('hint[%s]: ') % (name,), 'hint.prefix')
def show(ui):
"""Show all triggered hint messages"""
if ui.plain():
return
acked = ui.configlist('hint', 'ack')
if acked == ['*']:
def isacked(name):
return True
else:
acked = set(acked)
def isacked(name):
return name in acked or ui.configbool('hint', 'ack-%s' % name)
names = []
for name, msg in messages:
if not isacked(name):
prefix = _prefix(ui, name)
ui.write_err(('%s%s\n') % (prefix, msg.rstrip()))
names.append(name)

View File

@ -419,3 +419,23 @@ class internalmerge(_funcregistrarbase):
func.mergetype = mergetype
func.onfailure = onfailure
func.precheck = precheck
class hint(_funcregistrarbase):
"""Decorator to register hint messages
Usage::
# register a hint message
hint = register.hint()
@hint('next')
def nextmsg(fromnode, tonode):
return (_('use "hg next" to go from %s to %s')
% (short(fromnode), short(tonode)))
# trigger a hint message
def update(repo, destnode):
wnode = repo['.'].node()
if repo[destnode].p1().node() == wnode:
hint.trigger('next', wnode, tonode)
"""

44
tests/test-hint.t Normal file
View File

@ -0,0 +1,44 @@
$ cat > showhint.py << EOF
> from mercurial import (
> cmdutil,
> hintutil,
> registrar,
> )
>
> cmdtable = {}
> command = registrar.command(cmdtable)
>
> hint = registrar.hint()
>
> @hint('next')
> def hintnext(a, b):
> return "use 'hg next' to go from %s to %s" % (a, b)
>
> @hint('export')
> def hintexport(a):
> return "use 'hg export %s' to show commit content" % (a,)
>
> @command('showhint', norepo=True)
> def showhint(*args):
> hintutil.trigger('export', 'P')
> hintutil.trigger('next', 'X', 'Y')
> hintutil.trigger('export', 'Q')
> EOF
$ setconfig extensions.showhint=$TESTTMP/showhint.py
$ hg showhint
hint[export]: use 'hg export P' to show commit content
hint[next]: use 'hg next' to go from X to Y
Test HGPLAIN=1 silences all hints
$ HGPLAIN=1 hg showhint
Test silence configs
$ hg showhint --config hint.ack-export=True
hint[next]: use 'hg next' to go from X to Y
$ hg showhint --config hint.ack=next
hint[export]: use 'hg export P' to show commit content
$ hg showhint --config hint.ack=*