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