[PATCH v2] pager: migrate heavily-used extension into core

Sean Farley sean at farley.io
Mon Feb 6 18:04:54 EST 2017


Augie Fackler <raf at durin42.com> writes:

> (sending again because this seems to have gotten stuck somewhere...)
> (+yuya explicitly for chg thoughts, +smf so someone else can forward to the list if it's stuck again)
>
> On Fri, Feb 03, 2017 at 04:16:09PM -0800, Bryan O'Sullivan wrote:
>> # HG changeset patch
>> # User Bryan O'Sullivan <bryano at fb.com>
>> # Date 1486160890 28800
>> #      Fri Feb 03 14:28:10 2017 -0800
>> # Node ID 30ee18bf947b97eca3582555f63eb3b2441e9db8
>> # Parent  abf029200e198878a4576a87e095bd8d77d9cea9
>> pager: migrate heavily-used extension into core
>> 
>> No default behaviours were harmed during the making of this change.
>> 
>> Note: this patch will break out-of-tree extensions that rely on the
>> location of the old pager module's attend variable.  It is now a
>> static variable named pagedcommands on the ui class.
>
> I've got feedback on this approach, which I'd like to talk out a bit
> before we either decide to land this or go on a v3 voyage. See below.
>
> If this is agreeable, I'll just push other things aside and do this,
> since it's something that we've got pretty clear consensus on, and I'm
> the one proposing a chunk of work to try and gild the lily.
>
> Sorry for how long this is - if you want, jump to the API sketch at
> the bottom and start from there, and look at my paragraph of rationale
> only if that looks bad?
>
>> 
>> diff --git a/mercurial/commands.py b/mercurial/commands.py
>> --- a/mercurial/commands.py
>> +++ b/mercurial/commands.py
>> @@ -107,6 +107,8 @@ globalopts = [
>>     ('', 'version', None, _('output version information and exit')),
>>     ('h', 'help', None, _('display help and exit')),
>>     ('', 'hidden', False, _('consider hidden changesets')),
>> +    ('', 'pager', 'auto',
>> +     _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
>> ]
>> 
>> dryrunopts = [('n', 'dry-run', None,
>> diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
>> --- a/mercurial/dispatch.py
>> +++ b/mercurial/dispatch.py
>> @@ -816,6 +816,39 @@ def _dispatch(req):
>> def _runcommand(ui, options, cmd, cmdfunc):
>>     """Run a command function, possibly with profiling enabled."""
>>     try:
>> +        p = ui.config("pager", "pager", encoding.environ.get("PAGER"))
>> +        usepager = ui.pageractive
>> +        always = util.parsebool(options['pager'])
>> +        auto = options['pager'] == 'auto'
>> +
>> +        if not p or '--debugger' in sys.argv or not ui.formatted():
>> +            pass
>> +        elif always:
>> +            usepager = True
>> +        elif not auto:
>> +            usepager = False
>> +        else:
>> +            attend = ui.configlist('pager', 'attend', ui.pagedcommands)
>> +            ignore = ui.configlist('pager', 'ignore')
>> +            cmds, _ = cmdutil.findcmd(cmd, commands.table)
>
> This bums me out as an approach, because it means that a command is
> necessarily always paged or always not paged, which is not always
> appropriate. The immediate example I can think of is shelve, which is
> multi-mode:
>
> `shelve --list --patch` -> definitely wants to be paged, this is
> likely a ton of output
>
> `shelve --interactive` -> is *broken* if a pager is in play.
>
> Rather than stick with the brute-force attend list in core, I'd like
> to move in the direction of adding a ui.pager() call to the ui object,
> which starts the pager. We'd then have a transitional period (a couple
> of releases?) where programmatically setting the attend list was
> supported in the old pager extension code, and then always support
> setting pager.attend to forcibly page commands which don't think they
> want pager love. This also plays reasonably well with chg, because it
> means that there's (still) a trivial point for chg to be told "start
> the pager now".
>
> My reason for wanting to move away from the attend list is the above,
> but also that it's hopelessly buggy in certain circumstances, like
> aliases, and it doesn't have a good affordance for new commands to
> specify default behavior (other than poking themselves in a list, but
> if the user has configured the attend list they no longer get the
> benefits of the sane defaults people hopefully put thought into).
>
> How does that sound, overall? I'll tackle the refactoring today or
> Wednesday to mail an RFC patch if that doesn't sound too much like the
> perfect being the enemy of the good.
>
> (This design, btw, was inspired by the way git handles paging, where
> it's largely up to the command to decide if it wants to invoke the
> pager.)

If I'm understanding you correctly, this will get rid of the
pager.attend variable? If that's true, then I fully support that.

> As a sketch of where this is headed, API-wise:
>
> class ui:
>  def pager(self, command, category):
>    ""Starts the pager, if desired by the user.
>
>    `command` specifies the current command the user is running,
>    something like `log` or `shelve`. It should be the whole original
>    command name, not the partial name or alias name.
>
>    `category` specifies a broad category this pager invocation fits
>    into. Examples include `diff`, `log`, `status`, `help`. This
>    allows users to disable paging of entire types of commands easily.
>    """
>    # pager starts, self.pageractive=true, etc
>
> @command
> def shelve(ui, ...):
>  if action == 'list':
>    ui.pager('shelve', 'diff' if --patch else 'log')
>  ...
>
> @command
> def summary(ui, ...):
>  ui.pager('summary', 'status')
>  ...

Would this get rid of the need to set pager.pager=less? I think last
time the pager was brought up (I believe the Munich sprint), there was a
consensus on not relying on the existence of less / more / windows
weirdness.

The API looks pretty good to me. Nothing off the top of my head that I
can add / question besides what I asked above.


More information about the Mercurial-devel mailing list