2008-03-20 02:57:14 +03:00
|
|
|
# pager.py - display output using a pager
|
|
|
|
#
|
|
|
|
# Copyright 2008 David Soria Parra <dsp@php.net>
|
|
|
|
#
|
2009-04-26 03:08:54 +04:00
|
|
|
# This software may be used and distributed according to the terms of the
|
2010-01-20 07:20:08 +03:00
|
|
|
# GNU General Public License version 2 or any later version.
|
2008-03-20 02:57:14 +03:00
|
|
|
#
|
2010-08-28 06:36:35 +04:00
|
|
|
# To load the extension, add it to your configuration file:
|
2008-03-20 02:57:14 +03:00
|
|
|
#
|
|
|
|
# [extension]
|
2009-12-22 02:50:03 +03:00
|
|
|
# pager =
|
2008-03-20 02:57:14 +03:00
|
|
|
#
|
2008-04-03 15:47:05 +04:00
|
|
|
# Run "hg help pager" to get info on configuration.
|
|
|
|
|
2009-06-22 17:48:08 +04:00
|
|
|
'''browse command output with an external pager
|
2008-04-03 15:47:05 +04:00
|
|
|
|
2009-07-23 02:24:03 +04:00
|
|
|
To set the pager that should be used, set the application variable::
|
2008-04-03 15:47:05 +04:00
|
|
|
|
|
|
|
[pager]
|
2012-07-31 17:50:44 +04:00
|
|
|
pager = less -FRX
|
2008-04-03 15:47:05 +04:00
|
|
|
|
2009-07-26 03:56:02 +04:00
|
|
|
If no pager is set, the pager extensions uses the environment variable
|
|
|
|
$PAGER. If neither pager.pager, nor $PAGER is set, no pager is used.
|
2008-04-03 15:47:05 +04:00
|
|
|
|
|
|
|
You can disable the pager for certain commands by adding them to the
|
2009-07-23 02:24:03 +04:00
|
|
|
pager.ignore list::
|
2008-04-03 15:47:05 +04:00
|
|
|
|
|
|
|
[pager]
|
|
|
|
ignore = version, help, update
|
|
|
|
|
2009-07-26 03:56:02 +04:00
|
|
|
You can also enable the pager only for certain commands using
|
2009-11-12 18:29:40 +03:00
|
|
|
pager.attend. Below is the default list of commands to be paged::
|
2008-04-03 15:47:05 +04:00
|
|
|
|
|
|
|
[pager]
|
2009-11-12 18:29:40 +03:00
|
|
|
attend = annotate, cat, diff, export, glog, log, qdiff
|
|
|
|
|
|
|
|
Setting pager.attend to an empty value will cause all commands to be
|
|
|
|
paged.
|
2008-04-03 15:47:05 +04:00
|
|
|
|
|
|
|
If pager.attend is present, pager.ignore will be ignored.
|
|
|
|
|
2014-05-09 22:32:56 +04:00
|
|
|
Lastly, you can enable and disable paging for individual commands with
|
|
|
|
the attend-<command> option. This setting takes precedence over
|
|
|
|
existing attend and ignore options and defaults::
|
|
|
|
|
|
|
|
[pager]
|
|
|
|
attend-cat = false
|
|
|
|
|
2010-04-22 12:24:49 +04:00
|
|
|
To ignore global commands like :hg:`version` or :hg:`help`, you have
|
2010-08-28 06:36:35 +04:00
|
|
|
to specify them in your user configuration file.
|
2010-10-10 21:21:48 +04:00
|
|
|
|
2015-11-30 21:47:33 +03:00
|
|
|
To control whether the pager is used at all for an individual command,
|
|
|
|
you can use --pager=<value>::
|
|
|
|
|
|
|
|
- use as needed: `auto`.
|
|
|
|
- require the pager: `yes` or `on`.
|
|
|
|
- suppress the pager: `no` or `off` (any unrecognized value
|
|
|
|
will also work).
|
2014-05-09 22:32:56 +04:00
|
|
|
|
2008-04-03 15:47:05 +04:00
|
|
|
'''
|
2016-02-29 06:15:00 +03:00
|
|
|
from __future__ import absolute_import
|
|
|
|
|
|
|
|
import atexit
|
|
|
|
import os
|
|
|
|
import signal
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
|
2016-05-14 08:03:12 +03:00
|
|
|
from mercurial.i18n import _
|
2016-02-29 06:15:00 +03:00
|
|
|
from mercurial import (
|
|
|
|
cmdutil,
|
|
|
|
commands,
|
|
|
|
dispatch,
|
|
|
|
extensions,
|
|
|
|
util,
|
|
|
|
)
|
2008-03-20 02:57:14 +03:00
|
|
|
|
2015-04-28 23:44:37 +03:00
|
|
|
# Note for extension authors: ONLY specify testedwith = 'internal' for
|
|
|
|
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
|
|
|
|
# be specifying the version(s) of Mercurial they are tested with, or
|
|
|
|
# leave the attribute unspecified.
|
2012-05-15 23:37:49 +04:00
|
|
|
testedwith = 'internal'
|
|
|
|
|
2015-10-03 09:02:52 +03:00
|
|
|
def _runpager(ui, p):
|
2012-05-11 17:45:37 +04:00
|
|
|
pager = subprocess.Popen(p, shell=True, bufsize=-1,
|
|
|
|
close_fds=util.closefds, stdin=subprocess.PIPE,
|
|
|
|
stdout=sys.stdout, stderr=sys.stderr)
|
|
|
|
|
2015-10-03 09:16:33 +03:00
|
|
|
# back up original file objects and descriptors
|
|
|
|
olduifout = ui.fout
|
|
|
|
oldstdout = sys.stdout
|
2015-10-03 12:48:21 +03:00
|
|
|
stdoutfd = os.dup(sys.stdout.fileno())
|
|
|
|
stderrfd = os.dup(sys.stderr.fileno())
|
2015-10-03 09:16:33 +03:00
|
|
|
|
|
|
|
# create new line-buffered stdout so that output can show up immediately
|
|
|
|
ui.fout = sys.stdout = newstdout = os.fdopen(sys.stdout.fileno(), 'wb', 1)
|
2012-05-11 17:45:37 +04:00
|
|
|
os.dup2(pager.stdin.fileno(), sys.stdout.fileno())
|
2012-05-20 23:33:49 +04:00
|
|
|
if ui._isatty(sys.stderr):
|
2012-05-11 17:45:37 +04:00
|
|
|
os.dup2(pager.stdin.fileno(), sys.stderr.fileno())
|
|
|
|
|
|
|
|
@atexit.register
|
|
|
|
def killpager():
|
2013-02-23 01:17:33 +04:00
|
|
|
if util.safehasattr(signal, "SIGINT"):
|
|
|
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
2012-05-11 17:45:37 +04:00
|
|
|
pager.stdin.close()
|
2015-10-03 09:16:33 +03:00
|
|
|
ui.fout = olduifout
|
|
|
|
sys.stdout = oldstdout
|
|
|
|
# close new stdout while it's associated with pager; otherwise stdout
|
|
|
|
# fd would be closed when newstdout is deleted
|
|
|
|
newstdout.close()
|
|
|
|
# restore original fds: stdout is open again
|
2015-10-03 12:48:21 +03:00
|
|
|
os.dup2(stdoutfd, sys.stdout.fileno())
|
|
|
|
os.dup2(stderrfd, sys.stderr.fileno())
|
2012-05-11 17:45:37 +04:00
|
|
|
pager.wait()
|
2010-05-03 23:00:34 +04:00
|
|
|
|
2008-03-20 02:57:14 +03:00
|
|
|
def uisetup(ui):
|
2012-05-20 23:33:49 +04:00
|
|
|
if '--debugger' in sys.argv or not ui.formatted():
|
2010-06-19 20:20:12 +04:00
|
|
|
return
|
|
|
|
|
2016-03-14 18:03:19 +03:00
|
|
|
# chg has its own pager implementation
|
|
|
|
argv = sys.argv[:]
|
|
|
|
if 'chgunix' in dispatch._earlygetopt(['--cmdserver'], argv):
|
|
|
|
return
|
|
|
|
|
2008-10-23 02:34:52 +04:00
|
|
|
def pagecmd(orig, ui, options, cmd, cmdfunc):
|
2008-03-29 21:41:50 +03:00
|
|
|
p = ui.config("pager", "pager", os.environ.get("PAGER"))
|
2014-05-09 21:58:53 +04:00
|
|
|
usepager = False
|
2014-05-09 22:05:52 +04:00
|
|
|
always = util.parsebool(options['pager'])
|
2014-05-09 22:07:50 +04:00
|
|
|
auto = options['pager'] == 'auto'
|
2011-06-02 01:43:34 +04:00
|
|
|
|
2014-05-09 21:58:53 +04:00
|
|
|
if not p:
|
|
|
|
pass
|
2014-05-09 22:05:52 +04:00
|
|
|
elif always:
|
|
|
|
usepager = True
|
2014-05-09 22:07:50 +04:00
|
|
|
elif not auto:
|
|
|
|
usepager = False
|
2014-05-09 21:58:53 +04:00
|
|
|
else:
|
2009-11-12 18:29:40 +03:00
|
|
|
attend = ui.configlist('pager', 'attend', attended)
|
2014-05-09 22:10:23 +04:00
|
|
|
ignore = ui.configlist('pager', 'ignore')
|
2013-10-13 05:51:34 +04:00
|
|
|
cmds, _ = cmdutil.findcmd(cmd, commands.table)
|
|
|
|
|
|
|
|
for cmd in cmds:
|
2014-05-09 22:32:56 +04:00
|
|
|
var = 'attend-%s' % cmd
|
|
|
|
if ui.config('pager', var):
|
|
|
|
usepager = ui.configbool('pager', var)
|
|
|
|
break
|
2014-05-09 22:07:50 +04:00
|
|
|
if (cmd in attend or
|
|
|
|
(cmd not in ignore and not attend)):
|
2014-05-09 21:58:53 +04:00
|
|
|
usepager = True
|
2013-10-13 05:51:34 +04:00
|
|
|
break
|
2014-05-09 21:58:53 +04:00
|
|
|
|
2015-02-06 23:07:56 +03:00
|
|
|
setattr(ui, 'pageractive', usepager)
|
|
|
|
|
2014-05-09 21:58:53 +04:00
|
|
|
if usepager:
|
|
|
|
ui.setconfig('ui', 'formatted', ui.formatted(), 'pager')
|
|
|
|
ui.setconfig('ui', 'interactive', False, 'pager')
|
|
|
|
if util.safehasattr(signal, "SIGPIPE"):
|
|
|
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
|
|
_runpager(ui, p)
|
2008-10-23 02:34:52 +04:00
|
|
|
return orig(ui, options, cmd, cmdfunc)
|
2008-03-29 21:41:50 +03:00
|
|
|
|
2015-02-06 23:09:09 +03:00
|
|
|
# Wrap dispatch._runcommand after color is loaded so color can see
|
|
|
|
# ui.pageractive. Otherwise, if we loaded first, color's wrapped
|
|
|
|
# dispatch._runcommand would run without having access to ui.pageractive.
|
|
|
|
def afterloaded(loaded):
|
|
|
|
extensions.wrapfunction(dispatch, '_runcommand', pagecmd)
|
|
|
|
extensions.afterloaded('color', afterloaded)
|
2009-11-12 18:29:40 +03:00
|
|
|
|
2010-10-10 21:21:48 +04:00
|
|
|
def extsetup(ui):
|
|
|
|
commands.globalopts.append(
|
|
|
|
('', 'pager', 'auto',
|
|
|
|
_("when to paginate (boolean, always, auto, or never)"),
|
|
|
|
_('TYPE')))
|
|
|
|
|
2009-11-12 18:29:40 +03:00
|
|
|
attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']
|