##// END OF EJS Templates
Store command history for the debugger
Thomas Kluyver -
Show More
@@ -1,630 +1,632 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 the command line completion of other programs which include this isn't
6 the command line completion of other programs which include this isn't
7 damaged.
7 damaged.
8
8
9 In the future, this class will be expanded with improvements over the standard
9 In the future, this class will be expanded with improvements over the standard
10 pdb.
10 pdb.
11
11
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 changes. Licensing should therefore be under the standard Python terms. For
13 changes. Licensing should therefore be under the standard Python terms. For
14 details on the PSF (Python Software Foundation) standard license, see:
14 details on the PSF (Python Software Foundation) standard license, see:
15
15
16 http://www.python.org/2.2.3/license.html"""
16 http://www.python.org/2.2.3/license.html"""
17
17
18 #*****************************************************************************
18 #*****************************************************************************
19 #
19 #
20 # This file is licensed under the PSF license.
20 # This file is licensed under the PSF license.
21 #
21 #
22 # Copyright (C) 2001 Python Software Foundation, www.python.org
22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 #
24 #
25 #
25 #
26 #*****************************************************************************
26 #*****************************************************************************
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 import bdb
29 import bdb
30 import functools
30 import functools
31 import inspect
31 import inspect
32 import sys
32 import sys
33
33
34 from IPython import get_ipython
34 from IPython import get_ipython
35 from IPython.utils import PyColorize, ulinecache
35 from IPython.utils import PyColorize, ulinecache
36 from IPython.utils import coloransi, py3compat
36 from IPython.utils import coloransi, py3compat
37 from IPython.core.excolors import exception_colors
37 from IPython.core.excolors import exception_colors
38 from IPython.testing.skipdoctest import skip_doctest
38 from IPython.testing.skipdoctest import skip_doctest
39
39
40 from prompt_toolkit import prompt as ptk_prompt
40 from prompt_toolkit import prompt as ptk_prompt
41
41
42 prompt = 'ipdb> '
42 prompt = 'ipdb> '
43
43
44 #We have to check this directly from sys.argv, config struct not yet available
44 #We have to check this directly from sys.argv, config struct not yet available
45 from pdb import Pdb as OldPdb
45 from pdb import Pdb as OldPdb
46
46
47 # Allow the set_trace code to operate outside of an ipython instance, even if
47 # Allow the set_trace code to operate outside of an ipython instance, even if
48 # it does so with some limitations. The rest of this support is implemented in
48 # it does so with some limitations. The rest of this support is implemented in
49 # the Tracer constructor.
49 # the Tracer constructor.
50
50
51 def make_arrow(pad):
51 def make_arrow(pad):
52 """generate the leading arrow in front of traceback or debugger"""
52 """generate the leading arrow in front of traceback or debugger"""
53 if pad >= 2:
53 if pad >= 2:
54 return '-'*(pad-2) + '> '
54 return '-'*(pad-2) + '> '
55 elif pad == 1:
55 elif pad == 1:
56 return '>'
56 return '>'
57 return ''
57 return ''
58
58
59
59
60 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
60 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
61 """Exception hook which handles `BdbQuit` exceptions.
61 """Exception hook which handles `BdbQuit` exceptions.
62
62
63 All other exceptions are processed using the `excepthook`
63 All other exceptions are processed using the `excepthook`
64 parameter.
64 parameter.
65 """
65 """
66 if et==bdb.BdbQuit:
66 if et==bdb.BdbQuit:
67 print('Exiting Debugger.')
67 print('Exiting Debugger.')
68 elif excepthook is not None:
68 elif excepthook is not None:
69 excepthook(et, ev, tb)
69 excepthook(et, ev, tb)
70 else:
70 else:
71 # Backwards compatibility. Raise deprecation warning?
71 # Backwards compatibility. Raise deprecation warning?
72 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
72 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
73
73
74 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
74 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
75 print('Exiting Debugger.')
75 print('Exiting Debugger.')
76
76
77
77
78 class Tracer(object):
78 class Tracer(object):
79 """Class for local debugging, similar to pdb.set_trace.
79 """Class for local debugging, similar to pdb.set_trace.
80
80
81 Instances of this class, when called, behave like pdb.set_trace, but
81 Instances of this class, when called, behave like pdb.set_trace, but
82 providing IPython's enhanced capabilities.
82 providing IPython's enhanced capabilities.
83
83
84 This is implemented as a class which must be initialized in your own code
84 This is implemented as a class which must be initialized in your own code
85 and not as a standalone function because we need to detect at runtime
85 and not as a standalone function because we need to detect at runtime
86 whether IPython is already active or not. That detection is done in the
86 whether IPython is already active or not. That detection is done in the
87 constructor, ensuring that this code plays nicely with a running IPython,
87 constructor, ensuring that this code plays nicely with a running IPython,
88 while functioning acceptably (though with limitations) if outside of it.
88 while functioning acceptably (though with limitations) if outside of it.
89 """
89 """
90
90
91 @skip_doctest
91 @skip_doctest
92 def __init__(self, colors=None):
92 def __init__(self, colors=None):
93 """Create a local debugger instance.
93 """Create a local debugger instance.
94
94
95 Parameters
95 Parameters
96 ----------
96 ----------
97
97
98 colors : str, optional
98 colors : str, optional
99 The name of the color scheme to use, it must be one of IPython's
99 The name of the color scheme to use, it must be one of IPython's
100 valid color schemes. If not given, the function will default to
100 valid color schemes. If not given, the function will default to
101 the current IPython scheme when running inside IPython, and to
101 the current IPython scheme when running inside IPython, and to
102 'NoColor' otherwise.
102 'NoColor' otherwise.
103
103
104 Examples
104 Examples
105 --------
105 --------
106 ::
106 ::
107
107
108 from IPython.core.debugger import Tracer; debug_here = Tracer()
108 from IPython.core.debugger import Tracer; debug_here = Tracer()
109
109
110 Later in your code::
110 Later in your code::
111
111
112 debug_here() # -> will open up the debugger at that point.
112 debug_here() # -> will open up the debugger at that point.
113
113
114 Once the debugger activates, you can use all of its regular commands to
114 Once the debugger activates, you can use all of its regular commands to
115 step through code, set breakpoints, etc. See the pdb documentation
115 step through code, set breakpoints, etc. See the pdb documentation
116 from the Python standard library for usage details.
116 from the Python standard library for usage details.
117 """
117 """
118
118
119 ip = get_ipython()
119 ip = get_ipython()
120 if ip is None:
120 if ip is None:
121 # Outside of ipython, we set our own exception hook manually
121 # Outside of ipython, we set our own exception hook manually
122 sys.excepthook = functools.partial(BdbQuit_excepthook,
122 sys.excepthook = functools.partial(BdbQuit_excepthook,
123 excepthook=sys.excepthook)
123 excepthook=sys.excepthook)
124 def_colors = 'NoColor'
124 def_colors = 'NoColor'
125 else:
125 else:
126 # In ipython, we use its custom exception handler mechanism
126 # In ipython, we use its custom exception handler mechanism
127 def_colors = ip.colors
127 def_colors = ip.colors
128 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
128 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
129
129
130 if colors is None:
130 if colors is None:
131 colors = def_colors
131 colors = def_colors
132
132
133 # The stdlib debugger internally uses a modified repr from the `repr`
133 # The stdlib debugger internally uses a modified repr from the `repr`
134 # module, that limits the length of printed strings to a hardcoded
134 # module, that limits the length of printed strings to a hardcoded
135 # limit of 30 characters. That much trimming is too aggressive, let's
135 # limit of 30 characters. That much trimming is too aggressive, let's
136 # at least raise that limit to 80 chars, which should be enough for
136 # at least raise that limit to 80 chars, which should be enough for
137 # most interactive uses.
137 # most interactive uses.
138 try:
138 try:
139 try:
139 try:
140 from reprlib import aRepr # Py 3
140 from reprlib import aRepr # Py 3
141 except ImportError:
141 except ImportError:
142 from repr import aRepr # Py 2
142 from repr import aRepr # Py 2
143 aRepr.maxstring = 80
143 aRepr.maxstring = 80
144 except:
144 except:
145 # This is only a user-facing convenience, so any error we encounter
145 # This is only a user-facing convenience, so any error we encounter
146 # here can be warned about but can be otherwise ignored. These
146 # here can be warned about but can be otherwise ignored. These
147 # printouts will tell us about problems if this API changes
147 # printouts will tell us about problems if this API changes
148 import traceback
148 import traceback
149 traceback.print_exc()
149 traceback.print_exc()
150
150
151 self.debugger = Pdb(colors)
151 self.debugger = Pdb(colors)
152
152
153 def __call__(self):
153 def __call__(self):
154 """Starts an interactive debugger at the point where called.
154 """Starts an interactive debugger at the point where called.
155
155
156 This is similar to the pdb.set_trace() function from the std lib, but
156 This is similar to the pdb.set_trace() function from the std lib, but
157 using IPython's enhanced debugger."""
157 using IPython's enhanced debugger."""
158
158
159 self.debugger.set_trace(sys._getframe().f_back)
159 self.debugger.set_trace(sys._getframe().f_back)
160
160
161
161
162 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
162 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
163 """Make new_fn have old_fn's doc string. This is particularly useful
163 """Make new_fn have old_fn's doc string. This is particularly useful
164 for the ``do_...`` commands that hook into the help system.
164 for the ``do_...`` commands that hook into the help system.
165 Adapted from from a comp.lang.python posting
165 Adapted from from a comp.lang.python posting
166 by Duncan Booth."""
166 by Duncan Booth."""
167 def wrapper(*args, **kw):
167 def wrapper(*args, **kw):
168 return new_fn(*args, **kw)
168 return new_fn(*args, **kw)
169 if old_fn.__doc__:
169 if old_fn.__doc__:
170 wrapper.__doc__ = old_fn.__doc__ + additional_text
170 wrapper.__doc__ = old_fn.__doc__ + additional_text
171 return wrapper
171 return wrapper
172
172
173
173
174 def _file_lines(fname):
174 def _file_lines(fname):
175 """Return the contents of a named file as a list of lines.
175 """Return the contents of a named file as a list of lines.
176
176
177 This function never raises an IOError exception: if the file can't be
177 This function never raises an IOError exception: if the file can't be
178 read, it simply returns an empty list."""
178 read, it simply returns an empty list."""
179
179
180 try:
180 try:
181 outfile = open(fname)
181 outfile = open(fname)
182 except IOError:
182 except IOError:
183 return []
183 return []
184 else:
184 else:
185 out = outfile.readlines()
185 out = outfile.readlines()
186 outfile.close()
186 outfile.close()
187 return out
187 return out
188
188
189
189
190 class Pdb(OldPdb, object):
190 class Pdb(OldPdb, object):
191 """Modified Pdb class, does not load readline."""
191 """Modified Pdb class, does not load readline."""
192
192
193 def __init__(self,color_scheme='NoColor',completekey=None,
193 def __init__(self,color_scheme='NoColor',completekey=None,
194 stdin=None, stdout=None, context=5):
194 stdin=None, stdout=None, context=5):
195
195
196 # Parent constructor:
196 # Parent constructor:
197 try:
197 try:
198 self.context=int(context)
198 self.context=int(context)
199 if self.context <= 0:
199 if self.context <= 0:
200 raise ValueError("Context must be a positive integer")
200 raise ValueError("Context must be a positive integer")
201 except (TypeError, ValueError):
201 except (TypeError, ValueError):
202 raise ValueError("Context must be a positive integer")
202 raise ValueError("Context must be a positive integer")
203
203
204 OldPdb.__init__(self,completekey,stdin,stdout)
204 OldPdb.__init__(self,completekey,stdin,stdout)
205
205
206 # IPython changes...
206 # IPython changes...
207 self.shell = get_ipython()
207 self.shell = get_ipython()
208
208
209 if self.shell is None:
209 if self.shell is None:
210 # No IPython instance running, we must create one
210 # No IPython instance running, we must create one
211 from IPython.terminal.interactiveshell import \
211 from IPython.terminal.interactiveshell import \
212 TerminalInteractiveShell
212 TerminalInteractiveShell
213 self.shell = TerminalInteractiveShell.instance()
213 self.shell = TerminalInteractiveShell.instance()
214
214
215 # This is icky, but I'm not currently sure how best to test if we're
215 # This is icky, but I'm not currently sure how best to test if we're
216 # in a terminal shell using prompt_toolkit
216 # in a terminal shell using prompt_toolkit
217 self.use_prompt_toolkit = hasattr(self.shell, 'pt_cli')
217 self.use_prompt_toolkit = hasattr(self.shell, 'pt_cli')
218
218
219 self.aliases = {}
219 self.aliases = {}
220
220
221 # Create color table: we copy the default one from the traceback
221 # Create color table: we copy the default one from the traceback
222 # module and add a few attributes needed for debugging
222 # module and add a few attributes needed for debugging
223 self.color_scheme_table = exception_colors()
223 self.color_scheme_table = exception_colors()
224
224
225 # shorthands
225 # shorthands
226 C = coloransi.TermColors
226 C = coloransi.TermColors
227 cst = self.color_scheme_table
227 cst = self.color_scheme_table
228
228
229 cst['NoColor'].colors.prompt = C.NoColor
229 cst['NoColor'].colors.prompt = C.NoColor
230 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
230 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
231 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
231 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
232
232
233 cst['Linux'].colors.prompt = C.Green
233 cst['Linux'].colors.prompt = C.Green
234 cst['Linux'].colors.breakpoint_enabled = C.LightRed
234 cst['Linux'].colors.breakpoint_enabled = C.LightRed
235 cst['Linux'].colors.breakpoint_disabled = C.Red
235 cst['Linux'].colors.breakpoint_disabled = C.Red
236
236
237 cst['LightBG'].colors.prompt = C.Blue
237 cst['LightBG'].colors.prompt = C.Blue
238 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
238 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
239 cst['LightBG'].colors.breakpoint_disabled = C.Red
239 cst['LightBG'].colors.breakpoint_disabled = C.Red
240
240
241 self.set_colors(color_scheme)
241 self.set_colors(color_scheme)
242
242
243 # Add a python parser so we can syntax highlight source while
243 # Add a python parser so we can syntax highlight source while
244 # debugging.
244 # debugging.
245 self.parser = PyColorize.Parser()
245 self.parser = PyColorize.Parser()
246
246
247 # Set the prompt - the default prompt is '(Pdb)'
247 # Set the prompt - the default prompt is '(Pdb)'
248 self.prompt = prompt
248 self.prompt = prompt
249
249
250
250
251 def cmdloop(self, intro=None):
251 def cmdloop(self, intro=None):
252 """Repeatedly issue a prompt, accept input, parse an initial prefix
252 """Repeatedly issue a prompt, accept input, parse an initial prefix
253 off the received input, and dispatch to action methods, passing them
253 off the received input, and dispatch to action methods, passing them
254 the remainder of the line as argument.
254 the remainder of the line as argument.
255
255
256 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
256 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
257 """
257 """
258 if not self.use_prompt_toolkit:
258 if not self.use_prompt_toolkit:
259 return OldPdb.cmdloop(self, intro)
259 return OldPdb.cmdloop(self, intro)
260
260
261 if not self.use_rawinput:
261 if not self.use_rawinput:
262 raise ValueError('Sorry ipdb does not support raw_input=False')
262 raise ValueError('Sorry ipdb does not support raw_input=False')
263
263
264 def get_prompt_tokens(cli):
264 def get_prompt_tokens(cli):
265 from pygments.token import Token
265 from pygments.token import Token
266 return [(Token.Prompt, self.prompt)]
266 return [(Token.Prompt, self.prompt)]
267
267
268 self.preloop()
268 self.preloop()
269 try:
269 try:
270 if intro is not None:
270 if intro is not None:
271 self.intro = intro
271 self.intro = intro
272 if self.intro:
272 if self.intro:
273 self.stdout.write(str(self.intro)+"\n")
273 self.stdout.write(str(self.intro)+"\n")
274 stop = None
274 stop = None
275 while not stop:
275 while not stop:
276 if self.cmdqueue:
276 if self.cmdqueue:
277 line = self.cmdqueue.pop(0)
277 line = self.cmdqueue.pop(0)
278 else:
278 else:
279 try:
279 try:
280 line = ptk_prompt(get_prompt_tokens=get_prompt_tokens)
280 line = ptk_prompt(get_prompt_tokens=get_prompt_tokens,
281 history=self.shell.debugger_history,
282 )
281 except EOFError:
283 except EOFError:
282 line = 'EOF'
284 line = 'EOF'
283 line = self.precmd(line)
285 line = self.precmd(line)
284 stop = self.onecmd(line)
286 stop = self.onecmd(line)
285 stop = self.postcmd(stop, line)
287 stop = self.postcmd(stop, line)
286 self.postloop()
288 self.postloop()
287 except Exception:
289 except Exception:
288 pass
290 pass
289
291
290
292
291
293
292 def set_colors(self, scheme):
294 def set_colors(self, scheme):
293 """Shorthand access to the color table scheme selector method."""
295 """Shorthand access to the color table scheme selector method."""
294 self.color_scheme_table.set_active_scheme(scheme)
296 self.color_scheme_table.set_active_scheme(scheme)
295
297
296 def interaction(self, frame, traceback):
298 def interaction(self, frame, traceback):
297 try:
299 try:
298 OldPdb.interaction(self, frame, traceback)
300 OldPdb.interaction(self, frame, traceback)
299 except KeyboardInterrupt:
301 except KeyboardInterrupt:
300 sys.stdout.write('\n' + self.shell.get_exception_only())
302 sys.stdout.write('\n' + self.shell.get_exception_only())
301
303
302 def parseline(self, line):
304 def parseline(self, line):
303 if line.startswith("!!"):
305 if line.startswith("!!"):
304 # Force standard behavior.
306 # Force standard behavior.
305 return super(Pdb, self).parseline(line[2:])
307 return super(Pdb, self).parseline(line[2:])
306 # "Smart command mode" from pdb++: don't execute commands if a variable
308 # "Smart command mode" from pdb++: don't execute commands if a variable
307 # with the same name exists.
309 # with the same name exists.
308 cmd, arg, newline = super(Pdb, self).parseline(line)
310 cmd, arg, newline = super(Pdb, self).parseline(line)
309 if cmd in self.curframe.f_globals or cmd in self.curframe.f_locals:
311 if cmd in self.curframe.f_globals or cmd in self.curframe.f_locals:
310 return super(Pdb, self).parseline("!" + line)
312 return super(Pdb, self).parseline("!" + line)
311 return super(Pdb, self).parseline(line)
313 return super(Pdb, self).parseline(line)
312
314
313 def new_do_up(self, arg):
315 def new_do_up(self, arg):
314 OldPdb.do_up(self, arg)
316 OldPdb.do_up(self, arg)
315 self.shell.set_completer_frame(self.curframe)
317 self.shell.set_completer_frame(self.curframe)
316 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
318 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
317
319
318 def new_do_down(self, arg):
320 def new_do_down(self, arg):
319 OldPdb.do_down(self, arg)
321 OldPdb.do_down(self, arg)
320 self.shell.set_completer_frame(self.curframe)
322 self.shell.set_completer_frame(self.curframe)
321
323
322 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
324 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
323
325
324 def new_do_frame(self, arg):
326 def new_do_frame(self, arg):
325 OldPdb.do_frame(self, arg)
327 OldPdb.do_frame(self, arg)
326 self.shell.set_completer_frame(self.curframe)
328 self.shell.set_completer_frame(self.curframe)
327
329
328 def new_do_quit(self, arg):
330 def new_do_quit(self, arg):
329
331
330 if hasattr(self, 'old_all_completions'):
332 if hasattr(self, 'old_all_completions'):
331 self.shell.Completer.all_completions=self.old_all_completions
333 self.shell.Completer.all_completions=self.old_all_completions
332
334
333 return OldPdb.do_quit(self, arg)
335 return OldPdb.do_quit(self, arg)
334
336
335 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
337 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
336
338
337 def new_do_restart(self, arg):
339 def new_do_restart(self, arg):
338 """Restart command. In the context of ipython this is exactly the same
340 """Restart command. In the context of ipython this is exactly the same
339 thing as 'quit'."""
341 thing as 'quit'."""
340 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
342 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
341 return self.do_quit(arg)
343 return self.do_quit(arg)
342
344
343 def postloop(self):
345 def postloop(self):
344 self.shell.set_completer_frame(None)
346 self.shell.set_completer_frame(None)
345
347
346 def print_stack_trace(self, context=None):
348 def print_stack_trace(self, context=None):
347 if context is None:
349 if context is None:
348 context = self.context
350 context = self.context
349 try:
351 try:
350 context=int(context)
352 context=int(context)
351 if context <= 0:
353 if context <= 0:
352 raise ValueError("Context must be a positive integer")
354 raise ValueError("Context must be a positive integer")
353 except (TypeError, ValueError):
355 except (TypeError, ValueError):
354 raise ValueError("Context must be a positive integer")
356 raise ValueError("Context must be a positive integer")
355 try:
357 try:
356 for frame_lineno in self.stack:
358 for frame_lineno in self.stack:
357 self.print_stack_entry(frame_lineno, context=context)
359 self.print_stack_entry(frame_lineno, context=context)
358 except KeyboardInterrupt:
360 except KeyboardInterrupt:
359 pass
361 pass
360
362
361 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
363 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
362 context=None):
364 context=None):
363 if context is None:
365 if context is None:
364 context = self.context
366 context = self.context
365 try:
367 try:
366 context=int(context)
368 context=int(context)
367 if context <= 0:
369 if context <= 0:
368 raise ValueError("Context must be a positive integer")
370 raise ValueError("Context must be a positive integer")
369 except (TypeError, ValueError):
371 except (TypeError, ValueError):
370 raise ValueError("Context must be a positive integer")
372 raise ValueError("Context must be a positive integer")
371 print(self.format_stack_entry(frame_lineno, '', context))
373 print(self.format_stack_entry(frame_lineno, '', context))
372
374
373 # vds: >>
375 # vds: >>
374 frame, lineno = frame_lineno
376 frame, lineno = frame_lineno
375 filename = frame.f_code.co_filename
377 filename = frame.f_code.co_filename
376 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
378 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
377 # vds: <<
379 # vds: <<
378
380
379 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
381 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
380 if context is None:
382 if context is None:
381 context = self.context
383 context = self.context
382 try:
384 try:
383 context=int(context)
385 context=int(context)
384 if context <= 0:
386 if context <= 0:
385 print("Context must be a positive integer")
387 print("Context must be a positive integer")
386 except (TypeError, ValueError):
388 except (TypeError, ValueError):
387 print("Context must be a positive integer")
389 print("Context must be a positive integer")
388 try:
390 try:
389 import reprlib # Py 3
391 import reprlib # Py 3
390 except ImportError:
392 except ImportError:
391 import repr as reprlib # Py 2
393 import repr as reprlib # Py 2
392
394
393 ret = []
395 ret = []
394
396
395 Colors = self.color_scheme_table.active_colors
397 Colors = self.color_scheme_table.active_colors
396 ColorsNormal = Colors.Normal
398 ColorsNormal = Colors.Normal
397 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
399 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
398 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
400 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
399 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
401 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
400 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
402 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
401 ColorsNormal)
403 ColorsNormal)
402
404
403 frame, lineno = frame_lineno
405 frame, lineno = frame_lineno
404
406
405 return_value = ''
407 return_value = ''
406 if '__return__' in frame.f_locals:
408 if '__return__' in frame.f_locals:
407 rv = frame.f_locals['__return__']
409 rv = frame.f_locals['__return__']
408 #return_value += '->'
410 #return_value += '->'
409 return_value += reprlib.repr(rv) + '\n'
411 return_value += reprlib.repr(rv) + '\n'
410 ret.append(return_value)
412 ret.append(return_value)
411
413
412 #s = filename + '(' + `lineno` + ')'
414 #s = filename + '(' + `lineno` + ')'
413 filename = self.canonic(frame.f_code.co_filename)
415 filename = self.canonic(frame.f_code.co_filename)
414 link = tpl_link % py3compat.cast_unicode(filename)
416 link = tpl_link % py3compat.cast_unicode(filename)
415
417
416 if frame.f_code.co_name:
418 if frame.f_code.co_name:
417 func = frame.f_code.co_name
419 func = frame.f_code.co_name
418 else:
420 else:
419 func = "<lambda>"
421 func = "<lambda>"
420
422
421 call = ''
423 call = ''
422 if func != '?':
424 if func != '?':
423 if '__args__' in frame.f_locals:
425 if '__args__' in frame.f_locals:
424 args = reprlib.repr(frame.f_locals['__args__'])
426 args = reprlib.repr(frame.f_locals['__args__'])
425 else:
427 else:
426 args = '()'
428 args = '()'
427 call = tpl_call % (func, args)
429 call = tpl_call % (func, args)
428
430
429 # The level info should be generated in the same format pdb uses, to
431 # The level info should be generated in the same format pdb uses, to
430 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
432 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
431 if frame is self.curframe:
433 if frame is self.curframe:
432 ret.append('> ')
434 ret.append('> ')
433 else:
435 else:
434 ret.append(' ')
436 ret.append(' ')
435 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
437 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
436
438
437 start = lineno - 1 - context//2
439 start = lineno - 1 - context//2
438 lines = ulinecache.getlines(filename)
440 lines = ulinecache.getlines(filename)
439 start = min(start, len(lines) - context)
441 start = min(start, len(lines) - context)
440 start = max(start, 0)
442 start = max(start, 0)
441 lines = lines[start : start + context]
443 lines = lines[start : start + context]
442
444
443 for i,line in enumerate(lines):
445 for i,line in enumerate(lines):
444 show_arrow = (start + 1 + i == lineno)
446 show_arrow = (start + 1 + i == lineno)
445 linetpl = (frame is self.curframe or show_arrow) \
447 linetpl = (frame is self.curframe or show_arrow) \
446 and tpl_line_em \
448 and tpl_line_em \
447 or tpl_line
449 or tpl_line
448 ret.append(self.__format_line(linetpl, filename,
450 ret.append(self.__format_line(linetpl, filename,
449 start + 1 + i, line,
451 start + 1 + i, line,
450 arrow = show_arrow) )
452 arrow = show_arrow) )
451 return ''.join(ret)
453 return ''.join(ret)
452
454
453 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
455 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
454 bp_mark = ""
456 bp_mark = ""
455 bp_mark_color = ""
457 bp_mark_color = ""
456
458
457 scheme = self.color_scheme_table.active_scheme_name
459 scheme = self.color_scheme_table.active_scheme_name
458 new_line, err = self.parser.format2(line, 'str', scheme)
460 new_line, err = self.parser.format2(line, 'str', scheme)
459 if not err: line = new_line
461 if not err: line = new_line
460
462
461 bp = None
463 bp = None
462 if lineno in self.get_file_breaks(filename):
464 if lineno in self.get_file_breaks(filename):
463 bps = self.get_breaks(filename, lineno)
465 bps = self.get_breaks(filename, lineno)
464 bp = bps[-1]
466 bp = bps[-1]
465
467
466 if bp:
468 if bp:
467 Colors = self.color_scheme_table.active_colors
469 Colors = self.color_scheme_table.active_colors
468 bp_mark = str(bp.number)
470 bp_mark = str(bp.number)
469 bp_mark_color = Colors.breakpoint_enabled
471 bp_mark_color = Colors.breakpoint_enabled
470 if not bp.enabled:
472 if not bp.enabled:
471 bp_mark_color = Colors.breakpoint_disabled
473 bp_mark_color = Colors.breakpoint_disabled
472
474
473 numbers_width = 7
475 numbers_width = 7
474 if arrow:
476 if arrow:
475 # This is the line with the error
477 # This is the line with the error
476 pad = numbers_width - len(str(lineno)) - len(bp_mark)
478 pad = numbers_width - len(str(lineno)) - len(bp_mark)
477 num = '%s%s' % (make_arrow(pad), str(lineno))
479 num = '%s%s' % (make_arrow(pad), str(lineno))
478 else:
480 else:
479 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
481 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
480
482
481 return tpl_line % (bp_mark_color + bp_mark, num, line)
483 return tpl_line % (bp_mark_color + bp_mark, num, line)
482
484
483
485
484 def print_list_lines(self, filename, first, last):
486 def print_list_lines(self, filename, first, last):
485 """The printing (as opposed to the parsing part of a 'list'
487 """The printing (as opposed to the parsing part of a 'list'
486 command."""
488 command."""
487 try:
489 try:
488 Colors = self.color_scheme_table.active_colors
490 Colors = self.color_scheme_table.active_colors
489 ColorsNormal = Colors.Normal
491 ColorsNormal = Colors.Normal
490 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
492 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
491 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
493 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
492 src = []
494 src = []
493 if filename == "<string>" and hasattr(self, "_exec_filename"):
495 if filename == "<string>" and hasattr(self, "_exec_filename"):
494 filename = self._exec_filename
496 filename = self._exec_filename
495
497
496 for lineno in range(first, last+1):
498 for lineno in range(first, last+1):
497 line = ulinecache.getline(filename, lineno)
499 line = ulinecache.getline(filename, lineno)
498 if not line:
500 if not line:
499 break
501 break
500
502
501 if lineno == self.curframe.f_lineno:
503 if lineno == self.curframe.f_lineno:
502 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
504 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
503 else:
505 else:
504 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
506 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
505
507
506 src.append(line)
508 src.append(line)
507 self.lineno = lineno
509 self.lineno = lineno
508
510
509 print(''.join(src))
511 print(''.join(src))
510
512
511 except KeyboardInterrupt:
513 except KeyboardInterrupt:
512 pass
514 pass
513
515
514 def do_list(self, arg):
516 def do_list(self, arg):
515 self.lastcmd = 'list'
517 self.lastcmd = 'list'
516 last = None
518 last = None
517 if arg:
519 if arg:
518 try:
520 try:
519 x = eval(arg, {}, {})
521 x = eval(arg, {}, {})
520 if type(x) == type(()):
522 if type(x) == type(()):
521 first, last = x
523 first, last = x
522 first = int(first)
524 first = int(first)
523 last = int(last)
525 last = int(last)
524 if last < first:
526 if last < first:
525 # Assume it's a count
527 # Assume it's a count
526 last = first + last
528 last = first + last
527 else:
529 else:
528 first = max(1, int(x) - 5)
530 first = max(1, int(x) - 5)
529 except:
531 except:
530 print('*** Error in argument:', repr(arg))
532 print('*** Error in argument:', repr(arg))
531 return
533 return
532 elif self.lineno is None:
534 elif self.lineno is None:
533 first = max(1, self.curframe.f_lineno - 5)
535 first = max(1, self.curframe.f_lineno - 5)
534 else:
536 else:
535 first = self.lineno + 1
537 first = self.lineno + 1
536 if last is None:
538 if last is None:
537 last = first + 10
539 last = first + 10
538 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
540 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
539
541
540 # vds: >>
542 # vds: >>
541 lineno = first
543 lineno = first
542 filename = self.curframe.f_code.co_filename
544 filename = self.curframe.f_code.co_filename
543 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
545 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
544 # vds: <<
546 # vds: <<
545
547
546 do_l = do_list
548 do_l = do_list
547
549
548 def getsourcelines(self, obj):
550 def getsourcelines(self, obj):
549 lines, lineno = inspect.findsource(obj)
551 lines, lineno = inspect.findsource(obj)
550 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
552 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
551 # must be a module frame: do not try to cut a block out of it
553 # must be a module frame: do not try to cut a block out of it
552 return lines, 1
554 return lines, 1
553 elif inspect.ismodule(obj):
555 elif inspect.ismodule(obj):
554 return lines, 1
556 return lines, 1
555 return inspect.getblock(lines[lineno:]), lineno+1
557 return inspect.getblock(lines[lineno:]), lineno+1
556
558
557 def do_longlist(self, arg):
559 def do_longlist(self, arg):
558 self.lastcmd = 'longlist'
560 self.lastcmd = 'longlist'
559 try:
561 try:
560 lines, lineno = self.getsourcelines(self.curframe)
562 lines, lineno = self.getsourcelines(self.curframe)
561 except OSError as err:
563 except OSError as err:
562 self.error(err)
564 self.error(err)
563 return
565 return
564 last = lineno + len(lines)
566 last = lineno + len(lines)
565 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
567 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
566 do_ll = do_longlist
568 do_ll = do_longlist
567
569
568 def do_pdef(self, arg):
570 def do_pdef(self, arg):
569 """Print the call signature for any callable object.
571 """Print the call signature for any callable object.
570
572
571 The debugger interface to %pdef"""
573 The debugger interface to %pdef"""
572 namespaces = [('Locals', self.curframe.f_locals),
574 namespaces = [('Locals', self.curframe.f_locals),
573 ('Globals', self.curframe.f_globals)]
575 ('Globals', self.curframe.f_globals)]
574 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
576 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
575
577
576 def do_pdoc(self, arg):
578 def do_pdoc(self, arg):
577 """Print the docstring for an object.
579 """Print the docstring for an object.
578
580
579 The debugger interface to %pdoc."""
581 The debugger interface to %pdoc."""
580 namespaces = [('Locals', self.curframe.f_locals),
582 namespaces = [('Locals', self.curframe.f_locals),
581 ('Globals', self.curframe.f_globals)]
583 ('Globals', self.curframe.f_globals)]
582 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
584 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
583
585
584 def do_pfile(self, arg):
586 def do_pfile(self, arg):
585 """Print (or run through pager) the file where an object is defined.
587 """Print (or run through pager) the file where an object is defined.
586
588
587 The debugger interface to %pfile.
589 The debugger interface to %pfile.
588 """
590 """
589 namespaces = [('Locals', self.curframe.f_locals),
591 namespaces = [('Locals', self.curframe.f_locals),
590 ('Globals', self.curframe.f_globals)]
592 ('Globals', self.curframe.f_globals)]
591 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
593 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
592
594
593 def do_pinfo(self, arg):
595 def do_pinfo(self, arg):
594 """Provide detailed information about an object.
596 """Provide detailed information about an object.
595
597
596 The debugger interface to %pinfo, i.e., obj?."""
598 The debugger interface to %pinfo, i.e., obj?."""
597 namespaces = [('Locals', self.curframe.f_locals),
599 namespaces = [('Locals', self.curframe.f_locals),
598 ('Globals', self.curframe.f_globals)]
600 ('Globals', self.curframe.f_globals)]
599 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
601 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
600
602
601 def do_pinfo2(self, arg):
603 def do_pinfo2(self, arg):
602 """Provide extra detailed information about an object.
604 """Provide extra detailed information about an object.
603
605
604 The debugger interface to %pinfo2, i.e., obj??."""
606 The debugger interface to %pinfo2, i.e., obj??."""
605 namespaces = [('Locals', self.curframe.f_locals),
607 namespaces = [('Locals', self.curframe.f_locals),
606 ('Globals', self.curframe.f_globals)]
608 ('Globals', self.curframe.f_globals)]
607 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
609 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
608
610
609 def do_psource(self, arg):
611 def do_psource(self, arg):
610 """Print (or run through pager) the source code for an object."""
612 """Print (or run through pager) the source code for an object."""
611 namespaces = [('Locals', self.curframe.f_locals),
613 namespaces = [('Locals', self.curframe.f_locals),
612 ('Globals', self.curframe.f_globals)]
614 ('Globals', self.curframe.f_globals)]
613 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
615 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
614
616
615 if sys.version_info > (3, ):
617 if sys.version_info > (3, ):
616 def do_where(self, arg):
618 def do_where(self, arg):
617 """w(here)
619 """w(here)
618 Print a stack trace, with the most recent frame at the bottom.
620 Print a stack trace, with the most recent frame at the bottom.
619 An arrow indicates the "current frame", which determines the
621 An arrow indicates the "current frame", which determines the
620 context of most commands. 'bt' is an alias for this command.
622 context of most commands. 'bt' is an alias for this command.
621
623
622 Take a number as argument as an (optional) number of context line to
624 Take a number as argument as an (optional) number of context line to
623 print"""
625 print"""
624 if arg:
626 if arg:
625 context = int(arg)
627 context = int(arg)
626 self.print_stack_trace(context)
628 self.print_stack_trace(context)
627 else:
629 else:
628 self.print_stack_trace()
630 self.print_stack_trace()
629
631
630 do_w = do_where
632 do_w = do_where
@@ -1,481 +1,484 b''
1 """IPython terminal interface using prompt_toolkit in place of readline"""
1 """IPython terminal interface using prompt_toolkit in place of readline"""
2 from __future__ import print_function
2 from __future__ import print_function
3
3
4 import os
4 import os
5 import sys
5 import sys
6 import signal
6 import signal
7 import unicodedata
7 import unicodedata
8 from warnings import warn
8 from warnings import warn
9 from wcwidth import wcwidth
9 from wcwidth import wcwidth
10
10
11 from IPython.core.error import TryNext
11 from IPython.core.error import TryNext
12 from IPython.core.interactiveshell import InteractiveShell
12 from IPython.core.interactiveshell import InteractiveShell
13 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
13 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
14 from IPython.utils.terminal import toggle_set_term_title, set_term_title
14 from IPython.utils.terminal import toggle_set_term_title, set_term_title
15 from IPython.utils.process import abbrev_cwd
15 from IPython.utils.process import abbrev_cwd
16 from traitlets import Bool, Unicode, Dict, Integer, observe
16 from traitlets import Bool, Unicode, Dict, Integer, observe
17
17
18 from prompt_toolkit.completion import Completer, Completion
18 from prompt_toolkit.completion import Completer, Completion
19 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
19 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
20 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone
20 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone
21 from prompt_toolkit.history import InMemoryHistory
21 from prompt_toolkit.history import InMemoryHistory
22 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
22 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
23 from prompt_toolkit.interface import CommandLineInterface
23 from prompt_toolkit.interface import CommandLineInterface
24 from prompt_toolkit.key_binding.manager import KeyBindingManager
24 from prompt_toolkit.key_binding.manager import KeyBindingManager
25 from prompt_toolkit.keys import Keys
25 from prompt_toolkit.keys import Keys
26 from prompt_toolkit.layout.lexers import Lexer
26 from prompt_toolkit.layout.lexers import Lexer
27 from prompt_toolkit.layout.lexers import PygmentsLexer
27 from prompt_toolkit.layout.lexers import PygmentsLexer
28 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
28 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
29 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
29 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
30
30
31 from pygments.styles import get_style_by_name, get_all_styles
31 from pygments.styles import get_style_by_name, get_all_styles
32 from pygments.lexers import Python3Lexer, BashLexer, PythonLexer
32 from pygments.lexers import Python3Lexer, BashLexer, PythonLexer
33 from pygments.token import Token
33 from pygments.token import Token
34
34
35 from .pt_inputhooks import get_inputhook_func
35 from .pt_inputhooks import get_inputhook_func
36 from .interactiveshell import get_default_editor, TerminalMagics
36 from .interactiveshell import get_default_editor, TerminalMagics
37
37
38
38
39 class IPythonPTCompleter(Completer):
39 class IPythonPTCompleter(Completer):
40 """Adaptor to provide IPython completions to prompt_toolkit"""
40 """Adaptor to provide IPython completions to prompt_toolkit"""
41 def __init__(self, ipy_completer):
41 def __init__(self, ipy_completer):
42 self.ipy_completer = ipy_completer
42 self.ipy_completer = ipy_completer
43
43
44 def get_completions(self, document, complete_event):
44 def get_completions(self, document, complete_event):
45 if not document.current_line.strip():
45 if not document.current_line.strip():
46 return
46 return
47
47
48 used, matches = self.ipy_completer.complete(
48 used, matches = self.ipy_completer.complete(
49 line_buffer=document.current_line,
49 line_buffer=document.current_line,
50 cursor_pos=document.cursor_position_col
50 cursor_pos=document.cursor_position_col
51 )
51 )
52 start_pos = -len(used)
52 start_pos = -len(used)
53 for m in matches:
53 for m in matches:
54 m = unicodedata.normalize('NFC', m)
54 m = unicodedata.normalize('NFC', m)
55
55
56 # When the first character of the completion has a zero length,
56 # When the first character of the completion has a zero length,
57 # then it's probably a decomposed unicode character. E.g. caused by
57 # then it's probably a decomposed unicode character. E.g. caused by
58 # the "\dot" completion. Try to compose again with the previous
58 # the "\dot" completion. Try to compose again with the previous
59 # character.
59 # character.
60 if wcwidth(m[0]) == 0:
60 if wcwidth(m[0]) == 0:
61 if document.cursor_position + start_pos > 0:
61 if document.cursor_position + start_pos > 0:
62 char_before = document.text[document.cursor_position + start_pos - 1]
62 char_before = document.text[document.cursor_position + start_pos - 1]
63 m = unicodedata.normalize('NFC', char_before + m)
63 m = unicodedata.normalize('NFC', char_before + m)
64
64
65 # Yield the modified completion instead, if this worked.
65 # Yield the modified completion instead, if this worked.
66 if wcwidth(m[0:1]) == 1:
66 if wcwidth(m[0:1]) == 1:
67 yield Completion(m, start_position=start_pos - 1)
67 yield Completion(m, start_position=start_pos - 1)
68 continue
68 continue
69
69
70 # TODO: Use Jedi to determine meta_text
70 # TODO: Use Jedi to determine meta_text
71 # (Jedi currently has a bug that results in incorrect information.)
71 # (Jedi currently has a bug that results in incorrect information.)
72 # meta_text = ''
72 # meta_text = ''
73 # yield Completion(m, start_position=start_pos,
73 # yield Completion(m, start_position=start_pos,
74 # display_meta=meta_text)
74 # display_meta=meta_text)
75 yield Completion(m, start_position=start_pos)
75 yield Completion(m, start_position=start_pos)
76
76
77 class IPythonPTLexer(Lexer):
77 class IPythonPTLexer(Lexer):
78 """
78 """
79 Wrapper around PythonLexer and BashLexer.
79 Wrapper around PythonLexer and BashLexer.
80 """
80 """
81 def __init__(self):
81 def __init__(self):
82 self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer)
82 self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer)
83 self.shell_lexer = PygmentsLexer(BashLexer)
83 self.shell_lexer = PygmentsLexer(BashLexer)
84
84
85 def lex_document(self, cli, document):
85 def lex_document(self, cli, document):
86 if document.text.startswith('!'):
86 if document.text.startswith('!'):
87 return self.shell_lexer.lex_document(cli, document)
87 return self.shell_lexer.lex_document(cli, document)
88 else:
88 else:
89 return self.python_lexer.lex_document(cli, document)
89 return self.python_lexer.lex_document(cli, document)
90
90
91
91
92 class TerminalInteractiveShell(InteractiveShell):
92 class TerminalInteractiveShell(InteractiveShell):
93 colors_force = True
93 colors_force = True
94
94
95 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
95 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
96 'to reserve for the completion menu'
96 'to reserve for the completion menu'
97 ).tag(config=True)
97 ).tag(config=True)
98
98
99 def _space_for_menu_changed(self, old, new):
99 def _space_for_menu_changed(self, old, new):
100 self._update_layout()
100 self._update_layout()
101
101
102 pt_cli = None
102 pt_cli = None
103 debugger_history = None
103
104
104 autoedit_syntax = Bool(False,
105 autoedit_syntax = Bool(False,
105 help="auto editing of files with syntax errors.",
106 help="auto editing of files with syntax errors.",
106 ).tag(config=True)
107 ).tag(config=True)
107
108
108
109
109 confirm_exit = Bool(True,
110 confirm_exit = Bool(True,
110 help="""
111 help="""
111 Set to confirm when you try to exit IPython with an EOF (Control-D
112 Set to confirm when you try to exit IPython with an EOF (Control-D
112 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
113 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
113 you can force a direct exit without any confirmation.""",
114 you can force a direct exit without any confirmation.""",
114 ).tag(config=True)
115 ).tag(config=True)
115
116
116 editing_mode = Unicode('emacs',
117 editing_mode = Unicode('emacs',
117 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
118 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
118 ).tag(config=True)
119 ).tag(config=True)
119
120
120 mouse_support = Bool(False,
121 mouse_support = Bool(False,
121 help="Enable mouse support in the prompt"
122 help="Enable mouse support in the prompt"
122 ).tag(config=True)
123 ).tag(config=True)
123
124
124 highlighting_style = Unicode('default',
125 highlighting_style = Unicode('default',
125 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
126 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
126 ).tag(config=True)
127 ).tag(config=True)
127
128
128
129
129 @observe('highlighting_style')
130 @observe('highlighting_style')
130 def _highlighting_style_changed(self, change):
131 def _highlighting_style_changed(self, change):
131 self._style = self._make_style_from_name(self.highlighting_style)
132 self._style = self._make_style_from_name(self.highlighting_style)
132
133
133 highlighting_style_overrides = Dict(
134 highlighting_style_overrides = Dict(
134 help="Override highlighting format for specific tokens"
135 help="Override highlighting format for specific tokens"
135 ).tag(config=True)
136 ).tag(config=True)
136
137
137 editor = Unicode(get_default_editor(),
138 editor = Unicode(get_default_editor(),
138 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
139 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
139 ).tag(config=True)
140 ).tag(config=True)
140
141
141 term_title = Bool(True,
142 term_title = Bool(True,
142 help="Automatically set the terminal title"
143 help="Automatically set the terminal title"
143 ).tag(config=True)
144 ).tag(config=True)
144
145
145 display_completions_in_columns = Bool(False,
146 display_completions_in_columns = Bool(False,
146 help="Display a multi column completion menu.",
147 help="Display a multi column completion menu.",
147 ).tag(config=True)
148 ).tag(config=True)
148
149
149 highlight_matching_brackets = Bool(True,
150 highlight_matching_brackets = Bool(True,
150 help="Highlight matching brackets .",
151 help="Highlight matching brackets .",
151 ).tag(config=True)
152 ).tag(config=True)
152
153
153 @observe('term_title')
154 @observe('term_title')
154 def init_term_title(self, change=None):
155 def init_term_title(self, change=None):
155 # Enable or disable the terminal title.
156 # Enable or disable the terminal title.
156 if self.term_title:
157 if self.term_title:
157 toggle_set_term_title(True)
158 toggle_set_term_title(True)
158 set_term_title('IPython: ' + abbrev_cwd())
159 set_term_title('IPython: ' + abbrev_cwd())
159 else:
160 else:
160 toggle_set_term_title(False)
161 toggle_set_term_title(False)
161
162
162 def get_prompt_tokens(self, cli):
163 def get_prompt_tokens(self, cli):
163 return [
164 return [
164 (Token.Prompt, 'In ['),
165 (Token.Prompt, 'In ['),
165 (Token.PromptNum, str(self.execution_count)),
166 (Token.PromptNum, str(self.execution_count)),
166 (Token.Prompt, ']: '),
167 (Token.Prompt, ']: '),
167 ]
168 ]
168
169
169 def get_continuation_tokens(self, cli, width):
170 def get_continuation_tokens(self, cli, width):
170 return [
171 return [
171 (Token.Prompt, (' ' * (width - 5)) + '...: '),
172 (Token.Prompt, (' ' * (width - 5)) + '...: '),
172 ]
173 ]
173
174
174 def init_prompt_toolkit_cli(self):
175 def init_prompt_toolkit_cli(self):
175 if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty():
176 if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty():
176 # Fall back to plain non-interactive output for tests.
177 # Fall back to plain non-interactive output for tests.
177 # This is very limited, and only accepts a single line.
178 # This is very limited, and only accepts a single line.
178 def prompt():
179 def prompt():
179 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
180 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
180 self.prompt_for_code = prompt
181 self.prompt_for_code = prompt
181 return
182 return
182
183
183 kbmanager = KeyBindingManager.for_prompt()
184 kbmanager = KeyBindingManager.for_prompt()
184 insert_mode = ViInsertMode() | EmacsInsertMode()
185 insert_mode = ViInsertMode() | EmacsInsertMode()
185 # Ctrl+J == Enter, seemingly
186 # Ctrl+J == Enter, seemingly
186 @kbmanager.registry.add_binding(Keys.ControlJ,
187 @kbmanager.registry.add_binding(Keys.ControlJ,
187 filter=(HasFocus(DEFAULT_BUFFER)
188 filter=(HasFocus(DEFAULT_BUFFER)
188 & ~HasSelection()
189 & ~HasSelection()
189 & insert_mode
190 & insert_mode
190 ))
191 ))
191 def _(event):
192 def _(event):
192 b = event.current_buffer
193 b = event.current_buffer
193 d = b.document
194 d = b.document
194 if not (d.on_last_line or d.cursor_position_row >= d.line_count
195 if not (d.on_last_line or d.cursor_position_row >= d.line_count
195 - d.empty_line_count_at_the_end()):
196 - d.empty_line_count_at_the_end()):
196 b.newline()
197 b.newline()
197 return
198 return
198
199
199 status, indent = self.input_splitter.check_complete(d.text)
200 status, indent = self.input_splitter.check_complete(d.text)
200
201
201 if (status != 'incomplete') and b.accept_action.is_returnable:
202 if (status != 'incomplete') and b.accept_action.is_returnable:
202 b.accept_action.validate_and_handle(event.cli, b)
203 b.accept_action.validate_and_handle(event.cli, b)
203 else:
204 else:
204 b.insert_text('\n' + (' ' * (indent or 0)))
205 b.insert_text('\n' + (' ' * (indent or 0)))
205
206
206 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
207 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
207 def _reset_buffer(event):
208 def _reset_buffer(event):
208 event.current_buffer.reset()
209 event.current_buffer.reset()
209
210
210 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
211 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
211 def _reset_search_buffer(event):
212 def _reset_search_buffer(event):
212 if event.current_buffer.document.text:
213 if event.current_buffer.document.text:
213 event.current_buffer.reset()
214 event.current_buffer.reset()
214 else:
215 else:
215 event.cli.push_focus(DEFAULT_BUFFER)
216 event.cli.push_focus(DEFAULT_BUFFER)
216
217
217 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
218 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
218
219
219 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
220 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
220 def _suspend_to_bg(event):
221 def _suspend_to_bg(event):
221 event.cli.suspend_to_background()
222 event.cli.suspend_to_background()
222
223
223 @Condition
224 @Condition
224 def cursor_in_leading_ws(cli):
225 def cursor_in_leading_ws(cli):
225 before = cli.application.buffer.document.current_line_before_cursor
226 before = cli.application.buffer.document.current_line_before_cursor
226 return (not before) or before.isspace()
227 return (not before) or before.isspace()
227
228
228 # Ctrl+I == Tab
229 # Ctrl+I == Tab
229 @kbmanager.registry.add_binding(Keys.ControlI,
230 @kbmanager.registry.add_binding(Keys.ControlI,
230 filter=(HasFocus(DEFAULT_BUFFER)
231 filter=(HasFocus(DEFAULT_BUFFER)
231 & ~HasSelection()
232 & ~HasSelection()
232 & insert_mode
233 & insert_mode
233 & cursor_in_leading_ws
234 & cursor_in_leading_ws
234 ))
235 ))
235 def _indent_buffer(event):
236 def _indent_buffer(event):
236 event.current_buffer.insert_text(' ' * 4)
237 event.current_buffer.insert_text(' ' * 4)
237
238
238 # Pre-populate history from IPython's history database
239 # Pre-populate history from IPython's history database
239 history = InMemoryHistory()
240 history = InMemoryHistory()
240 last_cell = u""
241 last_cell = u""
241 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
242 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
242 include_latest=True):
243 include_latest=True):
243 # Ignore blank lines and consecutive duplicates
244 # Ignore blank lines and consecutive duplicates
244 cell = cell.rstrip()
245 cell = cell.rstrip()
245 if cell and (cell != last_cell):
246 if cell and (cell != last_cell):
246 history.append(cell)
247 history.append(cell)
247
248
248 self._style = self._make_style_from_name(self.highlighting_style)
249 self._style = self._make_style_from_name(self.highlighting_style)
249 style = DynamicStyle(lambda: self._style)
250 style = DynamicStyle(lambda: self._style)
250
251
251 editing_mode = getattr(EditingMode, self.editing_mode.upper())
252 editing_mode = getattr(EditingMode, self.editing_mode.upper())
252
253
253 self._app = create_prompt_application(
254 self._app = create_prompt_application(
254 editing_mode=editing_mode,
255 editing_mode=editing_mode,
255 key_bindings_registry=kbmanager.registry,
256 key_bindings_registry=kbmanager.registry,
256 history=history,
257 history=history,
257 completer=IPythonPTCompleter(self.Completer),
258 completer=IPythonPTCompleter(self.Completer),
258 enable_history_search=True,
259 enable_history_search=True,
259 style=style,
260 style=style,
260 mouse_support=self.mouse_support,
261 mouse_support=self.mouse_support,
261 **self._layout_options()
262 **self._layout_options()
262 )
263 )
263 self._eventloop = create_eventloop(self.inputhook)
264 self._eventloop = create_eventloop(self.inputhook)
264 self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop)
265 self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop)
265
266
266 def _make_style_from_name(self, name):
267 def _make_style_from_name(self, name):
267 """
268 """
268 Small wrapper that make an IPython compatible style from a style name
269 Small wrapper that make an IPython compatible style from a style name
269
270
270 We need that to add style for prompt ... etc.
271 We need that to add style for prompt ... etc.
271 """
272 """
272 style_cls = get_style_by_name(name)
273 style_cls = get_style_by_name(name)
273 style_overrides = {
274 style_overrides = {
274 Token.Prompt: '#009900',
275 Token.Prompt: '#009900',
275 Token.PromptNum: '#00ff00 bold',
276 Token.PromptNum: '#00ff00 bold',
276 }
277 }
277 if name == 'default':
278 if name == 'default':
278 style_cls = get_style_by_name('default')
279 style_cls = get_style_by_name('default')
279 # The default theme needs to be visible on both a dark background
280 # The default theme needs to be visible on both a dark background
280 # and a light background, because we can't tell what the terminal
281 # and a light background, because we can't tell what the terminal
281 # looks like. These tweaks to the default theme help with that.
282 # looks like. These tweaks to the default theme help with that.
282 style_overrides.update({
283 style_overrides.update({
283 Token.Number: '#007700',
284 Token.Number: '#007700',
284 Token.Operator: 'noinherit',
285 Token.Operator: 'noinherit',
285 Token.String: '#BB6622',
286 Token.String: '#BB6622',
286 Token.Name.Function: '#2080D0',
287 Token.Name.Function: '#2080D0',
287 Token.Name.Class: 'bold #2080D0',
288 Token.Name.Class: 'bold #2080D0',
288 Token.Name.Namespace: 'bold #2080D0',
289 Token.Name.Namespace: 'bold #2080D0',
289 })
290 })
290 style_overrides.update(self.highlighting_style_overrides)
291 style_overrides.update(self.highlighting_style_overrides)
291 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
292 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
292 style_dict=style_overrides)
293 style_dict=style_overrides)
293
294
294 return style
295 return style
295
296
296 def _layout_options(self):
297 def _layout_options(self):
297 """
298 """
298 Return the current layout option for the current Terminal InteractiveShell
299 Return the current layout option for the current Terminal InteractiveShell
299 """
300 """
300 return {
301 return {
301 'lexer':IPythonPTLexer(),
302 'lexer':IPythonPTLexer(),
302 'reserve_space_for_menu':self.space_for_menu,
303 'reserve_space_for_menu':self.space_for_menu,
303 'get_prompt_tokens':self.get_prompt_tokens,
304 'get_prompt_tokens':self.get_prompt_tokens,
304 'get_continuation_tokens':self.get_continuation_tokens,
305 'get_continuation_tokens':self.get_continuation_tokens,
305 'multiline':True,
306 'multiline':True,
306 'display_completions_in_columns': self.display_completions_in_columns,
307 'display_completions_in_columns': self.display_completions_in_columns,
307
308
308 # Highlight matching brackets, but only when this setting is
309 # Highlight matching brackets, but only when this setting is
309 # enabled, and only when the DEFAULT_BUFFER has the focus.
310 # enabled, and only when the DEFAULT_BUFFER has the focus.
310 'extra_input_processors': [ConditionalProcessor(
311 'extra_input_processors': [ConditionalProcessor(
311 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
312 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
312 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
313 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
313 Condition(lambda cli: self.highlight_matching_brackets))],
314 Condition(lambda cli: self.highlight_matching_brackets))],
314 }
315 }
315
316
316 def _update_layout(self):
317 def _update_layout(self):
317 """
318 """
318 Ask for a re computation of the application layout, if for example ,
319 Ask for a re computation of the application layout, if for example ,
319 some configuration options have changed.
320 some configuration options have changed.
320 """
321 """
321 self._app.layout = create_prompt_layout(**self._layout_options())
322 self._app.layout = create_prompt_layout(**self._layout_options())
322
323
323 def prompt_for_code(self):
324 def prompt_for_code(self):
324 document = self.pt_cli.run(
325 document = self.pt_cli.run(
325 pre_run=self.pre_prompt, reset_current_buffer=True)
326 pre_run=self.pre_prompt, reset_current_buffer=True)
326 return document.text
327 return document.text
327
328
328 def init_io(self):
329 def init_io(self):
329 if sys.platform not in {'win32', 'cli'}:
330 if sys.platform not in {'win32', 'cli'}:
330 return
331 return
331
332
332 import colorama
333 import colorama
333 colorama.init()
334 colorama.init()
334
335
335 # For some reason we make these wrappers around stdout/stderr.
336 # For some reason we make these wrappers around stdout/stderr.
336 # For now, we need to reset them so all output gets coloured.
337 # For now, we need to reset them so all output gets coloured.
337 # https://github.com/ipython/ipython/issues/8669
338 # https://github.com/ipython/ipython/issues/8669
338 from IPython.utils import io
339 from IPython.utils import io
339 io.stdout = io.IOStream(sys.stdout)
340 io.stdout = io.IOStream(sys.stdout)
340 io.stderr = io.IOStream(sys.stderr)
341 io.stderr = io.IOStream(sys.stderr)
341
342
342 def init_magics(self):
343 def init_magics(self):
343 super(TerminalInteractiveShell, self).init_magics()
344 super(TerminalInteractiveShell, self).init_magics()
344 self.register_magics(TerminalMagics)
345 self.register_magics(TerminalMagics)
345
346
346 def init_alias(self):
347 def init_alias(self):
347 # The parent class defines aliases that can be safely used with any
348 # The parent class defines aliases that can be safely used with any
348 # frontend.
349 # frontend.
349 super(TerminalInteractiveShell, self).init_alias()
350 super(TerminalInteractiveShell, self).init_alias()
350
351
351 # Now define aliases that only make sense on the terminal, because they
352 # Now define aliases that only make sense on the terminal, because they
352 # need direct access to the console in a way that we can't emulate in
353 # need direct access to the console in a way that we can't emulate in
353 # GUI or web frontend
354 # GUI or web frontend
354 if os.name == 'posix':
355 if os.name == 'posix':
355 for cmd in ['clear', 'more', 'less', 'man']:
356 for cmd in ['clear', 'more', 'less', 'man']:
356 self.alias_manager.soft_define_alias(cmd, cmd)
357 self.alias_manager.soft_define_alias(cmd, cmd)
357
358
358
359
359 def __init__(self, *args, **kwargs):
360 def __init__(self, *args, **kwargs):
360 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
361 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
361 self.init_prompt_toolkit_cli()
362 self.init_prompt_toolkit_cli()
362 self.init_term_title()
363 self.init_term_title()
363 self.keep_running = True
364 self.keep_running = True
364
365
366 self.debugger_history = InMemoryHistory()
367
365 def ask_exit(self):
368 def ask_exit(self):
366 self.keep_running = False
369 self.keep_running = False
367
370
368 rl_next_input = None
371 rl_next_input = None
369
372
370 def pre_prompt(self):
373 def pre_prompt(self):
371 if self.rl_next_input:
374 if self.rl_next_input:
372 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
375 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
373 self.rl_next_input = None
376 self.rl_next_input = None
374
377
375 def interact(self):
378 def interact(self):
376 while self.keep_running:
379 while self.keep_running:
377 print(self.separate_in, end='')
380 print(self.separate_in, end='')
378
381
379 try:
382 try:
380 code = self.prompt_for_code()
383 code = self.prompt_for_code()
381 except EOFError:
384 except EOFError:
382 if (not self.confirm_exit) \
385 if (not self.confirm_exit) \
383 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
386 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
384 self.ask_exit()
387 self.ask_exit()
385
388
386 else:
389 else:
387 if code:
390 if code:
388 self.run_cell(code, store_history=True)
391 self.run_cell(code, store_history=True)
389 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
392 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
390 self.edit_syntax_error()
393 self.edit_syntax_error()
391
394
392 def mainloop(self):
395 def mainloop(self):
393 # An extra layer of protection in case someone mashing Ctrl-C breaks
396 # An extra layer of protection in case someone mashing Ctrl-C breaks
394 # out of our internal code.
397 # out of our internal code.
395 while True:
398 while True:
396 try:
399 try:
397 self.interact()
400 self.interact()
398 break
401 break
399 except KeyboardInterrupt:
402 except KeyboardInterrupt:
400 print("\nKeyboardInterrupt escaped interact()\n")
403 print("\nKeyboardInterrupt escaped interact()\n")
401
404
402 if hasattr(self, '_eventloop'):
405 if hasattr(self, '_eventloop'):
403 self._eventloop.close()
406 self._eventloop.close()
404
407
405 _inputhook = None
408 _inputhook = None
406 def inputhook(self, context):
409 def inputhook(self, context):
407 if self._inputhook is not None:
410 if self._inputhook is not None:
408 self._inputhook(context)
411 self._inputhook(context)
409
412
410 def enable_gui(self, gui=None):
413 def enable_gui(self, gui=None):
411 if gui:
414 if gui:
412 self._inputhook = get_inputhook_func(gui)
415 self._inputhook = get_inputhook_func(gui)
413 else:
416 else:
414 self._inputhook = None
417 self._inputhook = None
415
418
416 # Methods to support auto-editing of SyntaxErrors:
419 # Methods to support auto-editing of SyntaxErrors:
417
420
418 def edit_syntax_error(self):
421 def edit_syntax_error(self):
419 """The bottom half of the syntax error handler called in the main loop.
422 """The bottom half of the syntax error handler called in the main loop.
420
423
421 Loop until syntax error is fixed or user cancels.
424 Loop until syntax error is fixed or user cancels.
422 """
425 """
423
426
424 while self.SyntaxTB.last_syntax_error:
427 while self.SyntaxTB.last_syntax_error:
425 # copy and clear last_syntax_error
428 # copy and clear last_syntax_error
426 err = self.SyntaxTB.clear_err_state()
429 err = self.SyntaxTB.clear_err_state()
427 if not self._should_recompile(err):
430 if not self._should_recompile(err):
428 return
431 return
429 try:
432 try:
430 # may set last_syntax_error again if a SyntaxError is raised
433 # may set last_syntax_error again if a SyntaxError is raised
431 self.safe_execfile(err.filename, self.user_ns)
434 self.safe_execfile(err.filename, self.user_ns)
432 except:
435 except:
433 self.showtraceback()
436 self.showtraceback()
434 else:
437 else:
435 try:
438 try:
436 with open(err.filename) as f:
439 with open(err.filename) as f:
437 # This should be inside a display_trap block and I
440 # This should be inside a display_trap block and I
438 # think it is.
441 # think it is.
439 sys.displayhook(f.read())
442 sys.displayhook(f.read())
440 except:
443 except:
441 self.showtraceback()
444 self.showtraceback()
442
445
443 def _should_recompile(self, e):
446 def _should_recompile(self, e):
444 """Utility routine for edit_syntax_error"""
447 """Utility routine for edit_syntax_error"""
445
448
446 if e.filename in ('<ipython console>', '<input>', '<string>',
449 if e.filename in ('<ipython console>', '<input>', '<string>',
447 '<console>', '<BackgroundJob compilation>',
450 '<console>', '<BackgroundJob compilation>',
448 None):
451 None):
449 return False
452 return False
450 try:
453 try:
451 if (self.autoedit_syntax and
454 if (self.autoedit_syntax and
452 not self.ask_yes_no(
455 not self.ask_yes_no(
453 'Return to editor to correct syntax error? '
456 'Return to editor to correct syntax error? '
454 '[Y/n] ', 'y')):
457 '[Y/n] ', 'y')):
455 return False
458 return False
456 except EOFError:
459 except EOFError:
457 return False
460 return False
458
461
459 def int0(x):
462 def int0(x):
460 try:
463 try:
461 return int(x)
464 return int(x)
462 except TypeError:
465 except TypeError:
463 return 0
466 return 0
464
467
465 # always pass integer line and offset values to editor hook
468 # always pass integer line and offset values to editor hook
466 try:
469 try:
467 self.hooks.fix_error_editor(e.filename,
470 self.hooks.fix_error_editor(e.filename,
468 int0(e.lineno), int0(e.offset),
471 int0(e.lineno), int0(e.offset),
469 e.msg)
472 e.msg)
470 except TryNext:
473 except TryNext:
471 warn('Could not open editor')
474 warn('Could not open editor')
472 return False
475 return False
473 return True
476 return True
474
477
475 # Run !system commands directly, not through pipes, so terminal programs
478 # Run !system commands directly, not through pipes, so terminal programs
476 # work correctly.
479 # work correctly.
477 system = InteractiveShell.system_raw
480 system = InteractiveShell.system_raw
478
481
479
482
480 if __name__ == '__main__':
483 if __name__ == '__main__':
481 TerminalInteractiveShell.instance().interact()
484 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now