##// END OF EJS Templates
pager: move pager-initiating code into core...
Augie Fackler -
r30992:61b41220 default
parent child Browse files
Show More
@@ -60,19 +60,11 b' you can use --pager=<value>::'
60 '''
60 '''
61 from __future__ import absolute_import
61 from __future__ import absolute_import
62
62
63 import atexit
64 import os
65 import signal
66 import subprocess
67 import sys
68
69 from mercurial.i18n import _
63 from mercurial.i18n import _
70 from mercurial import (
64 from mercurial import (
71 cmdutil,
65 cmdutil,
72 commands,
66 commands,
73 dispatch,
67 dispatch,
74 encoding,
75 error,
76 extensions,
68 extensions,
77 util,
69 util,
78 )
70 )
@@ -83,48 +75,14 b' from mercurial import ('
83 # leave the attribute unspecified.
75 # leave the attribute unspecified.
84 testedwith = 'ships-with-hg-core'
76 testedwith = 'ships-with-hg-core'
85
77
86 def _runpager(ui, p):
87 pager = subprocess.Popen(p, shell=True, bufsize=-1,
88 close_fds=util.closefds, stdin=subprocess.PIPE,
89 stdout=util.stdout, stderr=util.stderr)
90
91 # back up original file descriptors
92 stdoutfd = os.dup(util.stdout.fileno())
93 stderrfd = os.dup(util.stderr.fileno())
94
95 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
96 if ui._isatty(util.stderr):
97 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
98
99 @atexit.register
100 def killpager():
101 if util.safehasattr(signal, "SIGINT"):
102 signal.signal(signal.SIGINT, signal.SIG_IGN)
103 # restore original fds, closing pager.stdin copies in the process
104 os.dup2(stdoutfd, util.stdout.fileno())
105 os.dup2(stderrfd, util.stderr.fileno())
106 pager.stdin.close()
107 pager.wait()
108
109 def catchterm(*args):
110 raise error.SignalInterrupt
111
112 def uisetup(ui):
78 def uisetup(ui):
113 class pagerui(ui.__class__):
114 def _runpager(self, pagercmd):
115 _runpager(self, pagercmd)
116
117 ui.__class__ = pagerui
118
79
119 def pagecmd(orig, ui, options, cmd, cmdfunc):
80 def pagecmd(orig, ui, options, cmd, cmdfunc):
120 p = ui.config("pager", "pager", encoding.environ.get("PAGER"))
121 usepager = False
81 usepager = False
122 always = util.parsebool(options['pager'])
82 always = util.parsebool(options['pager'])
123 auto = options['pager'] == 'auto'
83 auto = options['pager'] == 'auto'
124
84
125 if not p or '--debugger' in sys.argv or not ui.formatted():
85 if always:
126 pass
127 elif always:
128 usepager = True
86 usepager = True
129 elif not auto:
87 elif not auto:
130 usepager = False
88 usepager = False
@@ -143,14 +101,8 b' def uisetup(ui):'
143 usepager = True
101 usepager = True
144 break
102 break
145
103
146 setattr(ui, 'pageractive', usepager)
147
148 if usepager:
104 if usepager:
149 ui.setconfig('ui', 'formatted', ui.formatted(), 'pager')
105 ui.pager('extension-via-attend-' + cmd)
150 ui.setconfig('ui', 'interactive', False, 'pager')
151 if util.safehasattr(signal, "SIGPIPE"):
152 signal.signal(signal.SIGPIPE, catchterm)
153 ui._runpager(p)
154 return orig(ui, options, cmd, cmdfunc)
106 return orig(ui, options, cmd, cmdfunc)
155
107
156 # Wrap dispatch._runcommand after color is loaded so color can see
108 # Wrap dispatch._runcommand after color is loaded so color can see
@@ -7,6 +7,7 b''
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import atexit
10 import collections
11 import collections
11 import contextlib
12 import contextlib
12 import errno
13 import errno
@@ -14,7 +15,9 b' import getpass'
14 import inspect
15 import inspect
15 import os
16 import os
16 import re
17 import re
18 import signal
17 import socket
19 import socket
20 import subprocess
18 import sys
21 import sys
19 import tempfile
22 import tempfile
20 import traceback
23 import traceback
@@ -115,6 +118,8 b' class httppasswordmgrdbproxy(object):'
115 def find_user_password(self, *args, **kwargs):
118 def find_user_password(self, *args, **kwargs):
116 return self._get_mgr().find_user_password(*args, **kwargs)
119 return self._get_mgr().find_user_password(*args, **kwargs)
117
120
121 def _catchterm(*args):
122 raise error.SignalInterrupt
118
123
119 class ui(object):
124 class ui(object):
120 def __init__(self, src=None):
125 def __init__(self, src=None):
@@ -149,6 +154,7 b' class ui(object):'
149 self.fout = src.fout
154 self.fout = src.fout
150 self.ferr = src.ferr
155 self.ferr = src.ferr
151 self.fin = src.fin
156 self.fin = src.fin
157 self.pageractive = src.pageractive
152
158
153 self._tcfg = src._tcfg.copy()
159 self._tcfg = src._tcfg.copy()
154 self._ucfg = src._ucfg.copy()
160 self._ucfg = src._ucfg.copy()
@@ -166,6 +172,7 b' class ui(object):'
166 self.fout = util.stdout
172 self.fout = util.stdout
167 self.ferr = util.stderr
173 self.ferr = util.stderr
168 self.fin = util.stdin
174 self.fin = util.stdin
175 self.pageractive = False
169
176
170 # shared read-only environment
177 # shared read-only environment
171 self.environ = encoding.environ
178 self.environ = encoding.environ
@@ -824,6 +831,77 b' class ui(object):'
824 return False
831 return False
825 return util.isatty(fh)
832 return util.isatty(fh)
826
833
834 def pager(self, command):
835 """Start a pager for subsequent command output.
836
837 Commands which produce a long stream of output should call
838 this function to activate the user's preferred pagination
839 mechanism (which may be no pager). Calling this function
840 precludes any future use of interactive functionality, such as
841 prompting the user or activating curses.
842
843 Args:
844 command: The full, non-aliased name of the command. That is, "log"
845 not "history, "summary" not "summ", etc.
846 """
847 if (self.pageractive
848 # TODO: if we want to allow HGPLAINEXCEPT=pager,
849 # formatted() will need some adjustment.
850 or not self.formatted()
851 or self.plain()
852 # TODO: expose debugger-enabled on the UI object
853 or '--debugger' in sys.argv):
854 # We only want to paginate if the ui appears to be
855 # interactive, the user didn't say HGPLAIN or
856 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
857 return
858
859 # TODO: add a "system defaults" config section so this default
860 # of more(1) can be easily replaced with a global
861 # configuration file. For example, on OS X the sane default is
862 # less(1), not more(1), and on debian it's
863 # sensible-pager(1). We should probably also give the system
864 # default editor command similar treatment.
865 envpager = encoding.environ.get('PAGER', 'more')
866 pagercmd = self.config('pager', 'pager', envpager)
867 self.pageractive = True
868 # Preserve the formatted-ness of the UI. This is important
869 # because we mess with stdout, which might confuse
870 # auto-detection of things being formatted.
871 self.setconfig('ui', 'formatted', self.formatted(), 'pager')
872 self.setconfig('ui', 'interactive', False, 'pager')
873 if util.safehasattr(signal, "SIGPIPE"):
874 signal.signal(signal.SIGPIPE, _catchterm)
875 self._runpager(pagercmd)
876
877 def _runpager(self, command):
878 """Actually start the pager and set up file descriptors.
879
880 This is separate in part so that extensions (like chg) can
881 override how a pager is invoked.
882 """
883 pager = subprocess.Popen(command, shell=True, bufsize=-1,
884 close_fds=util.closefds, stdin=subprocess.PIPE,
885 stdout=util.stdout, stderr=util.stderr)
886
887 # back up original file descriptors
888 stdoutfd = os.dup(util.stdout.fileno())
889 stderrfd = os.dup(util.stderr.fileno())
890
891 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
892 if self._isatty(util.stderr):
893 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
894
895 @atexit.register
896 def killpager():
897 if util.safehasattr(signal, "SIGINT"):
898 signal.signal(signal.SIGINT, signal.SIG_IGN)
899 # restore original fds, closing pager.stdin copies in the process
900 os.dup2(stdoutfd, util.stdout.fileno())
901 os.dup2(stderrfd, util.stderr.fileno())
902 pager.stdin.close()
903 pager.wait()
904
827 def interface(self, feature):
905 def interface(self, feature):
828 """what interface to use for interactive console features?
906 """what interface to use for interactive console features?
829
907
General Comments 0
You need to be logged in to leave comments. Login now