##// END OF EJS Templates
Ensure pager interprets escape sequences...
Dmitry Zotikov -
Show More
@@ -1,381 +1,388 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Paging capabilities for IPython.core
3 Paging capabilities for IPython.core
4
4
5 Notes
5 Notes
6 -----
6 -----
7
7
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
9 rid of that dependency, we could move it there.
9 rid of that dependency, we could move it there.
10 -----
10 -----
11 """
11 """
12
12
13 # Copyright (c) IPython Development Team.
13 # Copyright (c) IPython Development Team.
14 # Distributed under the terms of the Modified BSD License.
14 # Distributed under the terms of the Modified BSD License.
15
15
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21 import tempfile
21 import tempfile
22
22
23 from io import UnsupportedOperation
23 from io import UnsupportedOperation
24
24
25 from IPython import get_ipython
25 from IPython import get_ipython
26 from IPython.core.display import display
26 from IPython.core.display import display
27 from IPython.core.error import TryNext
27 from IPython.core.error import TryNext
28 from IPython.utils.data import chop
28 from IPython.utils.data import chop
29 from IPython.utils import io
29 from IPython.utils import io
30 from IPython.utils.process import system
30 from IPython.utils.process import system
31 from IPython.utils.terminal import get_terminal_size
31 from IPython.utils.terminal import get_terminal_size
32 from IPython.utils import py3compat
32 from IPython.utils import py3compat
33
33
34
34
35 def display_page(strng, start=0, screen_lines=25):
35 def display_page(strng, start=0, screen_lines=25):
36 """Just display, no paging. screen_lines is ignored."""
36 """Just display, no paging. screen_lines is ignored."""
37 if isinstance(strng, dict):
37 if isinstance(strng, dict):
38 data = strng
38 data = strng
39 else:
39 else:
40 if start:
40 if start:
41 strng = u'\n'.join(strng.splitlines()[start:])
41 strng = u'\n'.join(strng.splitlines()[start:])
42 data = {'text/plain': strng}
42 data = {'text/plain': strng}
43 display(data, raw=True)
43 display(data, raw=True)
44
44
45
45
46 def as_hook(page_func):
46 def as_hook(page_func):
47 """Wrap a pager func to strip the `self` arg
47 """Wrap a pager func to strip the `self` arg
48
48
49 so it can be called as a hook.
49 so it can be called as a hook.
50 """
50 """
51 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
51 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
52
52
53
53
54 esc_re = re.compile(r"(\x1b[^m]+m)")
54 esc_re = re.compile(r"(\x1b[^m]+m)")
55
55
56 def page_dumb(strng, start=0, screen_lines=25):
56 def page_dumb(strng, start=0, screen_lines=25):
57 """Very dumb 'pager' in Python, for when nothing else works.
57 """Very dumb 'pager' in Python, for when nothing else works.
58
58
59 Only moves forward, same interface as page(), except for pager_cmd and
59 Only moves forward, same interface as page(), except for pager_cmd and
60 mode."""
60 mode."""
61
61
62 out_ln = strng.splitlines()[start:]
62 out_ln = strng.splitlines()[start:]
63 screens = chop(out_ln,screen_lines-1)
63 screens = chop(out_ln,screen_lines-1)
64 if len(screens) == 1:
64 if len(screens) == 1:
65 print(os.linesep.join(screens[0]), file=io.stdout)
65 print(os.linesep.join(screens[0]), file=io.stdout)
66 else:
66 else:
67 last_escape = ""
67 last_escape = ""
68 for scr in screens[0:-1]:
68 for scr in screens[0:-1]:
69 hunk = os.linesep.join(scr)
69 hunk = os.linesep.join(scr)
70 print(last_escape + hunk, file=io.stdout)
70 print(last_escape + hunk, file=io.stdout)
71 if not page_more():
71 if not page_more():
72 return
72 return
73 esc_list = esc_re.findall(hunk)
73 esc_list = esc_re.findall(hunk)
74 if len(esc_list) > 0:
74 if len(esc_list) > 0:
75 last_escape = esc_list[-1]
75 last_escape = esc_list[-1]
76 print(last_escape + os.linesep.join(screens[-1]), file=io.stdout)
76 print(last_escape + os.linesep.join(screens[-1]), file=io.stdout)
77
77
78 def _detect_screen_size(screen_lines_def):
78 def _detect_screen_size(screen_lines_def):
79 """Attempt to work out the number of lines on the screen.
79 """Attempt to work out the number of lines on the screen.
80
80
81 This is called by page(). It can raise an error (e.g. when run in the
81 This is called by page(). It can raise an error (e.g. when run in the
82 test suite), so it's separated out so it can easily be called in a try block.
82 test suite), so it's separated out so it can easily be called in a try block.
83 """
83 """
84 TERM = os.environ.get('TERM',None)
84 TERM = os.environ.get('TERM',None)
85 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
85 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
86 # curses causes problems on many terminals other than xterm, and
86 # curses causes problems on many terminals other than xterm, and
87 # some termios calls lock up on Sun OS5.
87 # some termios calls lock up on Sun OS5.
88 return screen_lines_def
88 return screen_lines_def
89
89
90 try:
90 try:
91 import termios
91 import termios
92 import curses
92 import curses
93 except ImportError:
93 except ImportError:
94 return screen_lines_def
94 return screen_lines_def
95
95
96 # There is a bug in curses, where *sometimes* it fails to properly
96 # There is a bug in curses, where *sometimes* it fails to properly
97 # initialize, and then after the endwin() call is made, the
97 # initialize, and then after the endwin() call is made, the
98 # terminal is left in an unusable state. Rather than trying to
98 # terminal is left in an unusable state. Rather than trying to
99 # check everytime for this (by requesting and comparing termios
99 # check everytime for this (by requesting and comparing termios
100 # flags each time), we just save the initial terminal state and
100 # flags each time), we just save the initial terminal state and
101 # unconditionally reset it every time. It's cheaper than making
101 # unconditionally reset it every time. It's cheaper than making
102 # the checks.
102 # the checks.
103 try:
103 try:
104 term_flags = termios.tcgetattr(sys.stdout)
104 term_flags = termios.tcgetattr(sys.stdout)
105 except termios.error as err:
105 except termios.error as err:
106 # can fail on Linux 2.6, pager_page will catch the TypeError
106 # can fail on Linux 2.6, pager_page will catch the TypeError
107 raise TypeError('termios error: {0}'.format(err))
107 raise TypeError('termios error: {0}'.format(err))
108
108
109 # Curses modifies the stdout buffer size by default, which messes
109 # Curses modifies the stdout buffer size by default, which messes
110 # up Python's normal stdout buffering. This would manifest itself
110 # up Python's normal stdout buffering. This would manifest itself
111 # to IPython users as delayed printing on stdout after having used
111 # to IPython users as delayed printing on stdout after having used
112 # the pager.
112 # the pager.
113 #
113 #
114 # We can prevent this by manually setting the NCURSES_NO_SETBUF
114 # We can prevent this by manually setting the NCURSES_NO_SETBUF
115 # environment variable. For more details, see:
115 # environment variable. For more details, see:
116 # http://bugs.python.org/issue10144
116 # http://bugs.python.org/issue10144
117 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
117 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
118 os.environ['NCURSES_NO_SETBUF'] = ''
118 os.environ['NCURSES_NO_SETBUF'] = ''
119
119
120 # Proceed with curses initialization
120 # Proceed with curses initialization
121 try:
121 try:
122 scr = curses.initscr()
122 scr = curses.initscr()
123 except AttributeError:
123 except AttributeError:
124 # Curses on Solaris may not be complete, so we can't use it there
124 # Curses on Solaris may not be complete, so we can't use it there
125 return screen_lines_def
125 return screen_lines_def
126
126
127 screen_lines_real,screen_cols = scr.getmaxyx()
127 screen_lines_real,screen_cols = scr.getmaxyx()
128 curses.endwin()
128 curses.endwin()
129
129
130 # Restore environment
130 # Restore environment
131 if NCURSES_NO_SETBUF is None:
131 if NCURSES_NO_SETBUF is None:
132 del os.environ['NCURSES_NO_SETBUF']
132 del os.environ['NCURSES_NO_SETBUF']
133 else:
133 else:
134 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
134 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
135
135
136 # Restore terminal state in case endwin() didn't.
136 # Restore terminal state in case endwin() didn't.
137 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
137 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
138 # Now we have what we needed: the screen size in rows/columns
138 # Now we have what we needed: the screen size in rows/columns
139 return screen_lines_real
139 return screen_lines_real
140 #print '***Screen size:',screen_lines_real,'lines x',\
140 #print '***Screen size:',screen_lines_real,'lines x',\
141 #screen_cols,'columns.' # dbg
141 #screen_cols,'columns.' # dbg
142
142
143 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
143 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
144 """Display a string, piping through a pager after a certain length.
144 """Display a string, piping through a pager after a certain length.
145
145
146 strng can be a mime-bundle dict, supplying multiple representations,
146 strng can be a mime-bundle dict, supplying multiple representations,
147 keyed by mime-type.
147 keyed by mime-type.
148
148
149 The screen_lines parameter specifies the number of *usable* lines of your
149 The screen_lines parameter specifies the number of *usable* lines of your
150 terminal screen (total lines minus lines you need to reserve to show other
150 terminal screen (total lines minus lines you need to reserve to show other
151 information).
151 information).
152
152
153 If you set screen_lines to a number <=0, page() will try to auto-determine
153 If you set screen_lines to a number <=0, page() will try to auto-determine
154 your screen size and will only use up to (screen_size+screen_lines) for
154 your screen size and will only use up to (screen_size+screen_lines) for
155 printing, paging after that. That is, if you want auto-detection but need
155 printing, paging after that. That is, if you want auto-detection but need
156 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
156 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
157 auto-detection without any lines reserved simply use screen_lines = 0.
157 auto-detection without any lines reserved simply use screen_lines = 0.
158
158
159 If a string won't fit in the allowed lines, it is sent through the
159 If a string won't fit in the allowed lines, it is sent through the
160 specified pager command. If none given, look for PAGER in the environment,
160 specified pager command. If none given, look for PAGER in the environment,
161 and ultimately default to less.
161 and ultimately default to less.
162
162
163 If no system pager works, the string is sent through a 'dumb pager'
163 If no system pager works, the string is sent through a 'dumb pager'
164 written in python, very simplistic.
164 written in python, very simplistic.
165 """
165 """
166
166
167 # for compatibility with mime-bundle form:
167 # for compatibility with mime-bundle form:
168 if isinstance(strng, dict):
168 if isinstance(strng, dict):
169 strng = strng['text/plain']
169 strng = strng['text/plain']
170
170
171 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
171 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
172 TERM = os.environ.get('TERM','dumb')
172 TERM = os.environ.get('TERM','dumb')
173 if TERM in ['dumb','emacs'] and os.name != 'nt':
173 if TERM in ['dumb','emacs'] and os.name != 'nt':
174 print(strng)
174 print(strng)
175 return
175 return
176 # chop off the topmost part of the string we don't want to see
176 # chop off the topmost part of the string we don't want to see
177 str_lines = strng.splitlines()[start:]
177 str_lines = strng.splitlines()[start:]
178 str_toprint = os.linesep.join(str_lines)
178 str_toprint = os.linesep.join(str_lines)
179 num_newlines = len(str_lines)
179 num_newlines = len(str_lines)
180 len_str = len(str_toprint)
180 len_str = len(str_toprint)
181
181
182 # Dumb heuristics to guesstimate number of on-screen lines the string
182 # Dumb heuristics to guesstimate number of on-screen lines the string
183 # takes. Very basic, but good enough for docstrings in reasonable
183 # takes. Very basic, but good enough for docstrings in reasonable
184 # terminals. If someone later feels like refining it, it's not hard.
184 # terminals. If someone later feels like refining it, it's not hard.
185 numlines = max(num_newlines,int(len_str/80)+1)
185 numlines = max(num_newlines,int(len_str/80)+1)
186
186
187 screen_lines_def = get_terminal_size()[1]
187 screen_lines_def = get_terminal_size()[1]
188
188
189 # auto-determine screen size
189 # auto-determine screen size
190 if screen_lines <= 0:
190 if screen_lines <= 0:
191 try:
191 try:
192 screen_lines += _detect_screen_size(screen_lines_def)
192 screen_lines += _detect_screen_size(screen_lines_def)
193 except (TypeError, UnsupportedOperation):
193 except (TypeError, UnsupportedOperation):
194 print(str_toprint, file=io.stdout)
194 print(str_toprint, file=io.stdout)
195 return
195 return
196
196
197 #print 'numlines',numlines,'screenlines',screen_lines # dbg
197 #print 'numlines',numlines,'screenlines',screen_lines # dbg
198 if numlines <= screen_lines :
198 if numlines <= screen_lines :
199 #print '*** normal print' # dbg
199 #print '*** normal print' # dbg
200 print(str_toprint, file=io.stdout)
200 print(str_toprint, file=io.stdout)
201 else:
201 else:
202 # Try to open pager and default to internal one if that fails.
202 # Try to open pager and default to internal one if that fails.
203 # All failure modes are tagged as 'retval=1', to match the return
203 # All failure modes are tagged as 'retval=1', to match the return
204 # value of a failed system command. If any intermediate attempt
204 # value of a failed system command. If any intermediate attempt
205 # sets retval to 1, at the end we resort to our own page_dumb() pager.
205 # sets retval to 1, at the end we resort to our own page_dumb() pager.
206 pager_cmd = get_pager_cmd(pager_cmd)
206 pager_cmd = get_pager_cmd(pager_cmd)
207 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
207 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
208 if os.name == 'nt':
208 if os.name == 'nt':
209 if pager_cmd.startswith('type'):
209 if pager_cmd.startswith('type'):
210 # The default WinXP 'type' command is failing on complex strings.
210 # The default WinXP 'type' command is failing on complex strings.
211 retval = 1
211 retval = 1
212 else:
212 else:
213 fd, tmpname = tempfile.mkstemp('.txt')
213 fd, tmpname = tempfile.mkstemp('.txt')
214 try:
214 try:
215 os.close(fd)
215 os.close(fd)
216 with open(tmpname, 'wt') as tmpfile:
216 with open(tmpname, 'wt') as tmpfile:
217 tmpfile.write(strng)
217 tmpfile.write(strng)
218 cmd = "%s < %s" % (pager_cmd, tmpname)
218 cmd = "%s < %s" % (pager_cmd, tmpname)
219 # tmpfile needs to be closed for windows
219 # tmpfile needs to be closed for windows
220 if os.system(cmd):
220 if os.system(cmd):
221 retval = 1
221 retval = 1
222 else:
222 else:
223 retval = None
223 retval = None
224 finally:
224 finally:
225 os.remove(tmpname)
225 os.remove(tmpname)
226 else:
226 else:
227 try:
227 try:
228 retval = None
228 retval = None
229 # if I use popen4, things hang. No idea why.
229 # if I use popen4, things hang. No idea why.
230 #pager,shell_out = os.popen4(pager_cmd)
230 #pager,shell_out = os.popen4(pager_cmd)
231 pager = os.popen(pager_cmd, 'w')
231 pager = os.popen(pager_cmd, 'w')
232 try:
232 try:
233 pager_encoding = pager.encoding or sys.stdout.encoding
233 pager_encoding = pager.encoding or sys.stdout.encoding
234 pager.write(py3compat.cast_bytes_py2(
234 pager.write(py3compat.cast_bytes_py2(
235 strng, encoding=pager_encoding))
235 strng, encoding=pager_encoding))
236 finally:
236 finally:
237 retval = pager.close()
237 retval = pager.close()
238 except IOError as msg: # broken pipe when user quits
238 except IOError as msg: # broken pipe when user quits
239 if msg.args == (32, 'Broken pipe'):
239 if msg.args == (32, 'Broken pipe'):
240 retval = None
240 retval = None
241 else:
241 else:
242 retval = 1
242 retval = 1
243 except OSError:
243 except OSError:
244 # Other strange problems, sometimes seen in Win2k/cygwin
244 # Other strange problems, sometimes seen in Win2k/cygwin
245 retval = 1
245 retval = 1
246 if retval is not None:
246 if retval is not None:
247 page_dumb(strng,screen_lines=screen_lines)
247 page_dumb(strng,screen_lines=screen_lines)
248
248
249
249
250 def page(data, start=0, screen_lines=0, pager_cmd=None):
250 def page(data, start=0, screen_lines=0, pager_cmd=None):
251 """Display content in a pager, piping through a pager after a certain length.
251 """Display content in a pager, piping through a pager after a certain length.
252
252
253 data can be a mime-bundle dict, supplying multiple representations,
253 data can be a mime-bundle dict, supplying multiple representations,
254 keyed by mime-type, or text.
254 keyed by mime-type, or text.
255
255
256 Pager is dispatched via the `show_in_pager` IPython hook.
256 Pager is dispatched via the `show_in_pager` IPython hook.
257 If no hook is registered, `pager_page` will be used.
257 If no hook is registered, `pager_page` will be used.
258 """
258 """
259 # Some routines may auto-compute start offsets incorrectly and pass a
259 # Some routines may auto-compute start offsets incorrectly and pass a
260 # negative value. Offset to 0 for robustness.
260 # negative value. Offset to 0 for robustness.
261 start = max(0, start)
261 start = max(0, start)
262
262
263 # first, try the hook
263 # first, try the hook
264 ip = get_ipython()
264 ip = get_ipython()
265 if ip:
265 if ip:
266 try:
266 try:
267 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
267 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
268 return
268 return
269 except TryNext:
269 except TryNext:
270 pass
270 pass
271
271
272 # fallback on default pager
272 # fallback on default pager
273 return pager_page(data, start, screen_lines, pager_cmd)
273 return pager_page(data, start, screen_lines, pager_cmd)
274
274
275
275
276 def page_file(fname, start=0, pager_cmd=None):
276 def page_file(fname, start=0, pager_cmd=None):
277 """Page a file, using an optional pager command and starting line.
277 """Page a file, using an optional pager command and starting line.
278 """
278 """
279
279
280 pager_cmd = get_pager_cmd(pager_cmd)
280 pager_cmd = get_pager_cmd(pager_cmd)
281 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
281 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
282
282
283 try:
283 try:
284 if os.environ['TERM'] in ['emacs','dumb']:
284 if os.environ['TERM'] in ['emacs','dumb']:
285 raise EnvironmentError
285 raise EnvironmentError
286 system(pager_cmd + ' ' + fname)
286 system(pager_cmd + ' ' + fname)
287 except:
287 except:
288 try:
288 try:
289 if start > 0:
289 if start > 0:
290 start -= 1
290 start -= 1
291 page(open(fname).read(),start)
291 page(open(fname).read(),start)
292 except:
292 except:
293 print('Unable to show file',repr(fname))
293 print('Unable to show file',repr(fname))
294
294
295
295
296 def get_pager_cmd(pager_cmd=None):
296 def get_pager_cmd(pager_cmd=None):
297 """Return a pager command.
297 """Return a pager command.
298
298
299 Makes some attempts at finding an OS-correct one.
299 Makes some attempts at finding an OS-correct one.
300 """
300 """
301 if os.name == 'posix':
301 if os.name == 'posix':
302 default_pager_cmd = 'less -r' # -r for color control sequences
302 default_pager_cmd = 'less -r' # -r for color control sequences
303 elif os.name in ['nt','dos']:
303 elif os.name in ['nt','dos']:
304 default_pager_cmd = 'type'
304 default_pager_cmd = 'type'
305
305
306 if pager_cmd is None:
306 if pager_cmd is None:
307 try:
307 try:
308 pager_cmd = os.environ['PAGER']
308 pager_cmd = os.environ['PAGER']
309 except:
309 except:
310 pager_cmd = default_pager_cmd
310 pager_cmd = default_pager_cmd
311
312 if pager_cmd == 'less':
313 try:
314 os.getenv('LESS').index('-r')
315 except (ValueError, AttributeError):
316 pager_cmd += ' -r'
317
311 return pager_cmd
318 return pager_cmd
312
319
313
320
314 def get_pager_start(pager, start):
321 def get_pager_start(pager, start):
315 """Return the string for paging files with an offset.
322 """Return the string for paging files with an offset.
316
323
317 This is the '+N' argument which less and more (under Unix) accept.
324 This is the '+N' argument which less and more (under Unix) accept.
318 """
325 """
319
326
320 if pager in ['less','more']:
327 if pager in ['less','more']:
321 if start:
328 if start:
322 start_string = '+' + str(start)
329 start_string = '+' + str(start)
323 else:
330 else:
324 start_string = ''
331 start_string = ''
325 else:
332 else:
326 start_string = ''
333 start_string = ''
327 return start_string
334 return start_string
328
335
329
336
330 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
337 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
331 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
338 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
332 import msvcrt
339 import msvcrt
333 def page_more():
340 def page_more():
334 """ Smart pausing between pages
341 """ Smart pausing between pages
335
342
336 @return: True if need print more lines, False if quit
343 @return: True if need print more lines, False if quit
337 """
344 """
338 io.stdout.write('---Return to continue, q to quit--- ')
345 io.stdout.write('---Return to continue, q to quit--- ')
339 ans = msvcrt.getwch()
346 ans = msvcrt.getwch()
340 if ans in ("q", "Q"):
347 if ans in ("q", "Q"):
341 result = False
348 result = False
342 else:
349 else:
343 result = True
350 result = True
344 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
351 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
345 return result
352 return result
346 else:
353 else:
347 def page_more():
354 def page_more():
348 ans = py3compat.input('---Return to continue, q to quit--- ')
355 ans = py3compat.input('---Return to continue, q to quit--- ')
349 if ans.lower().startswith('q'):
356 if ans.lower().startswith('q'):
350 return False
357 return False
351 else:
358 else:
352 return True
359 return True
353
360
354
361
355 def snip_print(str,width = 75,print_full = 0,header = ''):
362 def snip_print(str,width = 75,print_full = 0,header = ''):
356 """Print a string snipping the midsection to fit in width.
363 """Print a string snipping the midsection to fit in width.
357
364
358 print_full: mode control:
365 print_full: mode control:
359
366
360 - 0: only snip long strings
367 - 0: only snip long strings
361 - 1: send to page() directly.
368 - 1: send to page() directly.
362 - 2: snip long strings and ask for full length viewing with page()
369 - 2: snip long strings and ask for full length viewing with page()
363
370
364 Return 1 if snipping was necessary, 0 otherwise."""
371 Return 1 if snipping was necessary, 0 otherwise."""
365
372
366 if print_full == 1:
373 if print_full == 1:
367 page(header+str)
374 page(header+str)
368 return 0
375 return 0
369
376
370 print(header, end=' ')
377 print(header, end=' ')
371 if len(str) < width:
378 if len(str) < width:
372 print(str)
379 print(str)
373 snip = 0
380 snip = 0
374 else:
381 else:
375 whalf = int((width -5)/2)
382 whalf = int((width -5)/2)
376 print(str[:whalf] + ' <...> ' + str[-whalf:])
383 print(str[:whalf] + ' <...> ' + str[-whalf:])
377 snip = 1
384 snip = 1
378 if snip and print_full == 2:
385 if snip and print_full == 2:
379 if py3compat.input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
386 if py3compat.input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
380 page(str)
387 page(str)
381 return snip
388 return snip
General Comments 0
You need to be logged in to leave comments. Login now