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