Moving Pager to Core
Note:
This page is primarily intended for developers of Mercurial.
Pager is currently a hacky extension, and breaks some things in odd ways. Given a concerted refactor, it could be much less fragile by moving it into core hg.
1. Current Problems
- Pager only applies to a handful of whitelisted commands, and aliases using those commands don't get paged
- Pager breaks interactivity of commands
- Sometimes surprising things get paged.
We don't know what the default pager configuration be?
Probably less, and probably set LESS=FSRX if LESS isn't already set?
- We don't detect nested pagers, and it will lose colors
2. Proposal
It looks like git just hard-codes which commands use the pager.
2.1. Using "with" context
We could probably do something similar by having a paged context manager on ui, eg:
with ui.paged: # all ui prints here go to the pager
As the pager is the child process (see 369741ef7253 and bb3d5c20eaf6), we can terminate it. So it could end and re-start in theory.
The main problem (jun thinks) is when SIGPIPE (the user exits the pager) happens, we face the choice of
- terminate the process
- redirect remaining output to /dev/null
"1" makes more sense for cases like "hg log". "2" would require an additional layer of pipes and is useful if we want to continue outputting without being paged (like backtrace). If we go this approach, we probably want "1" for perf and simplicity, and may special handling the backtrace logic.
2.2. An irreversible action
If we treat the "start pager" action as irreversible, we can have a simpler API:
ui.pager() # all subsequent output goes to the pager
That'd solve the problem of [alias] entries not getting paged, and would avoid multi-mode commands (eg shelve) from always being paged. We could also have ui.interactive() produce a developer warning ('tried to use ui.interactive() after enabling the pager') to prevent interactive-with-pager-running problems.
This is probably good as the first step.
3. Handling errors
If you use --traceback, currently the error is paged. This doesn't seem ideal, but there doesn't appear to be a good solution other than always emitting the error on stderr and terminating output to the pager as soon as an error occurs.