diff options
Diffstat (limited to 'hgext/pager.py')
-rw-r--r-- | hgext/pager.py | 140 |
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'] |