##// END OF EJS Templates
pager: add attend-<command> option...
Matt Mackall -
r21281:bcddddcf default
parent child Browse files
Show More
@@ -1,156 +1,168 b''
1 # pager.py - display output using a pager
1 # pager.py - display output using a pager
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 #
7 #
8 # To load the extension, add it to your configuration file:
8 # To load the extension, add it to your configuration file:
9 #
9 #
10 # [extension]
10 # [extension]
11 # pager =
11 # pager =
12 #
12 #
13 # Run "hg help pager" to get info on configuration.
13 # Run "hg help pager" to get info on configuration.
14
14
15 '''browse command output with an external pager
15 '''browse command output with an external pager
16
16
17 To set the pager that should be used, set the application variable::
17 To set the pager that should be used, set the application variable::
18
18
19 [pager]
19 [pager]
20 pager = less -FRX
20 pager = less -FRX
21
21
22 If no pager is set, the pager extensions uses the environment variable
22 If no pager is set, the pager extensions uses the environment variable
23 $PAGER. If neither pager.pager, nor $PAGER is set, no pager is used.
23 $PAGER. If neither pager.pager, nor $PAGER is set, no pager is used.
24
24
25 You can disable the pager for certain commands by adding them to the
25 You can disable the pager for certain commands by adding them to the
26 pager.ignore list::
26 pager.ignore list::
27
27
28 [pager]
28 [pager]
29 ignore = version, help, update
29 ignore = version, help, update
30
30
31 You can also enable the pager only for certain commands using
31 You can also enable the pager only for certain commands using
32 pager.attend. Below is the default list of commands to be paged::
32 pager.attend. Below is the default list of commands to be paged::
33
33
34 [pager]
34 [pager]
35 attend = annotate, cat, diff, export, glog, log, qdiff
35 attend = annotate, cat, diff, export, glog, log, qdiff
36
36
37 Setting pager.attend to an empty value will cause all commands to be
37 Setting pager.attend to an empty value will cause all commands to be
38 paged.
38 paged.
39
39
40 If pager.attend is present, pager.ignore will be ignored.
40 If pager.attend is present, pager.ignore will be ignored.
41
41
42 Lastly, you can enable and disable paging for individual commands with
43 the attend-<command> option. This setting takes precedence over
44 existing attend and ignore options and defaults::
45
46 [pager]
47 attend-cat = false
48
42 To ignore global commands like :hg:`version` or :hg:`help`, you have
49 To ignore global commands like :hg:`version` or :hg:`help`, you have
43 to specify them in your user configuration file.
50 to specify them in your user configuration file.
44
51
45 The --pager=... option can also be used to control when the pager is
52 The --pager=... option can also be used to control when the pager is
46 used. Use a boolean value like yes, no, on, off, or use auto for
53 used. Use a boolean value like yes, no, on, off, or use auto for
47 normal behavior.
54 normal behavior.
55
48 '''
56 '''
49
57
50 import atexit, sys, os, signal, subprocess, errno, shlex
58 import atexit, sys, os, signal, subprocess, errno, shlex
51 from mercurial import commands, dispatch, util, extensions, cmdutil
59 from mercurial import commands, dispatch, util, extensions, cmdutil
52 from mercurial.i18n import _
60 from mercurial.i18n import _
53
61
54 testedwith = 'internal'
62 testedwith = 'internal'
55
63
56 def _pagerfork(ui, p):
64 def _pagerfork(ui, p):
57 if not util.safehasattr(os, 'fork'):
65 if not util.safehasattr(os, 'fork'):
58 sys.stdout = util.popen(p, 'wb')
66 sys.stdout = util.popen(p, 'wb')
59 if ui._isatty(sys.stderr):
67 if ui._isatty(sys.stderr):
60 sys.stderr = sys.stdout
68 sys.stderr = sys.stdout
61 return
69 return
62 fdin, fdout = os.pipe()
70 fdin, fdout = os.pipe()
63 pid = os.fork()
71 pid = os.fork()
64 if pid == 0:
72 if pid == 0:
65 os.close(fdin)
73 os.close(fdin)
66 os.dup2(fdout, sys.stdout.fileno())
74 os.dup2(fdout, sys.stdout.fileno())
67 if ui._isatty(sys.stderr):
75 if ui._isatty(sys.stderr):
68 os.dup2(fdout, sys.stderr.fileno())
76 os.dup2(fdout, sys.stderr.fileno())
69 os.close(fdout)
77 os.close(fdout)
70 return
78 return
71 os.dup2(fdin, sys.stdin.fileno())
79 os.dup2(fdin, sys.stdin.fileno())
72 os.close(fdin)
80 os.close(fdin)
73 os.close(fdout)
81 os.close(fdout)
74 try:
82 try:
75 os.execvp('/bin/sh', ['/bin/sh', '-c', p])
83 os.execvp('/bin/sh', ['/bin/sh', '-c', p])
76 except OSError, e:
84 except OSError, e:
77 if e.errno == errno.ENOENT:
85 if e.errno == errno.ENOENT:
78 # no /bin/sh, try executing the pager directly
86 # no /bin/sh, try executing the pager directly
79 args = shlex.split(p)
87 args = shlex.split(p)
80 os.execvp(args[0], args)
88 os.execvp(args[0], args)
81 else:
89 else:
82 raise
90 raise
83
91
84 def _pagersubprocess(ui, p):
92 def _pagersubprocess(ui, p):
85 pager = subprocess.Popen(p, shell=True, bufsize=-1,
93 pager = subprocess.Popen(p, shell=True, bufsize=-1,
86 close_fds=util.closefds, stdin=subprocess.PIPE,
94 close_fds=util.closefds, stdin=subprocess.PIPE,
87 stdout=sys.stdout, stderr=sys.stderr)
95 stdout=sys.stdout, stderr=sys.stderr)
88
96
89 stdout = os.dup(sys.stdout.fileno())
97 stdout = os.dup(sys.stdout.fileno())
90 stderr = os.dup(sys.stderr.fileno())
98 stderr = os.dup(sys.stderr.fileno())
91 os.dup2(pager.stdin.fileno(), sys.stdout.fileno())
99 os.dup2(pager.stdin.fileno(), sys.stdout.fileno())
92 if ui._isatty(sys.stderr):
100 if ui._isatty(sys.stderr):
93 os.dup2(pager.stdin.fileno(), sys.stderr.fileno())
101 os.dup2(pager.stdin.fileno(), sys.stderr.fileno())
94
102
95 @atexit.register
103 @atexit.register
96 def killpager():
104 def killpager():
97 if util.safehasattr(signal, "SIGINT"):
105 if util.safehasattr(signal, "SIGINT"):
98 signal.signal(signal.SIGINT, signal.SIG_IGN)
106 signal.signal(signal.SIGINT, signal.SIG_IGN)
99 pager.stdin.close()
107 pager.stdin.close()
100 os.dup2(stdout, sys.stdout.fileno())
108 os.dup2(stdout, sys.stdout.fileno())
101 os.dup2(stderr, sys.stderr.fileno())
109 os.dup2(stderr, sys.stderr.fileno())
102 pager.wait()
110 pager.wait()
103
111
104 def _runpager(ui, p):
112 def _runpager(ui, p):
105 # The subprocess module shipped with Python <= 2.4 is buggy (issue3533).
113 # The subprocess module shipped with Python <= 2.4 is buggy (issue3533).
106 # The compat version is buggy on Windows (issue3225), but has been shipping
114 # The compat version is buggy on Windows (issue3225), but has been shipping
107 # with hg for a long time. Preserve existing functionality.
115 # with hg for a long time. Preserve existing functionality.
108 if sys.version_info >= (2, 5):
116 if sys.version_info >= (2, 5):
109 _pagersubprocess(ui, p)
117 _pagersubprocess(ui, p)
110 else:
118 else:
111 _pagerfork(ui, p)
119 _pagerfork(ui, p)
112
120
113 def uisetup(ui):
121 def uisetup(ui):
114 if '--debugger' in sys.argv or not ui.formatted():
122 if '--debugger' in sys.argv or not ui.formatted():
115 return
123 return
116
124
117 def pagecmd(orig, ui, options, cmd, cmdfunc):
125 def pagecmd(orig, ui, options, cmd, cmdfunc):
118 p = ui.config("pager", "pager", os.environ.get("PAGER"))
126 p = ui.config("pager", "pager", os.environ.get("PAGER"))
119 usepager = False
127 usepager = False
120 always = util.parsebool(options['pager'])
128 always = util.parsebool(options['pager'])
121 auto = options['pager'] == 'auto'
129 auto = options['pager'] == 'auto'
122
130
123 if not p:
131 if not p:
124 pass
132 pass
125 elif always:
133 elif always:
126 usepager = True
134 usepager = True
127 elif not auto:
135 elif not auto:
128 usepager = False
136 usepager = False
129 else:
137 else:
130 attend = ui.configlist('pager', 'attend', attended)
138 attend = ui.configlist('pager', 'attend', attended)
131 ignore = ui.configlist('pager', 'ignore')
139 ignore = ui.configlist('pager', 'ignore')
132 cmds, _ = cmdutil.findcmd(cmd, commands.table)
140 cmds, _ = cmdutil.findcmd(cmd, commands.table)
133
141
134 for cmd in cmds:
142 for cmd in cmds:
143 var = 'attend-%s' % cmd
144 if ui.config('pager', var):
145 usepager = ui.configbool('pager', var)
146 break
135 if (cmd in attend or
147 if (cmd in attend or
136 (cmd not in ignore and not attend)):
148 (cmd not in ignore and not attend)):
137 usepager = True
149 usepager = True
138 break
150 break
139
151
140 if usepager:
152 if usepager:
141 ui.setconfig('ui', 'formatted', ui.formatted(), 'pager')
153 ui.setconfig('ui', 'formatted', ui.formatted(), 'pager')
142 ui.setconfig('ui', 'interactive', False, 'pager')
154 ui.setconfig('ui', 'interactive', False, 'pager')
143 if util.safehasattr(signal, "SIGPIPE"):
155 if util.safehasattr(signal, "SIGPIPE"):
144 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
156 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
145 _runpager(ui, p)
157 _runpager(ui, p)
146 return orig(ui, options, cmd, cmdfunc)
158 return orig(ui, options, cmd, cmdfunc)
147
159
148 extensions.wrapfunction(dispatch, '_runcommand', pagecmd)
160 extensions.wrapfunction(dispatch, '_runcommand', pagecmd)
149
161
150 def extsetup(ui):
162 def extsetup(ui):
151 commands.globalopts.append(
163 commands.globalopts.append(
152 ('', 'pager', 'auto',
164 ('', 'pager', 'auto',
153 _("when to paginate (boolean, always, auto, or never)"),
165 _("when to paginate (boolean, always, auto, or never)"),
154 _('TYPE')))
166 _('TYPE')))
155
167
156 attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']
168 attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']
General Comments 0
You need to be logged in to leave comments. Login now