summaryrefslogtreecommitdiff
path: root/hgext/pager.py
diff options
context:
space:
mode:
Diffstat (limited to 'hgext/pager.py')
-rw-r--r--hgext/pager.py140
1 files changed, 140 insertions, 0 deletions
diff --git a/hgext/pager.py b/hgext/pager.py
new file mode 100644
index 0000000..ae430ef
--- /dev/null
+++ b/hgext/pager.py
@@ -0,0 +1,140 @@
+# pager.py - display output using a pager
+#
+# Copyright 2008 David Soria Parra <dsp@php.net>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+#
+# To load the extension, add it to your configuration file:
+#
+# [extension]
+# pager =
+#
+# Run "hg help pager" to get info on configuration.
+
+'''browse command output with an external pager
+
+To set the pager that should be used, set the application variable::
+
+ [pager]
+ pager = less -FRX
+
+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.
+
+You can disable the pager for certain commands by adding them to the
+pager.ignore list::
+
+ [pager]
+ ignore = version, help, update
+
+You can also enable the pager only for certain commands using
+pager.attend. Below is the default list of commands to be paged::
+
+ [pager]
+ attend = annotate, cat, diff, export, glog, log, qdiff
+
+Setting pager.attend to an empty value will cause all commands to be
+paged.
+
+If pager.attend is present, pager.ignore will be ignored.
+
+To ignore global commands like :hg:`version` or :hg:`help`, you have
+to specify them in your user configuration file.
+
+The --pager=... option can also be used to control when the pager is
+used. Use a boolean value like yes, no, on, off, or use auto for
+normal behavior.
+'''
+
+import atexit, sys, os, signal, subprocess
+from mercurial import commands, dispatch, util, extensions
+from mercurial.i18n import _
+
+testedwith = 'internal'
+
+def _pagerfork(ui, p):
+ if not util.safehasattr(os, 'fork'):
+ sys.stdout = util.popen(p, 'wb')
+ if ui._isatty(sys.stderr):
+ sys.stderr = sys.stdout
+ return
+ fdin, fdout = os.pipe()
+ pid = os.fork()
+ if pid == 0:
+ os.close(fdin)
+ os.dup2(fdout, sys.stdout.fileno())
+ if ui._isatty(sys.stderr):
+ os.dup2(fdout, sys.stderr.fileno())
+ os.close(fdout)
+ return
+ os.dup2(fdin, sys.stdin.fileno())
+ os.close(fdin)
+ os.close(fdout)
+ try:
+ os.execvp('/bin/sh', ['/bin/sh', '-c', p])
+ except OSError, e:
+ if e.errno == errno.ENOENT:
+ # no /bin/sh, try executing the pager directly
+ args = shlex.split(p)
+ os.execvp(args[0], args)
+ else:
+ raise
+
+def _pagersubprocess(ui, p):
+ pager = subprocess.Popen(p, shell=True, bufsize=-1,
+ close_fds=util.closefds, stdin=subprocess.PIPE,
+ stdout=sys.stdout, stderr=sys.stderr)
+
+ stdout = os.dup(sys.stdout.fileno())
+ stderr = os.dup(sys.stderr.fileno())
+ os.dup2(pager.stdin.fileno(), sys.stdout.fileno())
+ if ui._isatty(sys.stderr):
+ os.dup2(pager.stdin.fileno(), sys.stderr.fileno())
+
+ @atexit.register
+ def killpager():
+ pager.stdin.close()
+ os.dup2(stdout, sys.stdout.fileno())
+ os.dup2(stderr, sys.stderr.fileno())
+ pager.wait()
+
+def _runpager(ui, p):
+ # The subprocess module shipped with Python <= 2.4 is buggy (issue3533).
+ # The compat version is buggy on Windows (issue3225), but has been shipping
+ # with hg for a long time. Preserve existing functionality.
+ if sys.version_info >= (2, 5):
+ _pagersubprocess(ui, p)
+ else:
+ _pagerfork(ui, p)
+
+def uisetup(ui):
+ if '--debugger' in sys.argv or not ui.formatted():
+ return
+
+ def pagecmd(orig, ui, options, cmd, cmdfunc):
+ p = ui.config("pager", "pager", os.environ.get("PAGER"))
+
+ if p:
+ attend = ui.configlist('pager', 'attend', attended)
+ auto = options['pager'] == 'auto'
+ always = util.parsebool(options['pager'])
+ if (always or auto and
+ (cmd in attend or
+ (cmd not in ui.configlist('pager', 'ignore') and not attend))):
+ ui.setconfig('ui', 'formatted', ui.formatted())
+ ui.setconfig('ui', 'interactive', False)
+ if util.safehasattr(signal, "SIGPIPE"):
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+ _runpager(ui, p)
+ return orig(ui, options, cmd, cmdfunc)
+
+ extensions.wrapfunction(dispatch, '_runcommand', pagecmd)
+
+def extsetup(ui):
+ commands.globalopts.append(
+ ('', 'pager', 'auto',
+ _("when to paginate (boolean, always, auto, or never)"),
+ _('TYPE')))
+
+attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']