##// END OF EJS Templates
don't try to replace history when rl history unchanged...
Julian Taylor -
Show More
@@ -1,611 +1,616 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):
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():
234 if self.multiline_history and self.has_readline and source_raw.rstrip():
235 hlen = self.readline.get_current_history_length()
235 hlen = self.readline.get_current_history_length()
236
237 # nothing changed do nothing, e.g. when rl removes consecutive dups
238 if self.hlen_before_cell == hlen:
239 return
240
236 for i in range(hlen - self.hlen_before_cell):
241 for i in range(hlen - self.hlen_before_cell):
237 self.readline.remove_history_item(hlen - i - 1)
242 self.readline.remove_history_item(hlen - i - 1)
238 stdin_encoding = sys.stdin.encoding or "utf-8"
243 stdin_encoding = sys.stdin.encoding or "utf-8"
239 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
244 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
240 stdin_encoding))
245 stdin_encoding))
241 self.hlen_before_cell = self.readline.get_current_history_length()
246 self.hlen_before_cell = self.readline.get_current_history_length()
242
247
243 def interact(self, display_banner=None):
248 def interact(self, display_banner=None):
244 """Closely emulate the interactive Python console."""
249 """Closely emulate the interactive Python console."""
245
250
246 # batch run -> do not interact
251 # batch run -> do not interact
247 if self.exit_now:
252 if self.exit_now:
248 return
253 return
249
254
250 if display_banner is None:
255 if display_banner is None:
251 display_banner = self.display_banner
256 display_banner = self.display_banner
252
257
253 if isinstance(display_banner, basestring):
258 if isinstance(display_banner, basestring):
254 self.show_banner(display_banner)
259 self.show_banner(display_banner)
255 elif display_banner:
260 elif display_banner:
256 self.show_banner()
261 self.show_banner()
257
262
258 more = False
263 more = False
259
264
260 # Mark activity in the builtins
265 # Mark activity in the builtins
261 __builtin__.__dict__['__IPYTHON__active'] += 1
266 __builtin__.__dict__['__IPYTHON__active'] += 1
262
267
263 if self.has_readline:
268 if self.has_readline:
264 self.readline_startup_hook(self.pre_readline)
269 self.readline_startup_hook(self.pre_readline)
265 self.hlen_before_cell = self.readline.get_current_history_length()
270 self.hlen_before_cell = self.readline.get_current_history_length()
266 # exit_now is set by a call to %Exit or %Quit, through the
271 # exit_now is set by a call to %Exit or %Quit, through the
267 # ask_exit callback.
272 # ask_exit callback.
268
273
269 while not self.exit_now:
274 while not self.exit_now:
270 self.hooks.pre_prompt_hook()
275 self.hooks.pre_prompt_hook()
271 if more:
276 if more:
272 try:
277 try:
273 prompt = self.hooks.generate_prompt(True)
278 prompt = self.hooks.generate_prompt(True)
274 except:
279 except:
275 self.showtraceback()
280 self.showtraceback()
276 if self.autoindent:
281 if self.autoindent:
277 self.rl_do_indent = True
282 self.rl_do_indent = True
278
283
279 else:
284 else:
280 try:
285 try:
281 prompt = self.hooks.generate_prompt(False)
286 prompt = self.hooks.generate_prompt(False)
282 except:
287 except:
283 self.showtraceback()
288 self.showtraceback()
284 try:
289 try:
285 line = self.raw_input(prompt)
290 line = self.raw_input(prompt)
286 if self.exit_now:
291 if self.exit_now:
287 # quick exit on sys.std[in|out] close
292 # quick exit on sys.std[in|out] close
288 break
293 break
289 if self.autoindent:
294 if self.autoindent:
290 self.rl_do_indent = False
295 self.rl_do_indent = False
291
296
292 except KeyboardInterrupt:
297 except KeyboardInterrupt:
293 #double-guard against keyboardinterrupts during kbdint handling
298 #double-guard against keyboardinterrupts during kbdint handling
294 try:
299 try:
295 self.write('\nKeyboardInterrupt\n')
300 self.write('\nKeyboardInterrupt\n')
296 source_raw = self.input_splitter.source_raw_reset()[1]
301 source_raw = self.input_splitter.source_raw_reset()[1]
297 self._replace_rlhist_multiline(source_raw)
302 self._replace_rlhist_multiline(source_raw)
298 more = False
303 more = False
299 except KeyboardInterrupt:
304 except KeyboardInterrupt:
300 pass
305 pass
301 except EOFError:
306 except EOFError:
302 if self.autoindent:
307 if self.autoindent:
303 self.rl_do_indent = False
308 self.rl_do_indent = False
304 if self.has_readline:
309 if self.has_readline:
305 self.readline_startup_hook(None)
310 self.readline_startup_hook(None)
306 self.write('\n')
311 self.write('\n')
307 self.exit()
312 self.exit()
308 except bdb.BdbQuit:
313 except bdb.BdbQuit:
309 warn('The Python debugger has exited with a BdbQuit exception.\n'
314 warn('The Python debugger has exited with a BdbQuit exception.\n'
310 'Because of how pdb handles the stack, it is impossible\n'
315 'Because of how pdb handles the stack, it is impossible\n'
311 'for IPython to properly format this particular exception.\n'
316 'for IPython to properly format this particular exception.\n'
312 'IPython will resume normal operation.')
317 'IPython will resume normal operation.')
313 except:
318 except:
314 # exceptions here are VERY RARE, but they can be triggered
319 # exceptions here are VERY RARE, but they can be triggered
315 # asynchronously by signal handlers, for example.
320 # asynchronously by signal handlers, for example.
316 self.showtraceback()
321 self.showtraceback()
317 else:
322 else:
318 self.input_splitter.push(line)
323 self.input_splitter.push(line)
319 more = self.input_splitter.push_accepts_more()
324 more = self.input_splitter.push_accepts_more()
320 if (self.SyntaxTB.last_syntax_error and
325 if (self.SyntaxTB.last_syntax_error and
321 self.autoedit_syntax):
326 self.autoedit_syntax):
322 self.edit_syntax_error()
327 self.edit_syntax_error()
323 if not more:
328 if not more:
324 source_raw = self.input_splitter.source_raw_reset()[1]
329 source_raw = self.input_splitter.source_raw_reset()[1]
325 self.run_cell(source_raw, store_history=True)
330 self.run_cell(source_raw, store_history=True)
326 self._replace_rlhist_multiline(source_raw)
331 self._replace_rlhist_multiline(source_raw)
327
332
328 # We are off again...
333 # We are off again...
329 __builtin__.__dict__['__IPYTHON__active'] -= 1
334 __builtin__.__dict__['__IPYTHON__active'] -= 1
330
335
331 # Turn off the exit flag, so the mainloop can be restarted if desired
336 # Turn off the exit flag, so the mainloop can be restarted if desired
332 self.exit_now = False
337 self.exit_now = False
333
338
334 def raw_input(self, prompt=''):
339 def raw_input(self, prompt=''):
335 """Write a prompt and read a line.
340 """Write a prompt and read a line.
336
341
337 The returned line does not include the trailing newline.
342 The returned line does not include the trailing newline.
338 When the user enters the EOF key sequence, EOFError is raised.
343 When the user enters the EOF key sequence, EOFError is raised.
339
344
340 Optional inputs:
345 Optional inputs:
341
346
342 - prompt(''): a string to be printed to prompt the user.
347 - prompt(''): a string to be printed to prompt the user.
343
348
344 - continue_prompt(False): whether this line is the first one or a
349 - continue_prompt(False): whether this line is the first one or a
345 continuation in a sequence of inputs.
350 continuation in a sequence of inputs.
346 """
351 """
347 # Code run by the user may have modified the readline completer state.
352 # Code run by the user may have modified the readline completer state.
348 # We must ensure that our completer is back in place.
353 # We must ensure that our completer is back in place.
349
354
350 if self.has_readline:
355 if self.has_readline:
351 self.set_readline_completer()
356 self.set_readline_completer()
352
357
353 try:
358 try:
354 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
359 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
355 except ValueError:
360 except ValueError:
356 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
361 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
357 " or sys.stdout.close()!\nExiting IPython!")
362 " or sys.stdout.close()!\nExiting IPython!")
358 self.ask_exit()
363 self.ask_exit()
359 return ""
364 return ""
360
365
361 # Try to be reasonably smart about not re-indenting pasted input more
366 # Try to be reasonably smart about not re-indenting pasted input more
362 # than necessary. We do this by trimming out the auto-indent initial
367 # than necessary. We do this by trimming out the auto-indent initial
363 # spaces, if the user's actual input started itself with whitespace.
368 # spaces, if the user's actual input started itself with whitespace.
364 if self.autoindent:
369 if self.autoindent:
365 if num_ini_spaces(line) > self.indent_current_nsp:
370 if num_ini_spaces(line) > self.indent_current_nsp:
366 line = line[self.indent_current_nsp:]
371 line = line[self.indent_current_nsp:]
367 self.indent_current_nsp = 0
372 self.indent_current_nsp = 0
368
373
369 return line
374 return line
370
375
371 #-------------------------------------------------------------------------
376 #-------------------------------------------------------------------------
372 # Methods to support auto-editing of SyntaxErrors.
377 # Methods to support auto-editing of SyntaxErrors.
373 #-------------------------------------------------------------------------
378 #-------------------------------------------------------------------------
374
379
375 def edit_syntax_error(self):
380 def edit_syntax_error(self):
376 """The bottom half of the syntax error handler called in the main loop.
381 """The bottom half of the syntax error handler called in the main loop.
377
382
378 Loop until syntax error is fixed or user cancels.
383 Loop until syntax error is fixed or user cancels.
379 """
384 """
380
385
381 while self.SyntaxTB.last_syntax_error:
386 while self.SyntaxTB.last_syntax_error:
382 # copy and clear last_syntax_error
387 # copy and clear last_syntax_error
383 err = self.SyntaxTB.clear_err_state()
388 err = self.SyntaxTB.clear_err_state()
384 if not self._should_recompile(err):
389 if not self._should_recompile(err):
385 return
390 return
386 try:
391 try:
387 # may set last_syntax_error again if a SyntaxError is raised
392 # may set last_syntax_error again if a SyntaxError is raised
388 self.safe_execfile(err.filename,self.user_ns)
393 self.safe_execfile(err.filename,self.user_ns)
389 except:
394 except:
390 self.showtraceback()
395 self.showtraceback()
391 else:
396 else:
392 try:
397 try:
393 f = file(err.filename)
398 f = file(err.filename)
394 try:
399 try:
395 # This should be inside a display_trap block and I
400 # This should be inside a display_trap block and I
396 # think it is.
401 # think it is.
397 sys.displayhook(f.read())
402 sys.displayhook(f.read())
398 finally:
403 finally:
399 f.close()
404 f.close()
400 except:
405 except:
401 self.showtraceback()
406 self.showtraceback()
402
407
403 def _should_recompile(self,e):
408 def _should_recompile(self,e):
404 """Utility routine for edit_syntax_error"""
409 """Utility routine for edit_syntax_error"""
405
410
406 if e.filename in ('<ipython console>','<input>','<string>',
411 if e.filename in ('<ipython console>','<input>','<string>',
407 '<console>','<BackgroundJob compilation>',
412 '<console>','<BackgroundJob compilation>',
408 None):
413 None):
409
414
410 return False
415 return False
411 try:
416 try:
412 if (self.autoedit_syntax and
417 if (self.autoedit_syntax and
413 not self.ask_yes_no('Return to editor to correct syntax error? '
418 not self.ask_yes_no('Return to editor to correct syntax error? '
414 '[Y/n] ','y')):
419 '[Y/n] ','y')):
415 return False
420 return False
416 except EOFError:
421 except EOFError:
417 return False
422 return False
418
423
419 def int0(x):
424 def int0(x):
420 try:
425 try:
421 return int(x)
426 return int(x)
422 except TypeError:
427 except TypeError:
423 return 0
428 return 0
424 # always pass integer line and offset values to editor hook
429 # always pass integer line and offset values to editor hook
425 try:
430 try:
426 self.hooks.fix_error_editor(e.filename,
431 self.hooks.fix_error_editor(e.filename,
427 int0(e.lineno),int0(e.offset),e.msg)
432 int0(e.lineno),int0(e.offset),e.msg)
428 except TryNext:
433 except TryNext:
429 warn('Could not open editor')
434 warn('Could not open editor')
430 return False
435 return False
431 return True
436 return True
432
437
433 #-------------------------------------------------------------------------
438 #-------------------------------------------------------------------------
434 # Things related to GUI support and pylab
439 # Things related to GUI support and pylab
435 #-------------------------------------------------------------------------
440 #-------------------------------------------------------------------------
436
441
437 def enable_pylab(self, gui=None, import_all=True):
442 def enable_pylab(self, gui=None, import_all=True):
438 """Activate pylab support at runtime.
443 """Activate pylab support at runtime.
439
444
440 This turns on support for matplotlib, preloads into the interactive
445 This turns on support for matplotlib, preloads into the interactive
441 namespace all of numpy and pylab, and configures IPython to correcdtly
446 namespace all of numpy and pylab, and configures IPython to correcdtly
442 interact with the GUI event loop. The GUI backend to be used can be
447 interact with the GUI event loop. The GUI backend to be used can be
443 optionally selected with the optional :param:`gui` argument.
448 optionally selected with the optional :param:`gui` argument.
444
449
445 Parameters
450 Parameters
446 ----------
451 ----------
447 gui : optional, string
452 gui : optional, string
448
453
449 If given, dictates the choice of matplotlib GUI backend to use
454 If given, dictates the choice of matplotlib GUI backend to use
450 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
455 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
451 'gtk'), otherwise we use the default chosen by matplotlib (as
456 'gtk'), otherwise we use the default chosen by matplotlib (as
452 dictated by the matplotlib build-time options plus the user's
457 dictated by the matplotlib build-time options plus the user's
453 matplotlibrc configuration file).
458 matplotlibrc configuration file).
454 """
459 """
455 # We want to prevent the loading of pylab to pollute the user's
460 # We want to prevent the loading of pylab to pollute the user's
456 # namespace as shown by the %who* magics, so we execute the activation
461 # namespace as shown by the %who* magics, so we execute the activation
457 # code in an empty namespace, and we update *both* user_ns and
462 # code in an empty namespace, and we update *both* user_ns and
458 # user_ns_hidden with this information.
463 # user_ns_hidden with this information.
459 ns = {}
464 ns = {}
460 gui = pylab_activate(ns, gui, import_all)
465 gui = pylab_activate(ns, gui, import_all)
461 self.user_ns.update(ns)
466 self.user_ns.update(ns)
462 self.user_ns_hidden.update(ns)
467 self.user_ns_hidden.update(ns)
463 # Now we must activate the gui pylab wants to use, and fix %run to take
468 # Now we must activate the gui pylab wants to use, and fix %run to take
464 # plot updates into account
469 # plot updates into account
465 enable_gui(gui)
470 enable_gui(gui)
466 self.magic_run = self._pylab_magic_run
471 self.magic_run = self._pylab_magic_run
467
472
468 #-------------------------------------------------------------------------
473 #-------------------------------------------------------------------------
469 # Things related to exiting
474 # Things related to exiting
470 #-------------------------------------------------------------------------
475 #-------------------------------------------------------------------------
471
476
472 def ask_exit(self):
477 def ask_exit(self):
473 """ Ask the shell to exit. Can be overiden and used as a callback. """
478 """ Ask the shell to exit. Can be overiden and used as a callback. """
474 self.exit_now = True
479 self.exit_now = True
475
480
476 def exit(self):
481 def exit(self):
477 """Handle interactive exit.
482 """Handle interactive exit.
478
483
479 This method calls the ask_exit callback."""
484 This method calls the ask_exit callback."""
480 if self.confirm_exit:
485 if self.confirm_exit:
481 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
486 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
482 self.ask_exit()
487 self.ask_exit()
483 else:
488 else:
484 self.ask_exit()
489 self.ask_exit()
485
490
486 #------------------------------------------------------------------------
491 #------------------------------------------------------------------------
487 # Magic overrides
492 # Magic overrides
488 #------------------------------------------------------------------------
493 #------------------------------------------------------------------------
489 # Once the base class stops inheriting from magic, this code needs to be
494 # Once the base class stops inheriting from magic, this code needs to be
490 # moved into a separate machinery as well. For now, at least isolate here
495 # moved into a separate machinery as well. For now, at least isolate here
491 # the magics which this class needs to implement differently from the base
496 # the magics which this class needs to implement differently from the base
492 # class, or that are unique to it.
497 # class, or that are unique to it.
493
498
494 def magic_autoindent(self, parameter_s = ''):
499 def magic_autoindent(self, parameter_s = ''):
495 """Toggle autoindent on/off (if available)."""
500 """Toggle autoindent on/off (if available)."""
496
501
497 self.shell.set_autoindent()
502 self.shell.set_autoindent()
498 print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent]
503 print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent]
499
504
500 @skip_doctest
505 @skip_doctest
501 def magic_cpaste(self, parameter_s=''):
506 def magic_cpaste(self, parameter_s=''):
502 """Paste & execute a pre-formatted code block from clipboard.
507 """Paste & execute a pre-formatted code block from clipboard.
503
508
504 You must terminate the block with '--' (two minus-signs) or Ctrl-D alone on the
509 You must terminate the block with '--' (two minus-signs) or Ctrl-D alone on the
505 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
510 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
506 is the new sentinel for this operation)
511 is the new sentinel for this operation)
507
512
508 The block is dedented prior to execution to enable execution of method
513 The block is dedented prior to execution to enable execution of method
509 definitions. '>' and '+' characters at the beginning of a line are
514 definitions. '>' and '+' characters at the beginning of a line are
510 ignored, to allow pasting directly from e-mails, diff files and
515 ignored, to allow pasting directly from e-mails, diff files and
511 doctests (the '...' continuation prompt is also stripped). The
516 doctests (the '...' continuation prompt is also stripped). The
512 executed block is also assigned to variable named 'pasted_block' for
517 executed block is also assigned to variable named 'pasted_block' for
513 later editing with '%edit pasted_block'.
518 later editing with '%edit pasted_block'.
514
519
515 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
520 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
516 This assigns the pasted block to variable 'foo' as string, without
521 This assigns the pasted block to variable 'foo' as string, without
517 dedenting or executing it (preceding >>> and + is still stripped)
522 dedenting or executing it (preceding >>> and + is still stripped)
518
523
519 '%cpaste -r' re-executes the block previously entered by cpaste.
524 '%cpaste -r' re-executes the block previously entered by cpaste.
520
525
521 Do not be alarmed by garbled output on Windows (it's a readline bug).
526 Do not be alarmed by garbled output on Windows (it's a readline bug).
522 Just press enter and type -- (and press enter again) and the block
527 Just press enter and type -- (and press enter again) and the block
523 will be what was just pasted.
528 will be what was just pasted.
524
529
525 IPython statements (magics, shell escapes) are not supported (yet).
530 IPython statements (magics, shell escapes) are not supported (yet).
526
531
527 See also
532 See also
528 --------
533 --------
529 paste: automatically pull code from clipboard.
534 paste: automatically pull code from clipboard.
530
535
531 Examples
536 Examples
532 --------
537 --------
533 ::
538 ::
534
539
535 In [8]: %cpaste
540 In [8]: %cpaste
536 Pasting code; enter '--' alone on the line to stop.
541 Pasting code; enter '--' alone on the line to stop.
537 :>>> a = ["world!", "Hello"]
542 :>>> a = ["world!", "Hello"]
538 :>>> print " ".join(sorted(a))
543 :>>> print " ".join(sorted(a))
539 :--
544 :--
540 Hello world!
545 Hello world!
541 """
546 """
542
547
543 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
548 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
544 par = args.strip()
549 par = args.strip()
545 if opts.has_key('r'):
550 if opts.has_key('r'):
546 self._rerun_pasted()
551 self._rerun_pasted()
547 return
552 return
548
553
549 sentinel = opts.get('s','--')
554 sentinel = opts.get('s','--')
550
555
551 block = self._strip_pasted_lines_for_code(
556 block = self._strip_pasted_lines_for_code(
552 self._get_pasted_lines(sentinel))
557 self._get_pasted_lines(sentinel))
553
558
554 self._execute_block(block, par)
559 self._execute_block(block, par)
555
560
556 def magic_paste(self, parameter_s=''):
561 def magic_paste(self, parameter_s=''):
557 """Paste & execute a pre-formatted code block from clipboard.
562 """Paste & execute a pre-formatted code block from clipboard.
558
563
559 The text is pulled directly from the clipboard without user
564 The text is pulled directly from the clipboard without user
560 intervention and printed back on the screen before execution (unless
565 intervention and printed back on the screen before execution (unless
561 the -q flag is given to force quiet mode).
566 the -q flag is given to force quiet mode).
562
567
563 The block is dedented prior to execution to enable execution of method
568 The block is dedented prior to execution to enable execution of method
564 definitions. '>' and '+' characters at the beginning of a line are
569 definitions. '>' and '+' characters at the beginning of a line are
565 ignored, to allow pasting directly from e-mails, diff files and
570 ignored, to allow pasting directly from e-mails, diff files and
566 doctests (the '...' continuation prompt is also stripped). The
571 doctests (the '...' continuation prompt is also stripped). The
567 executed block is also assigned to variable named 'pasted_block' for
572 executed block is also assigned to variable named 'pasted_block' for
568 later editing with '%edit pasted_block'.
573 later editing with '%edit pasted_block'.
569
574
570 You can also pass a variable name as an argument, e.g. '%paste foo'.
575 You can also pass a variable name as an argument, e.g. '%paste foo'.
571 This assigns the pasted block to variable 'foo' as string, without
576 This assigns the pasted block to variable 'foo' as string, without
572 dedenting or executing it (preceding >>> and + is still stripped)
577 dedenting or executing it (preceding >>> and + is still stripped)
573
578
574 Options
579 Options
575 -------
580 -------
576
581
577 -r: re-executes the block previously entered by cpaste.
582 -r: re-executes the block previously entered by cpaste.
578
583
579 -q: quiet mode: do not echo the pasted text back to the terminal.
584 -q: quiet mode: do not echo the pasted text back to the terminal.
580
585
581 IPython statements (magics, shell escapes) are not supported (yet).
586 IPython statements (magics, shell escapes) are not supported (yet).
582
587
583 See also
588 See also
584 --------
589 --------
585 cpaste: manually paste code into terminal until you mark its end.
590 cpaste: manually paste code into terminal until you mark its end.
586 """
591 """
587 opts,args = self.parse_options(parameter_s,'rq',mode='string')
592 opts,args = self.parse_options(parameter_s,'rq',mode='string')
588 par = args.strip()
593 par = args.strip()
589 if opts.has_key('r'):
594 if opts.has_key('r'):
590 self._rerun_pasted()
595 self._rerun_pasted()
591 return
596 return
592
597
593 text = self.shell.hooks.clipboard_get()
598 text = self.shell.hooks.clipboard_get()
594 block = self._strip_pasted_lines_for_code(text.splitlines())
599 block = self._strip_pasted_lines_for_code(text.splitlines())
595
600
596 # By default, echo back to terminal unless quiet mode is requested
601 # By default, echo back to terminal unless quiet mode is requested
597 if not opts.has_key('q'):
602 if not opts.has_key('q'):
598 write = self.shell.write
603 write = self.shell.write
599 write(self.shell.pycolorize(block))
604 write(self.shell.pycolorize(block))
600 if not block.endswith('\n'):
605 if not block.endswith('\n'):
601 write('\n')
606 write('\n')
602 write("## -- End pasted text --\n")
607 write("## -- End pasted text --\n")
603
608
604 self._execute_block(block, par)
609 self._execute_block(block, par)
605
610
606 def showindentationerror(self):
611 def showindentationerror(self):
607 super(TerminalInteractiveShell, self).showindentationerror()
612 super(TerminalInteractiveShell, self).showindentationerror()
608 print("If you want to paste code into IPython, try the %paste magic function.")
613 print("If you want to paste code into IPython, try the %paste magic function.")
609
614
610
615
611 InteractiveShellABC.register(TerminalInteractiveShell)
616 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -1,136 +1,137 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')
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 ip.hlen_before_cell = ip.readline.get_current_history_length()
46 ip._replace_rlhist_multiline(u'sourc€\nsource2')
46 ip._replace_rlhist_multiline(u'sourc€\nsource2')
47
47
48 self.assertEquals(ip.readline.get_current_history_length(),
48 self.assertEquals(ip.readline.get_current_history_length(),
49 ip.hlen_before_cell)
49 ip.hlen_before_cell)
50 hist = self.rl_hist_entries(ip.readline, 2)
50 hist = self.rl_hist_entries(ip.readline, 2)
51 self.assertEquals(hist, ghist)
51 self.assertEquals(hist, ghist)
52
52
53 @skipif(not get_ipython().has_readline, 'no readline')
53 @skipif(not get_ipython().has_readline, 'no readline')
54 def test_replace_multiline_hist_adds(self):
54 def test_replace_multiline_hist_adds(self):
55 """Test that multiline replace function adds history"""
55 """Test that multiline replace function adds history"""
56 ip = get_ipython()
56 ip = get_ipython()
57
57
58 ip.hlen_before_cell = ip.readline.get_current_history_length()
58 ip.hlen_before_cell = ip.readline.get_current_history_length()
59 ip._replace_rlhist_multiline(u'sourc€')
59 ip._replace_rlhist_multiline(u'sourc€')
60
60
61 self.assertEquals(ip.hlen_before_cell,
61 self.assertEquals(ip.hlen_before_cell,
62 ip.readline.get_current_history_length())
62 ip.readline.get_current_history_length())
63
63
64 @skipif(not get_ipython().has_readline, 'no readline')
64 @skipif(not get_ipython().has_readline, 'no readline')
65 def test_replace_multiline_hist_keeps_history(self):
65 def test_replace_multiline_hist_keeps_history(self):
66 """Test that multiline replace does not delete history"""
66 """Test that multiline replace does not delete history"""
67 ip = get_ipython()
67 ip = get_ipython()
68 ip.multiline_history = True
68 ip.multiline_history = True
69
69
70 ghist = [u'line1', u'line2']
70 ghist = [u'line1', u'line2']
71 for h in ghist:
71 for h in ghist:
72 ip.readline.add_history(h)
72 ip.readline.add_history(h)
73
73
74 #start cell
74 #start cell
75 ip.hlen_before_cell = ip.readline.get_current_history_length()
75 ip.hlen_before_cell = ip.readline.get_current_history_length()
76 # nothing added to rl history, should do nothing
76 ip._replace_rlhist_multiline(u'sourc€\nsource2')
77 ip._replace_rlhist_multiline(u'sourc€\nsource2')
77
78
78 self.assertEquals(ip.readline.get_current_history_length(),
79 self.assertEquals(ip.readline.get_current_history_length(),
79 ip.hlen_before_cell)
80 ip.hlen_before_cell)
80 hist = self.rl_hist_entries(ip.readline, 3)
81 hist = self.rl_hist_entries(ip.readline, 2)
81 self.assertEquals(hist, ghist + ['sourc€\nsource2'])
82 self.assertEquals(hist, ghist)
82
83
83
84
84 @skipif(not get_ipython().has_readline, 'no readline')
85 @skipif(not get_ipython().has_readline, 'no readline')
85 def test_replace_multiline_hist_replaces_twice(self):
86 def test_replace_multiline_hist_replaces_twice(self):
86 """Test that multiline entries are replaced twice"""
87 """Test that multiline entries are replaced twice"""
87 ip = get_ipython()
88 ip = get_ipython()
88 ip.multiline_history = True
89 ip.multiline_history = True
89
90
90 ip.readline.add_history(u'line0')
91 ip.readline.add_history(u'line0')
91 #start cell
92 #start cell
92 ip.hlen_before_cell = ip.readline.get_current_history_length()
93 ip.hlen_before_cell = ip.readline.get_current_history_length()
93 ip.readline.add_history('l€ne1')
94 ip.readline.add_history('l€ne1')
94 ip.readline.add_history('line2')
95 ip.readline.add_history('line2')
95 #replace cell with single line
96 #replace cell with single line
96 ip._replace_rlhist_multiline(u'l€ne1\nline2')
97 ip._replace_rlhist_multiline(u'l€ne1\nline2')
97 ip.readline.add_history('l€ne3')
98 ip.readline.add_history('l€ne3')
98 ip.readline.add_history('line4')
99 ip.readline.add_history('line4')
99 #replace cell with single line
100 #replace cell with single line
100 ip._replace_rlhist_multiline(u'l€ne3\nline4')
101 ip._replace_rlhist_multiline(u'l€ne3\nline4')
101
102
102 self.assertEquals(ip.readline.get_current_history_length(),
103 self.assertEquals(ip.readline.get_current_history_length(),
103 ip.hlen_before_cell)
104 ip.hlen_before_cell)
104 hist = self.rl_hist_entries(ip.readline, 3)
105 hist = self.rl_hist_entries(ip.readline, 3)
105 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3\nline4'])
106 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3\nline4'])
106
107
107
108
108 @skipif(not get_ipython().has_readline, 'no readline')
109 @skipif(not get_ipython().has_readline, 'no readline')
109 def test_replace_multiline_hist_replaces_empty_line(self):
110 def test_replace_multiline_hist_replaces_empty_line(self):
110 """Test that multiline history skips empty line cells"""
111 """Test that multiline history skips empty line cells"""
111 ip = get_ipython()
112 ip = get_ipython()
112 ip.multiline_history = True
113 ip.multiline_history = True
113
114
114 ip.readline.add_history(u'line0')
115 ip.readline.add_history(u'line0')
115 #start cell
116 #start cell
116 ip.hlen_before_cell = ip.readline.get_current_history_length()
117 ip.hlen_before_cell = ip.readline.get_current_history_length()
117 ip.readline.add_history('l€ne1')
118 ip.readline.add_history('l€ne1')
118 ip.readline.add_history('line2')
119 ip.readline.add_history('line2')
119 ip._replace_rlhist_multiline(u'l€ne1\nline2')
120 ip._replace_rlhist_multiline(u'l€ne1\nline2')
120 ip.readline.add_history('')
121 ip.readline.add_history('')
121 ip._replace_rlhist_multiline(u'')
122 ip._replace_rlhist_multiline(u'')
122 ip.readline.add_history('l€ne3')
123 ip.readline.add_history('l€ne3')
123 ip._replace_rlhist_multiline(u'l€ne3')
124 ip._replace_rlhist_multiline(u'l€ne3')
124 ip.readline.add_history(' ')
125 ip.readline.add_history(' ')
125 ip._replace_rlhist_multiline(' ')
126 ip._replace_rlhist_multiline(' ')
126 ip.readline.add_history('\t')
127 ip.readline.add_history('\t')
127 ip.readline.add_history('\t ')
128 ip.readline.add_history('\t ')
128 ip._replace_rlhist_multiline('\t')
129 ip._replace_rlhist_multiline('\t')
129 ip.readline.add_history('line4')
130 ip.readline.add_history('line4')
130 ip._replace_rlhist_multiline(u'line4')
131 ip._replace_rlhist_multiline(u'line4')
131
132
132 self.assertEquals(ip.readline.get_current_history_length(),
133 self.assertEquals(ip.readline.get_current_history_length(),
133 ip.hlen_before_cell)
134 ip.hlen_before_cell)
134 hist = self.rl_hist_entries(ip.readline, 4)
135 hist = self.rl_hist_entries(ip.readline, 4)
135 # expect no empty cells in history
136 # expect no empty cells in history
136 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3', 'line4'])
137 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3', 'line4'])
General Comments 0
You need to be logged in to leave comments. Login now