##// END OF EJS Templates
make hlen_before_cell a function argument instead of class member
Julian Taylor -
Show More
@@ -1,616 +1,625 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Subclass of InteractiveShell for terminal based frontends."""
2 """Subclass of InteractiveShell for terminal based frontends."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2010 The IPython Development Team
7 # Copyright (C) 2008-2010 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import __builtin__
17 import __builtin__
18 import bdb
18 import bdb
19 import os
19 import os
20 import re
20 import re
21 import sys
21 import sys
22
22
23 try:
23 try:
24 from contextlib import nested
24 from contextlib import nested
25 except:
25 except:
26 from IPython.utils.nested_context import nested
26 from IPython.utils.nested_context import nested
27
27
28 from IPython.core.error import TryNext
28 from IPython.core.error import TryNext
29 from IPython.core.usage import interactive_usage, default_banner
29 from IPython.core.usage import interactive_usage, default_banner
30 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
30 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
31 from IPython.lib.inputhook import enable_gui
31 from IPython.lib.inputhook import enable_gui
32 from IPython.lib.pylabtools import pylab_activate
32 from IPython.lib.pylabtools import pylab_activate
33 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.testing.skipdoctest import skip_doctest
34 from IPython.utils import py3compat
34 from IPython.utils import py3compat
35 from IPython.utils.terminal import toggle_set_term_title, set_term_title
35 from IPython.utils.terminal import toggle_set_term_title, set_term_title
36 from IPython.utils.process import abbrev_cwd
36 from IPython.utils.process import abbrev_cwd
37 from IPython.utils.warn import warn
37 from IPython.utils.warn import warn
38 from IPython.utils.text import num_ini_spaces
38 from IPython.utils.text import num_ini_spaces
39 from IPython.utils.traitlets import Int, CBool, Unicode
39 from IPython.utils.traitlets import Int, CBool, Unicode
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Utilities
42 # Utilities
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45 def get_default_editor():
45 def get_default_editor():
46 try:
46 try:
47 ed = os.environ['EDITOR']
47 ed = os.environ['EDITOR']
48 except KeyError:
48 except KeyError:
49 if os.name == 'posix':
49 if os.name == 'posix':
50 ed = 'vi' # the only one guaranteed to be there!
50 ed = 'vi' # the only one guaranteed to be there!
51 else:
51 else:
52 ed = 'notepad' # same in Windows!
52 ed = 'notepad' # same in Windows!
53 return ed
53 return ed
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Main class
56 # Main class
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 class TerminalInteractiveShell(InteractiveShell):
59 class TerminalInteractiveShell(InteractiveShell):
60
60
61 autoedit_syntax = CBool(False, config=True,
61 autoedit_syntax = CBool(False, config=True,
62 help="auto editing of files with syntax errors.")
62 help="auto editing of files with syntax errors.")
63 banner = Unicode('')
63 banner = Unicode('')
64 banner1 = Unicode(default_banner, config=True,
64 banner1 = Unicode(default_banner, config=True,
65 help="""The part of the banner to be printed before the profile"""
65 help="""The part of the banner to be printed before the profile"""
66 )
66 )
67 banner2 = Unicode('', config=True,
67 banner2 = Unicode('', config=True,
68 help="""The part of the banner to be printed after the profile"""
68 help="""The part of the banner to be printed after the profile"""
69 )
69 )
70 confirm_exit = CBool(True, config=True,
70 confirm_exit = CBool(True, config=True,
71 help="""
71 help="""
72 Set to confirm when you try to exit IPython with an EOF (Control-D
72 Set to confirm when you try to exit IPython with an EOF (Control-D
73 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
73 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
74 you can force a direct exit without any confirmation.""",
74 you can force a direct exit without any confirmation.""",
75 )
75 )
76 # This display_banner only controls whether or not self.show_banner()
76 # This display_banner only controls whether or not self.show_banner()
77 # is called when mainloop/interact are called. The default is False
77 # is called when mainloop/interact are called. The default is False
78 # because for the terminal based application, the banner behavior
78 # because for the terminal based application, the banner behavior
79 # is controlled by Global.display_banner, which IPythonApp looks at
79 # is controlled by Global.display_banner, which IPythonApp looks at
80 # to determine if *it* should call show_banner() by hand or not.
80 # to determine if *it* should call show_banner() by hand or not.
81 display_banner = CBool(False) # This isn't configurable!
81 display_banner = CBool(False) # This isn't configurable!
82 embedded = CBool(False)
82 embedded = CBool(False)
83 embedded_active = CBool(False)
83 embedded_active = CBool(False)
84 editor = Unicode(get_default_editor(), config=True,
84 editor = Unicode(get_default_editor(), config=True,
85 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
85 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
86 )
86 )
87 pager = Unicode('less', config=True,
87 pager = Unicode('less', config=True,
88 help="The shell program to be used for paging.")
88 help="The shell program to be used for paging.")
89
89
90 screen_length = Int(0, config=True,
90 screen_length = Int(0, config=True,
91 help=
91 help=
92 """Number of lines of your screen, used to control printing of very
92 """Number of lines of your screen, used to control printing of very
93 long strings. Strings longer than this number of lines will be sent
93 long strings. Strings longer than this number of lines will be sent
94 through a pager instead of directly printed. The default value for
94 through a pager instead of directly printed. The default value for
95 this is 0, which means IPython will auto-detect your screen size every
95 this is 0, which means IPython will auto-detect your screen size every
96 time it needs to print certain potentially long strings (this doesn't
96 time it needs to print certain potentially long strings (this doesn't
97 change the behavior of the 'print' keyword, it's only triggered
97 change the behavior of the 'print' keyword, it's only triggered
98 internally). If for some reason this isn't working well (it needs
98 internally). If for some reason this isn't working well (it needs
99 curses support), specify it yourself. Otherwise don't change the
99 curses support), specify it yourself. Otherwise don't change the
100 default.""",
100 default.""",
101 )
101 )
102 term_title = CBool(False, config=True,
102 term_title = CBool(False, config=True,
103 help="Enable auto setting the terminal title."
103 help="Enable auto setting the terminal title."
104 )
104 )
105
105
106 def __init__(self, config=None, ipython_dir=None, profile_dir=None, user_ns=None,
106 def __init__(self, config=None, ipython_dir=None, profile_dir=None, user_ns=None,
107 user_global_ns=None, custom_exceptions=((),None),
107 user_global_ns=None, custom_exceptions=((),None),
108 usage=None, banner1=None, banner2=None,
108 usage=None, banner1=None, banner2=None,
109 display_banner=None):
109 display_banner=None):
110
110
111 super(TerminalInteractiveShell, self).__init__(
111 super(TerminalInteractiveShell, self).__init__(
112 config=config, profile_dir=profile_dir, user_ns=user_ns,
112 config=config, profile_dir=profile_dir, user_ns=user_ns,
113 user_global_ns=user_global_ns, custom_exceptions=custom_exceptions
113 user_global_ns=user_global_ns, custom_exceptions=custom_exceptions
114 )
114 )
115 # use os.system instead of utils.process.system by default, except on Windows
115 # use os.system instead of utils.process.system by default, except on Windows
116 if os.name == 'nt':
116 if os.name == 'nt':
117 self.system = self.system_piped
117 self.system = self.system_piped
118 else:
118 else:
119 self.system = self.system_raw
119 self.system = self.system_raw
120
120
121 self.init_term_title()
121 self.init_term_title()
122 self.init_usage(usage)
122 self.init_usage(usage)
123 self.init_banner(banner1, banner2, display_banner)
123 self.init_banner(banner1, banner2, display_banner)
124
124
125 #-------------------------------------------------------------------------
125 #-------------------------------------------------------------------------
126 # Things related to the terminal
126 # Things related to the terminal
127 #-------------------------------------------------------------------------
127 #-------------------------------------------------------------------------
128
128
129 @property
129 @property
130 def usable_screen_length(self):
130 def usable_screen_length(self):
131 if self.screen_length == 0:
131 if self.screen_length == 0:
132 return 0
132 return 0
133 else:
133 else:
134 num_lines_bot = self.separate_in.count('\n')+1
134 num_lines_bot = self.separate_in.count('\n')+1
135 return self.screen_length - num_lines_bot
135 return self.screen_length - num_lines_bot
136
136
137 def init_term_title(self):
137 def init_term_title(self):
138 # Enable or disable the terminal title.
138 # Enable or disable the terminal title.
139 if self.term_title:
139 if self.term_title:
140 toggle_set_term_title(True)
140 toggle_set_term_title(True)
141 set_term_title('IPython: ' + abbrev_cwd())
141 set_term_title('IPython: ' + abbrev_cwd())
142 else:
142 else:
143 toggle_set_term_title(False)
143 toggle_set_term_title(False)
144
144
145 #-------------------------------------------------------------------------
145 #-------------------------------------------------------------------------
146 # Things related to aliases
146 # Things related to aliases
147 #-------------------------------------------------------------------------
147 #-------------------------------------------------------------------------
148
148
149 def init_alias(self):
149 def init_alias(self):
150 # The parent class defines aliases that can be safely used with any
150 # The parent class defines aliases that can be safely used with any
151 # frontend.
151 # frontend.
152 super(TerminalInteractiveShell, self).init_alias()
152 super(TerminalInteractiveShell, self).init_alias()
153
153
154 # Now define aliases that only make sense on the terminal, because they
154 # Now define aliases that only make sense on the terminal, because they
155 # need direct access to the console in a way that we can't emulate in
155 # need direct access to the console in a way that we can't emulate in
156 # GUI or web frontend
156 # GUI or web frontend
157 if os.name == 'posix':
157 if os.name == 'posix':
158 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
158 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
159 ('man', 'man')]
159 ('man', 'man')]
160 elif os.name == 'nt':
160 elif os.name == 'nt':
161 aliases = [('cls', 'cls')]
161 aliases = [('cls', 'cls')]
162
162
163
163
164 for name, cmd in aliases:
164 for name, cmd in aliases:
165 self.alias_manager.define_alias(name, cmd)
165 self.alias_manager.define_alias(name, cmd)
166
166
167 #-------------------------------------------------------------------------
167 #-------------------------------------------------------------------------
168 # Things related to the banner and usage
168 # Things related to the banner and usage
169 #-------------------------------------------------------------------------
169 #-------------------------------------------------------------------------
170
170
171 def _banner1_changed(self):
171 def _banner1_changed(self):
172 self.compute_banner()
172 self.compute_banner()
173
173
174 def _banner2_changed(self):
174 def _banner2_changed(self):
175 self.compute_banner()
175 self.compute_banner()
176
176
177 def _term_title_changed(self, name, new_value):
177 def _term_title_changed(self, name, new_value):
178 self.init_term_title()
178 self.init_term_title()
179
179
180 def init_banner(self, banner1, banner2, display_banner):
180 def init_banner(self, banner1, banner2, display_banner):
181 if banner1 is not None:
181 if banner1 is not None:
182 self.banner1 = banner1
182 self.banner1 = banner1
183 if banner2 is not None:
183 if banner2 is not None:
184 self.banner2 = banner2
184 self.banner2 = banner2
185 if display_banner is not None:
185 if display_banner is not None:
186 self.display_banner = display_banner
186 self.display_banner = display_banner
187 self.compute_banner()
187 self.compute_banner()
188
188
189 def show_banner(self, banner=None):
189 def show_banner(self, banner=None):
190 if banner is None:
190 if banner is None:
191 banner = self.banner
191 banner = self.banner
192 self.write(banner)
192 self.write(banner)
193
193
194 def compute_banner(self):
194 def compute_banner(self):
195 self.banner = self.banner1
195 self.banner = self.banner1
196 if self.profile and self.profile != 'default':
196 if self.profile and self.profile != 'default':
197 self.banner += '\nIPython profile: %s\n' % self.profile
197 self.banner += '\nIPython profile: %s\n' % self.profile
198 if self.banner2:
198 if self.banner2:
199 self.banner += '\n' + self.banner2
199 self.banner += '\n' + self.banner2
200
200
201 def init_usage(self, usage=None):
201 def init_usage(self, usage=None):
202 if usage is None:
202 if usage is None:
203 self.usage = interactive_usage
203 self.usage = interactive_usage
204 else:
204 else:
205 self.usage = usage
205 self.usage = usage
206
206
207 #-------------------------------------------------------------------------
207 #-------------------------------------------------------------------------
208 # Mainloop and code execution logic
208 # Mainloop and code execution logic
209 #-------------------------------------------------------------------------
209 #-------------------------------------------------------------------------
210
210
211 def mainloop(self, display_banner=None):
211 def mainloop(self, display_banner=None):
212 """Start the mainloop.
212 """Start the mainloop.
213
213
214 If an optional banner argument is given, it will override the
214 If an optional banner argument is given, it will override the
215 internally created default banner.
215 internally created default banner.
216 """
216 """
217
217
218 with nested(self.builtin_trap, self.display_trap):
218 with nested(self.builtin_trap, self.display_trap):
219
219
220 while 1:
220 while 1:
221 try:
221 try:
222 self.interact(display_banner=display_banner)
222 self.interact(display_banner=display_banner)
223 #self.interact_with_readline()
223 #self.interact_with_readline()
224 # XXX for testing of a readline-decoupled repl loop, call
224 # XXX for testing of a readline-decoupled repl loop, call
225 # interact_with_readline above
225 # interact_with_readline above
226 break
226 break
227 except KeyboardInterrupt:
227 except KeyboardInterrupt:
228 # this should not be necessary, but KeyboardInterrupt
228 # this should not be necessary, but KeyboardInterrupt
229 # handling seems rather unpredictable...
229 # handling seems rather unpredictable...
230 self.write("\nKeyboardInterrupt in interact()\n")
230 self.write("\nKeyboardInterrupt in interact()\n")
231
231
232 def _replace_rlhist_multiline(self, source_raw):
232 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
233 """Store multiple lines as a single entry in history"""
233 """Store multiple lines as a single entry in history"""
234 if self.multiline_history and self.has_readline and source_raw.rstrip():
235 hlen = self.readline.get_current_history_length()
236
234
237 # nothing changed do nothing, e.g. when rl removes consecutive dups
235 # do nothing without readline or disabled multiline
238 if self.hlen_before_cell == hlen:
236 if not self.has_readline or not self.multiline_history:
239 return
237 return hlen_before_cell
238
239 # skip empty cells
240 if not source_raw.rstrip():
241 return hlen_before_cell
242
243 # nothing changed do nothing, e.g. when rl removes consecutive dups
244 hlen = self.readline.get_current_history_length()
245 if hlen == hlen_before_cell:
246 return hlen_before_cell
240
247
241 for i in range(hlen - self.hlen_before_cell):
248 for i in range(hlen - hlen_before_cell):
242 self.readline.remove_history_item(hlen - i - 1)
249 self.readline.remove_history_item(hlen - i - 1)
243 stdin_encoding = sys.stdin.encoding or "utf-8"
250 stdin_encoding = sys.stdin.encoding or "utf-8"
244 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
251 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
245 stdin_encoding))
252 stdin_encoding))
246 self.hlen_before_cell = self.readline.get_current_history_length()
253 return self.readline.get_current_history_length()
247
254
248 def interact(self, display_banner=None):
255 def interact(self, display_banner=None):
249 """Closely emulate the interactive Python console."""
256 """Closely emulate the interactive Python console."""
250
257
251 # batch run -> do not interact
258 # batch run -> do not interact
252 if self.exit_now:
259 if self.exit_now:
253 return
260 return
254
261
255 if display_banner is None:
262 if display_banner is None:
256 display_banner = self.display_banner
263 display_banner = self.display_banner
257
264
258 if isinstance(display_banner, basestring):
265 if isinstance(display_banner, basestring):
259 self.show_banner(display_banner)
266 self.show_banner(display_banner)
260 elif display_banner:
267 elif display_banner:
261 self.show_banner()
268 self.show_banner()
262
269
263 more = False
270 more = False
264
271
265 # Mark activity in the builtins
272 # Mark activity in the builtins
266 __builtin__.__dict__['__IPYTHON__active'] += 1
273 __builtin__.__dict__['__IPYTHON__active'] += 1
267
274
268 if self.has_readline:
275 if self.has_readline:
269 self.readline_startup_hook(self.pre_readline)
276 self.readline_startup_hook(self.pre_readline)
270 self.hlen_before_cell = self.readline.get_current_history_length()
277 hlen_b4_cell = self.readline.get_current_history_length()
271 # exit_now is set by a call to %Exit or %Quit, through the
278 # exit_now is set by a call to %Exit or %Quit, through the
272 # ask_exit callback.
279 # ask_exit callback.
273
280
274 while not self.exit_now:
281 while not self.exit_now:
275 self.hooks.pre_prompt_hook()
282 self.hooks.pre_prompt_hook()
276 if more:
283 if more:
277 try:
284 try:
278 prompt = self.hooks.generate_prompt(True)
285 prompt = self.hooks.generate_prompt(True)
279 except:
286 except:
280 self.showtraceback()
287 self.showtraceback()
281 if self.autoindent:
288 if self.autoindent:
282 self.rl_do_indent = True
289 self.rl_do_indent = True
283
290
284 else:
291 else:
285 try:
292 try:
286 prompt = self.hooks.generate_prompt(False)
293 prompt = self.hooks.generate_prompt(False)
287 except:
294 except:
288 self.showtraceback()
295 self.showtraceback()
289 try:
296 try:
290 line = self.raw_input(prompt)
297 line = self.raw_input(prompt)
291 if self.exit_now:
298 if self.exit_now:
292 # quick exit on sys.std[in|out] close
299 # quick exit on sys.std[in|out] close
293 break
300 break
294 if self.autoindent:
301 if self.autoindent:
295 self.rl_do_indent = False
302 self.rl_do_indent = False
296
303
297 except KeyboardInterrupt:
304 except KeyboardInterrupt:
298 #double-guard against keyboardinterrupts during kbdint handling
305 #double-guard against keyboardinterrupts during kbdint handling
299 try:
306 try:
300 self.write('\nKeyboardInterrupt\n')
307 self.write('\nKeyboardInterrupt\n')
301 source_raw = self.input_splitter.source_raw_reset()[1]
308 source_raw = self.input_splitter.source_raw_reset()[1]
302 self._replace_rlhist_multiline(source_raw)
309 hlen_b4_cell = \
310 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
303 more = False
311 more = False
304 except KeyboardInterrupt:
312 except KeyboardInterrupt:
305 pass
313 pass
306 except EOFError:
314 except EOFError:
307 if self.autoindent:
315 if self.autoindent:
308 self.rl_do_indent = False
316 self.rl_do_indent = False
309 if self.has_readline:
317 if self.has_readline:
310 self.readline_startup_hook(None)
318 self.readline_startup_hook(None)
311 self.write('\n')
319 self.write('\n')
312 self.exit()
320 self.exit()
313 except bdb.BdbQuit:
321 except bdb.BdbQuit:
314 warn('The Python debugger has exited with a BdbQuit exception.\n'
322 warn('The Python debugger has exited with a BdbQuit exception.\n'
315 'Because of how pdb handles the stack, it is impossible\n'
323 'Because of how pdb handles the stack, it is impossible\n'
316 'for IPython to properly format this particular exception.\n'
324 'for IPython to properly format this particular exception.\n'
317 'IPython will resume normal operation.')
325 'IPython will resume normal operation.')
318 except:
326 except:
319 # exceptions here are VERY RARE, but they can be triggered
327 # exceptions here are VERY RARE, but they can be triggered
320 # asynchronously by signal handlers, for example.
328 # asynchronously by signal handlers, for example.
321 self.showtraceback()
329 self.showtraceback()
322 else:
330 else:
323 self.input_splitter.push(line)
331 self.input_splitter.push(line)
324 more = self.input_splitter.push_accepts_more()
332 more = self.input_splitter.push_accepts_more()
325 if (self.SyntaxTB.last_syntax_error and
333 if (self.SyntaxTB.last_syntax_error and
326 self.autoedit_syntax):
334 self.autoedit_syntax):
327 self.edit_syntax_error()
335 self.edit_syntax_error()
328 if not more:
336 if not more:
329 source_raw = self.input_splitter.source_raw_reset()[1]
337 source_raw = self.input_splitter.source_raw_reset()[1]
330 self.run_cell(source_raw, store_history=True)
338 self.run_cell(source_raw, store_history=True)
331 self._replace_rlhist_multiline(source_raw)
339 hlen_b4_cell = \
340 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
332
341
333 # We are off again...
342 # We are off again...
334 __builtin__.__dict__['__IPYTHON__active'] -= 1
343 __builtin__.__dict__['__IPYTHON__active'] -= 1
335
344
336 # Turn off the exit flag, so the mainloop can be restarted if desired
345 # Turn off the exit flag, so the mainloop can be restarted if desired
337 self.exit_now = False
346 self.exit_now = False
338
347
339 def raw_input(self, prompt=''):
348 def raw_input(self, prompt=''):
340 """Write a prompt and read a line.
349 """Write a prompt and read a line.
341
350
342 The returned line does not include the trailing newline.
351 The returned line does not include the trailing newline.
343 When the user enters the EOF key sequence, EOFError is raised.
352 When the user enters the EOF key sequence, EOFError is raised.
344
353
345 Optional inputs:
354 Optional inputs:
346
355
347 - prompt(''): a string to be printed to prompt the user.
356 - prompt(''): a string to be printed to prompt the user.
348
357
349 - continue_prompt(False): whether this line is the first one or a
358 - continue_prompt(False): whether this line is the first one or a
350 continuation in a sequence of inputs.
359 continuation in a sequence of inputs.
351 """
360 """
352 # Code run by the user may have modified the readline completer state.
361 # Code run by the user may have modified the readline completer state.
353 # We must ensure that our completer is back in place.
362 # We must ensure that our completer is back in place.
354
363
355 if self.has_readline:
364 if self.has_readline:
356 self.set_readline_completer()
365 self.set_readline_completer()
357
366
358 try:
367 try:
359 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
368 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
360 except ValueError:
369 except ValueError:
361 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
370 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
362 " or sys.stdout.close()!\nExiting IPython!")
371 " or sys.stdout.close()!\nExiting IPython!")
363 self.ask_exit()
372 self.ask_exit()
364 return ""
373 return ""
365
374
366 # Try to be reasonably smart about not re-indenting pasted input more
375 # Try to be reasonably smart about not re-indenting pasted input more
367 # than necessary. We do this by trimming out the auto-indent initial
376 # than necessary. We do this by trimming out the auto-indent initial
368 # spaces, if the user's actual input started itself with whitespace.
377 # spaces, if the user's actual input started itself with whitespace.
369 if self.autoindent:
378 if self.autoindent:
370 if num_ini_spaces(line) > self.indent_current_nsp:
379 if num_ini_spaces(line) > self.indent_current_nsp:
371 line = line[self.indent_current_nsp:]
380 line = line[self.indent_current_nsp:]
372 self.indent_current_nsp = 0
381 self.indent_current_nsp = 0
373
382
374 return line
383 return line
375
384
376 #-------------------------------------------------------------------------
385 #-------------------------------------------------------------------------
377 # Methods to support auto-editing of SyntaxErrors.
386 # Methods to support auto-editing of SyntaxErrors.
378 #-------------------------------------------------------------------------
387 #-------------------------------------------------------------------------
379
388
380 def edit_syntax_error(self):
389 def edit_syntax_error(self):
381 """The bottom half of the syntax error handler called in the main loop.
390 """The bottom half of the syntax error handler called in the main loop.
382
391
383 Loop until syntax error is fixed or user cancels.
392 Loop until syntax error is fixed or user cancels.
384 """
393 """
385
394
386 while self.SyntaxTB.last_syntax_error:
395 while self.SyntaxTB.last_syntax_error:
387 # copy and clear last_syntax_error
396 # copy and clear last_syntax_error
388 err = self.SyntaxTB.clear_err_state()
397 err = self.SyntaxTB.clear_err_state()
389 if not self._should_recompile(err):
398 if not self._should_recompile(err):
390 return
399 return
391 try:
400 try:
392 # may set last_syntax_error again if a SyntaxError is raised
401 # may set last_syntax_error again if a SyntaxError is raised
393 self.safe_execfile(err.filename,self.user_ns)
402 self.safe_execfile(err.filename,self.user_ns)
394 except:
403 except:
395 self.showtraceback()
404 self.showtraceback()
396 else:
405 else:
397 try:
406 try:
398 f = file(err.filename)
407 f = file(err.filename)
399 try:
408 try:
400 # This should be inside a display_trap block and I
409 # This should be inside a display_trap block and I
401 # think it is.
410 # think it is.
402 sys.displayhook(f.read())
411 sys.displayhook(f.read())
403 finally:
412 finally:
404 f.close()
413 f.close()
405 except:
414 except:
406 self.showtraceback()
415 self.showtraceback()
407
416
408 def _should_recompile(self,e):
417 def _should_recompile(self,e):
409 """Utility routine for edit_syntax_error"""
418 """Utility routine for edit_syntax_error"""
410
419
411 if e.filename in ('<ipython console>','<input>','<string>',
420 if e.filename in ('<ipython console>','<input>','<string>',
412 '<console>','<BackgroundJob compilation>',
421 '<console>','<BackgroundJob compilation>',
413 None):
422 None):
414
423
415 return False
424 return False
416 try:
425 try:
417 if (self.autoedit_syntax and
426 if (self.autoedit_syntax and
418 not self.ask_yes_no('Return to editor to correct syntax error? '
427 not self.ask_yes_no('Return to editor to correct syntax error? '
419 '[Y/n] ','y')):
428 '[Y/n] ','y')):
420 return False
429 return False
421 except EOFError:
430 except EOFError:
422 return False
431 return False
423
432
424 def int0(x):
433 def int0(x):
425 try:
434 try:
426 return int(x)
435 return int(x)
427 except TypeError:
436 except TypeError:
428 return 0
437 return 0
429 # always pass integer line and offset values to editor hook
438 # always pass integer line and offset values to editor hook
430 try:
439 try:
431 self.hooks.fix_error_editor(e.filename,
440 self.hooks.fix_error_editor(e.filename,
432 int0(e.lineno),int0(e.offset),e.msg)
441 int0(e.lineno),int0(e.offset),e.msg)
433 except TryNext:
442 except TryNext:
434 warn('Could not open editor')
443 warn('Could not open editor')
435 return False
444 return False
436 return True
445 return True
437
446
438 #-------------------------------------------------------------------------
447 #-------------------------------------------------------------------------
439 # Things related to GUI support and pylab
448 # Things related to GUI support and pylab
440 #-------------------------------------------------------------------------
449 #-------------------------------------------------------------------------
441
450
442 def enable_pylab(self, gui=None, import_all=True):
451 def enable_pylab(self, gui=None, import_all=True):
443 """Activate pylab support at runtime.
452 """Activate pylab support at runtime.
444
453
445 This turns on support for matplotlib, preloads into the interactive
454 This turns on support for matplotlib, preloads into the interactive
446 namespace all of numpy and pylab, and configures IPython to correcdtly
455 namespace all of numpy and pylab, and configures IPython to correcdtly
447 interact with the GUI event loop. The GUI backend to be used can be
456 interact with the GUI event loop. The GUI backend to be used can be
448 optionally selected with the optional :param:`gui` argument.
457 optionally selected with the optional :param:`gui` argument.
449
458
450 Parameters
459 Parameters
451 ----------
460 ----------
452 gui : optional, string
461 gui : optional, string
453
462
454 If given, dictates the choice of matplotlib GUI backend to use
463 If given, dictates the choice of matplotlib GUI backend to use
455 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
464 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
456 'gtk'), otherwise we use the default chosen by matplotlib (as
465 'gtk'), otherwise we use the default chosen by matplotlib (as
457 dictated by the matplotlib build-time options plus the user's
466 dictated by the matplotlib build-time options plus the user's
458 matplotlibrc configuration file).
467 matplotlibrc configuration file).
459 """
468 """
460 # We want to prevent the loading of pylab to pollute the user's
469 # We want to prevent the loading of pylab to pollute the user's
461 # namespace as shown by the %who* magics, so we execute the activation
470 # namespace as shown by the %who* magics, so we execute the activation
462 # code in an empty namespace, and we update *both* user_ns and
471 # code in an empty namespace, and we update *both* user_ns and
463 # user_ns_hidden with this information.
472 # user_ns_hidden with this information.
464 ns = {}
473 ns = {}
465 gui = pylab_activate(ns, gui, import_all)
474 gui = pylab_activate(ns, gui, import_all)
466 self.user_ns.update(ns)
475 self.user_ns.update(ns)
467 self.user_ns_hidden.update(ns)
476 self.user_ns_hidden.update(ns)
468 # Now we must activate the gui pylab wants to use, and fix %run to take
477 # Now we must activate the gui pylab wants to use, and fix %run to take
469 # plot updates into account
478 # plot updates into account
470 enable_gui(gui)
479 enable_gui(gui)
471 self.magic_run = self._pylab_magic_run
480 self.magic_run = self._pylab_magic_run
472
481
473 #-------------------------------------------------------------------------
482 #-------------------------------------------------------------------------
474 # Things related to exiting
483 # Things related to exiting
475 #-------------------------------------------------------------------------
484 #-------------------------------------------------------------------------
476
485
477 def ask_exit(self):
486 def ask_exit(self):
478 """ Ask the shell to exit. Can be overiden and used as a callback. """
487 """ Ask the shell to exit. Can be overiden and used as a callback. """
479 self.exit_now = True
488 self.exit_now = True
480
489
481 def exit(self):
490 def exit(self):
482 """Handle interactive exit.
491 """Handle interactive exit.
483
492
484 This method calls the ask_exit callback."""
493 This method calls the ask_exit callback."""
485 if self.confirm_exit:
494 if self.confirm_exit:
486 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
495 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
487 self.ask_exit()
496 self.ask_exit()
488 else:
497 else:
489 self.ask_exit()
498 self.ask_exit()
490
499
491 #------------------------------------------------------------------------
500 #------------------------------------------------------------------------
492 # Magic overrides
501 # Magic overrides
493 #------------------------------------------------------------------------
502 #------------------------------------------------------------------------
494 # Once the base class stops inheriting from magic, this code needs to be
503 # Once the base class stops inheriting from magic, this code needs to be
495 # moved into a separate machinery as well. For now, at least isolate here
504 # moved into a separate machinery as well. For now, at least isolate here
496 # the magics which this class needs to implement differently from the base
505 # the magics which this class needs to implement differently from the base
497 # class, or that are unique to it.
506 # class, or that are unique to it.
498
507
499 def magic_autoindent(self, parameter_s = ''):
508 def magic_autoindent(self, parameter_s = ''):
500 """Toggle autoindent on/off (if available)."""
509 """Toggle autoindent on/off (if available)."""
501
510
502 self.shell.set_autoindent()
511 self.shell.set_autoindent()
503 print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent]
512 print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent]
504
513
505 @skip_doctest
514 @skip_doctest
506 def magic_cpaste(self, parameter_s=''):
515 def magic_cpaste(self, parameter_s=''):
507 """Paste & execute a pre-formatted code block from clipboard.
516 """Paste & execute a pre-formatted code block from clipboard.
508
517
509 You must terminate the block with '--' (two minus-signs) or Ctrl-D alone on the
518 You must terminate the block with '--' (two minus-signs) or Ctrl-D alone on the
510 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
519 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
511 is the new sentinel for this operation)
520 is the new sentinel for this operation)
512
521
513 The block is dedented prior to execution to enable execution of method
522 The block is dedented prior to execution to enable execution of method
514 definitions. '>' and '+' characters at the beginning of a line are
523 definitions. '>' and '+' characters at the beginning of a line are
515 ignored, to allow pasting directly from e-mails, diff files and
524 ignored, to allow pasting directly from e-mails, diff files and
516 doctests (the '...' continuation prompt is also stripped). The
525 doctests (the '...' continuation prompt is also stripped). The
517 executed block is also assigned to variable named 'pasted_block' for
526 executed block is also assigned to variable named 'pasted_block' for
518 later editing with '%edit pasted_block'.
527 later editing with '%edit pasted_block'.
519
528
520 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
529 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
521 This assigns the pasted block to variable 'foo' as string, without
530 This assigns the pasted block to variable 'foo' as string, without
522 dedenting or executing it (preceding >>> and + is still stripped)
531 dedenting or executing it (preceding >>> and + is still stripped)
523
532
524 '%cpaste -r' re-executes the block previously entered by cpaste.
533 '%cpaste -r' re-executes the block previously entered by cpaste.
525
534
526 Do not be alarmed by garbled output on Windows (it's a readline bug).
535 Do not be alarmed by garbled output on Windows (it's a readline bug).
527 Just press enter and type -- (and press enter again) and the block
536 Just press enter and type -- (and press enter again) and the block
528 will be what was just pasted.
537 will be what was just pasted.
529
538
530 IPython statements (magics, shell escapes) are not supported (yet).
539 IPython statements (magics, shell escapes) are not supported (yet).
531
540
532 See also
541 See also
533 --------
542 --------
534 paste: automatically pull code from clipboard.
543 paste: automatically pull code from clipboard.
535
544
536 Examples
545 Examples
537 --------
546 --------
538 ::
547 ::
539
548
540 In [8]: %cpaste
549 In [8]: %cpaste
541 Pasting code; enter '--' alone on the line to stop.
550 Pasting code; enter '--' alone on the line to stop.
542 :>>> a = ["world!", "Hello"]
551 :>>> a = ["world!", "Hello"]
543 :>>> print " ".join(sorted(a))
552 :>>> print " ".join(sorted(a))
544 :--
553 :--
545 Hello world!
554 Hello world!
546 """
555 """
547
556
548 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
557 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
549 par = args.strip()
558 par = args.strip()
550 if opts.has_key('r'):
559 if opts.has_key('r'):
551 self._rerun_pasted()
560 self._rerun_pasted()
552 return
561 return
553
562
554 sentinel = opts.get('s','--')
563 sentinel = opts.get('s','--')
555
564
556 block = self._strip_pasted_lines_for_code(
565 block = self._strip_pasted_lines_for_code(
557 self._get_pasted_lines(sentinel))
566 self._get_pasted_lines(sentinel))
558
567
559 self._execute_block(block, par)
568 self._execute_block(block, par)
560
569
561 def magic_paste(self, parameter_s=''):
570 def magic_paste(self, parameter_s=''):
562 """Paste & execute a pre-formatted code block from clipboard.
571 """Paste & execute a pre-formatted code block from clipboard.
563
572
564 The text is pulled directly from the clipboard without user
573 The text is pulled directly from the clipboard without user
565 intervention and printed back on the screen before execution (unless
574 intervention and printed back on the screen before execution (unless
566 the -q flag is given to force quiet mode).
575 the -q flag is given to force quiet mode).
567
576
568 The block is dedented prior to execution to enable execution of method
577 The block is dedented prior to execution to enable execution of method
569 definitions. '>' and '+' characters at the beginning of a line are
578 definitions. '>' and '+' characters at the beginning of a line are
570 ignored, to allow pasting directly from e-mails, diff files and
579 ignored, to allow pasting directly from e-mails, diff files and
571 doctests (the '...' continuation prompt is also stripped). The
580 doctests (the '...' continuation prompt is also stripped). The
572 executed block is also assigned to variable named 'pasted_block' for
581 executed block is also assigned to variable named 'pasted_block' for
573 later editing with '%edit pasted_block'.
582 later editing with '%edit pasted_block'.
574
583
575 You can also pass a variable name as an argument, e.g. '%paste foo'.
584 You can also pass a variable name as an argument, e.g. '%paste foo'.
576 This assigns the pasted block to variable 'foo' as string, without
585 This assigns the pasted block to variable 'foo' as string, without
577 dedenting or executing it (preceding >>> and + is still stripped)
586 dedenting or executing it (preceding >>> and + is still stripped)
578
587
579 Options
588 Options
580 -------
589 -------
581
590
582 -r: re-executes the block previously entered by cpaste.
591 -r: re-executes the block previously entered by cpaste.
583
592
584 -q: quiet mode: do not echo the pasted text back to the terminal.
593 -q: quiet mode: do not echo the pasted text back to the terminal.
585
594
586 IPython statements (magics, shell escapes) are not supported (yet).
595 IPython statements (magics, shell escapes) are not supported (yet).
587
596
588 See also
597 See also
589 --------
598 --------
590 cpaste: manually paste code into terminal until you mark its end.
599 cpaste: manually paste code into terminal until you mark its end.
591 """
600 """
592 opts,args = self.parse_options(parameter_s,'rq',mode='string')
601 opts,args = self.parse_options(parameter_s,'rq',mode='string')
593 par = args.strip()
602 par = args.strip()
594 if opts.has_key('r'):
603 if opts.has_key('r'):
595 self._rerun_pasted()
604 self._rerun_pasted()
596 return
605 return
597
606
598 text = self.shell.hooks.clipboard_get()
607 text = self.shell.hooks.clipboard_get()
599 block = self._strip_pasted_lines_for_code(text.splitlines())
608 block = self._strip_pasted_lines_for_code(text.splitlines())
600
609
601 # By default, echo back to terminal unless quiet mode is requested
610 # By default, echo back to terminal unless quiet mode is requested
602 if not opts.has_key('q'):
611 if not opts.has_key('q'):
603 write = self.shell.write
612 write = self.shell.write
604 write(self.shell.pycolorize(block))
613 write(self.shell.pycolorize(block))
605 if not block.endswith('\n'):
614 if not block.endswith('\n'):
606 write('\n')
615 write('\n')
607 write("## -- End pasted text --\n")
616 write("## -- End pasted text --\n")
608
617
609 self._execute_block(block, par)
618 self._execute_block(block, par)
610
619
611 def showindentationerror(self):
620 def showindentationerror(self):
612 super(TerminalInteractiveShell, self).showindentationerror()
621 super(TerminalInteractiveShell, self).showindentationerror()
613 print("If you want to paste code into IPython, try the %paste magic function.")
622 print("If you want to paste code into IPython, try the %paste magic function.")
614
623
615
624
616 InteractiveShellABC.register(TerminalInteractiveShell)
625 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -1,137 +1,142 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Authors
4 Authors
5 -------
5 -------
6 * Julian Taylor
6 * Julian Taylor
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # stdlib
18 # stdlib
19 import unittest
19 import unittest
20
20
21 from IPython.testing.decorators import skipif
21 from IPython.testing.decorators import skipif
22
22
23 class InteractiveShellTestCase(unittest.TestCase):
23 class InteractiveShellTestCase(unittest.TestCase):
24 def rl_hist_entries(self, rl, n):
24 def rl_hist_entries(self, rl, n):
25 """Get last n readline history entries as a list"""
25 """Get last n readline history entries as a list"""
26 return [rl.get_history_item(rl.get_current_history_length() - x)
26 return [rl.get_history_item(rl.get_current_history_length() - x)
27 for x in range(n - 1, -1, -1)]
27 for x in range(n - 1, -1, -1)]
28
28
29 def test_runs_without_rl(self):
29 def test_runs_without_rl(self):
30 """Test that function does not throw without readline"""
30 """Test that function does not throw without readline"""
31 ip = get_ipython()
31 ip = get_ipython()
32 ip.has_readline = False
32 ip.has_readline = False
33 ip.readline = None
33 ip.readline = None
34 ip._replace_rlhist_multiline(u'source')
34 ip._replace_rlhist_multiline(u'source', 0)
35
35
36 @skipif(not get_ipython().has_readline, 'no readline')
36 @skipif(not get_ipython().has_readline, 'no readline')
37 def test_replace_multiline_hist_disabled(self):
37 def test_replace_multiline_hist_disabled(self):
38 """Test that multiline replace does nothing if disabled"""
38 """Test that multiline replace does nothing if disabled"""
39 ip = get_ipython()
39 ip = get_ipython()
40 ip.multiline_history = False
40 ip.multiline_history = False
41
41
42 ghist = [u'line1', u'line2']
42 ghist = [u'line1', u'line2']
43 for h in ghist:
43 for h in ghist:
44 ip.readline.add_history(h)
44 ip.readline.add_history(h)
45 ip.hlen_before_cell = ip.readline.get_current_history_length()
45 hlen_b4_cell = ip.readline.get_current_history_length()
46 ip._replace_rlhist_multiline(u'sourc€\nsource2')
46 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2',
47 hlen_b4_cell)
47
48
48 self.assertEquals(ip.readline.get_current_history_length(),
49 self.assertEquals(ip.readline.get_current_history_length(),
49 ip.hlen_before_cell)
50 hlen_b4_cell)
50 hist = self.rl_hist_entries(ip.readline, 2)
51 hist = self.rl_hist_entries(ip.readline, 2)
51 self.assertEquals(hist, ghist)
52 self.assertEquals(hist, ghist)
52
53
53 @skipif(not get_ipython().has_readline, 'no readline')
54 @skipif(not get_ipython().has_readline, 'no readline')
54 def test_replace_multiline_hist_adds(self):
55 def test_replace_multiline_hist_adds(self):
55 """Test that multiline replace function adds history"""
56 """Test that multiline replace function adds history"""
56 ip = get_ipython()
57 ip = get_ipython()
57
58
58 ip.hlen_before_cell = ip.readline.get_current_history_length()
59 hlen_b4_cell = ip.readline.get_current_history_length()
59 ip._replace_rlhist_multiline(u'sourc€')
60 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€', hlen_b4_cell)
60
61
61 self.assertEquals(ip.hlen_before_cell,
62 self.assertEquals(hlen_b4_cell,
62 ip.readline.get_current_history_length())
63 ip.readline.get_current_history_length())
63
64
64 @skipif(not get_ipython().has_readline, 'no readline')
65 @skipif(not get_ipython().has_readline, 'no readline')
65 def test_replace_multiline_hist_keeps_history(self):
66 def test_replace_multiline_hist_keeps_history(self):
66 """Test that multiline replace does not delete history"""
67 """Test that multiline replace does not delete history"""
67 ip = get_ipython()
68 ip = get_ipython()
68 ip.multiline_history = True
69 ip.multiline_history = True
69
70
70 ghist = [u'line1', u'line2']
71 ghist = [u'line1', u'line2']
71 for h in ghist:
72 for h in ghist:
72 ip.readline.add_history(h)
73 ip.readline.add_history(h)
73
74
74 #start cell
75 #start cell
75 ip.hlen_before_cell = ip.readline.get_current_history_length()
76 hlen_b4_cell = ip.readline.get_current_history_length()
76 # nothing added to rl history, should do nothing
77 # nothing added to rl history, should do nothing
77 ip._replace_rlhist_multiline(u'sourc€\nsource2')
78 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2',
79 hlen_b4_cell)
78
80
79 self.assertEquals(ip.readline.get_current_history_length(),
81 self.assertEquals(ip.readline.get_current_history_length(),
80 ip.hlen_before_cell)
82 hlen_b4_cell)
81 hist = self.rl_hist_entries(ip.readline, 2)
83 hist = self.rl_hist_entries(ip.readline, 2)
82 self.assertEquals(hist, ghist)
84 self.assertEquals(hist, ghist)
83
85
84
86
85 @skipif(not get_ipython().has_readline, 'no readline')
87 @skipif(not get_ipython().has_readline, 'no readline')
86 def test_replace_multiline_hist_replaces_twice(self):
88 def test_replace_multiline_hist_replaces_twice(self):
87 """Test that multiline entries are replaced twice"""
89 """Test that multiline entries are replaced twice"""
88 ip = get_ipython()
90 ip = get_ipython()
89 ip.multiline_history = True
91 ip.multiline_history = True
90
92
91 ip.readline.add_history(u'line0')
93 ip.readline.add_history(u'line0')
92 #start cell
94 #start cell
93 ip.hlen_before_cell = ip.readline.get_current_history_length()
95 hlen_b4_cell = ip.readline.get_current_history_length()
94 ip.readline.add_history('l€ne1')
96 ip.readline.add_history('l€ne1')
95 ip.readline.add_history('line2')
97 ip.readline.add_history('line2')
96 #replace cell with single line
98 #replace cell with single line
97 ip._replace_rlhist_multiline(u'l€ne1\nline2')
99 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2',
100 hlen_b4_cell)
98 ip.readline.add_history('l€ne3')
101 ip.readline.add_history('l€ne3')
99 ip.readline.add_history('line4')
102 ip.readline.add_history('line4')
100 #replace cell with single line
103 #replace cell with single line
101 ip._replace_rlhist_multiline(u'l€ne3\nline4')
104 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3\nline4',
105 hlen_b4_cell)
102
106
103 self.assertEquals(ip.readline.get_current_history_length(),
107 self.assertEquals(ip.readline.get_current_history_length(),
104 ip.hlen_before_cell)
108 hlen_b4_cell)
105 hist = self.rl_hist_entries(ip.readline, 3)
109 hist = self.rl_hist_entries(ip.readline, 3)
106 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3\nline4'])
110 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3\nline4'])
107
111
108
112
109 @skipif(not get_ipython().has_readline, 'no readline')
113 @skipif(not get_ipython().has_readline, 'no readline')
110 def test_replace_multiline_hist_replaces_empty_line(self):
114 def test_replace_multiline_hist_replaces_empty_line(self):
111 """Test that multiline history skips empty line cells"""
115 """Test that multiline history skips empty line cells"""
112 ip = get_ipython()
116 ip = get_ipython()
113 ip.multiline_history = True
117 ip.multiline_history = True
114
118
115 ip.readline.add_history(u'line0')
119 ip.readline.add_history(u'line0')
116 #start cell
120 #start cell
117 ip.hlen_before_cell = ip.readline.get_current_history_length()
121 hlen_b4_cell = ip.readline.get_current_history_length()
118 ip.readline.add_history('l€ne1')
122 ip.readline.add_history('l€ne1')
119 ip.readline.add_history('line2')
123 ip.readline.add_history('line2')
120 ip._replace_rlhist_multiline(u'l€ne1\nline2')
124 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2',
125 hlen_b4_cell)
121 ip.readline.add_history('')
126 ip.readline.add_history('')
122 ip._replace_rlhist_multiline(u'')
127 hlen_b4_cell = ip._replace_rlhist_multiline(u'', hlen_b4_cell)
123 ip.readline.add_history('l€ne3')
128 ip.readline.add_history('l€ne3')
124 ip._replace_rlhist_multiline(u'l€ne3')
129 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3', hlen_b4_cell)
125 ip.readline.add_history(' ')
130 ip.readline.add_history(' ')
126 ip._replace_rlhist_multiline(' ')
131 hlen_b4_cell = ip._replace_rlhist_multiline(' ', hlen_b4_cell)
127 ip.readline.add_history('\t')
132 ip.readline.add_history('\t')
128 ip.readline.add_history('\t ')
133 ip.readline.add_history('\t ')
129 ip._replace_rlhist_multiline('\t')
134 hlen_b4_cell = ip._replace_rlhist_multiline('\t', hlen_b4_cell)
130 ip.readline.add_history('line4')
135 ip.readline.add_history('line4')
131 ip._replace_rlhist_multiline(u'line4')
136 hlen_b4_cell = ip._replace_rlhist_multiline(u'line4', hlen_b4_cell)
132
137
133 self.assertEquals(ip.readline.get_current_history_length(),
138 self.assertEquals(ip.readline.get_current_history_length(),
134 ip.hlen_before_cell)
139 hlen_b4_cell)
135 hist = self.rl_hist_entries(ip.readline, 4)
140 hist = self.rl_hist_entries(ip.readline, 4)
136 # expect no empty cells in history
141 # expect no empty cells in history
137 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3', 'line4'])
142 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3', 'line4'])
General Comments 0
You need to be logged in to leave comments. Login now