##// END OF EJS Templates
handle from ptshell side
Chris -
Show More
@@ -1,685 +1,681 b''
1 """Input handling and transformation machinery.
1 """Input handling and transformation machinery.
2
2
3 The first class in this module, :class:`InputSplitter`, is designed to tell when
3 The first class in this module, :class:`InputSplitter`, is designed to tell when
4 input from a line-oriented frontend is complete and should be executed, and when
4 input from a line-oriented frontend is complete and should be executed, and when
5 the user should be prompted for another line of code instead. The name 'input
5 the user should be prompted for another line of code instead. The name 'input
6 splitter' is largely for historical reasons.
6 splitter' is largely for historical reasons.
7
7
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 with full support for the extended IPython syntax (magics, system calls, etc).
9 with full support for the extended IPython syntax (magics, system calls, etc).
10 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
10 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
11 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
11 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
12 and stores the results.
12 and stores the results.
13
13
14 For more details, see the class docstrings below.
14 For more details, see the class docstrings below.
15 """
15 """
16
16
17 # Copyright (c) IPython Development Team.
17 # Copyright (c) IPython Development Team.
18 # Distributed under the terms of the Modified BSD License.
18 # Distributed under the terms of the Modified BSD License.
19 import ast
19 import ast
20 import codeop
20 import codeop
21 import re
21 import re
22 import sys
22 import sys
23 import warnings
23 import warnings
24
24
25 from IPython.utils.py3compat import cast_unicode
25 from IPython.utils.py3compat import cast_unicode
26 from IPython.core.inputtransformer import (leading_indent,
26 from IPython.core.inputtransformer import (leading_indent,
27 classic_prompt,
27 classic_prompt,
28 ipy_prompt,
28 ipy_prompt,
29 strip_encoding_cookie,
29 strip_encoding_cookie,
30 cellmagic,
30 cellmagic,
31 assemble_logical_lines,
31 assemble_logical_lines,
32 help_end,
32 help_end,
33 escaped_commands,
33 escaped_commands,
34 assign_from_magic,
34 assign_from_magic,
35 assign_from_system,
35 assign_from_system,
36 assemble_python_lines,
36 assemble_python_lines,
37 )
37 )
38
38
39 # These are available in this module for backwards compatibility.
39 # These are available in this module for backwards compatibility.
40 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
40 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
41 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
41 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
42 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
42 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
43
43
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # Utilities
45 # Utilities
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48 # FIXME: These are general-purpose utilities that later can be moved to the
48 # FIXME: These are general-purpose utilities that later can be moved to the
49 # general ward. Kept here for now because we're being very strict about test
49 # general ward. Kept here for now because we're being very strict about test
50 # coverage with this code, and this lets us ensure that we keep 100% coverage
50 # coverage with this code, and this lets us ensure that we keep 100% coverage
51 # while developing.
51 # while developing.
52
52
53 # compiled regexps for autoindent management
53 # compiled regexps for autoindent management
54 dedent_re = re.compile('|'.join([
54 dedent_re = re.compile('|'.join([
55 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
55 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
56 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
56 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
57 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
57 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
58 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
58 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
59 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
59 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
60 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
60 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
61 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
61 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
62 ]))
62 ]))
63 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
63 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
64
64
65 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
65 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
66 # before pure comments
66 # before pure comments
67 comment_line_re = re.compile('^\s*\#')
67 comment_line_re = re.compile('^\s*\#')
68
68
69
69
70 def num_ini_spaces(s):
70 def num_ini_spaces(s):
71 """Return the number of initial spaces in a string.
71 """Return the number of initial spaces in a string.
72
72
73 Note that tabs are counted as a single space. For now, we do *not* support
73 Note that tabs are counted as a single space. For now, we do *not* support
74 mixing of tabs and spaces in the user's input.
74 mixing of tabs and spaces in the user's input.
75
75
76 Parameters
76 Parameters
77 ----------
77 ----------
78 s : string
78 s : string
79
79
80 Returns
80 Returns
81 -------
81 -------
82 n : int
82 n : int
83 """
83 """
84
84
85 ini_spaces = ini_spaces_re.match(s)
85 ini_spaces = ini_spaces_re.match(s)
86 if ini_spaces:
86 if ini_spaces:
87 return ini_spaces.end()
87 return ini_spaces.end()
88 else:
88 else:
89 return 0
89 return 0
90
90
91 def last_blank(src):
91 def last_blank(src):
92 """Determine if the input source ends in a blank.
92 """Determine if the input source ends in a blank.
93
93
94 A blank is either a newline or a line consisting of whitespace.
94 A blank is either a newline or a line consisting of whitespace.
95
95
96 Parameters
96 Parameters
97 ----------
97 ----------
98 src : string
98 src : string
99 A single or multiline string.
99 A single or multiline string.
100 """
100 """
101 if not src: return False
101 if not src: return False
102 ll = src.splitlines()[-1]
102 ll = src.splitlines()[-1]
103 return (ll == '') or ll.isspace()
103 return (ll == '') or ll.isspace()
104
104
105
105
106 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
106 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
107 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
107 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
108
108
109 def last_two_blanks(src):
109 def last_two_blanks(src):
110 """Determine if the input source ends in two blanks.
110 """Determine if the input source ends in two blanks.
111
111
112 A blank is either a newline or a line consisting of whitespace.
112 A blank is either a newline or a line consisting of whitespace.
113
113
114 Parameters
114 Parameters
115 ----------
115 ----------
116 src : string
116 src : string
117 A single or multiline string.
117 A single or multiline string.
118 """
118 """
119 if not src: return False
119 if not src: return False
120 # The logic here is tricky: I couldn't get a regexp to work and pass all
120 # The logic here is tricky: I couldn't get a regexp to work and pass all
121 # the tests, so I took a different approach: split the source by lines,
121 # the tests, so I took a different approach: split the source by lines,
122 # grab the last two and prepend '###\n' as a stand-in for whatever was in
122 # grab the last two and prepend '###\n' as a stand-in for whatever was in
123 # the body before the last two lines. Then, with that structure, it's
123 # the body before the last two lines. Then, with that structure, it's
124 # possible to analyze with two regexps. Not the most elegant solution, but
124 # possible to analyze with two regexps. Not the most elegant solution, but
125 # it works. If anyone tries to change this logic, make sure to validate
125 # it works. If anyone tries to change this logic, make sure to validate
126 # the whole test suite first!
126 # the whole test suite first!
127 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
127 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
128 return (bool(last_two_blanks_re.match(new_src)) or
128 return (bool(last_two_blanks_re.match(new_src)) or
129 bool(last_two_blanks_re2.match(new_src)) )
129 bool(last_two_blanks_re2.match(new_src)) )
130
130
131
131
132 def remove_comments(src):
132 def remove_comments(src):
133 """Remove all comments from input source.
133 """Remove all comments from input source.
134
134
135 Note: comments are NOT recognized inside of strings!
135 Note: comments are NOT recognized inside of strings!
136
136
137 Parameters
137 Parameters
138 ----------
138 ----------
139 src : string
139 src : string
140 A single or multiline input string.
140 A single or multiline input string.
141
141
142 Returns
142 Returns
143 -------
143 -------
144 String with all Python comments removed.
144 String with all Python comments removed.
145 """
145 """
146
146
147 return re.sub('#.*', '', src)
147 return re.sub('#.*', '', src)
148
148
149
149
150 def get_input_encoding():
150 def get_input_encoding():
151 """Return the default standard input encoding.
151 """Return the default standard input encoding.
152
152
153 If sys.stdin has no encoding, 'ascii' is returned."""
153 If sys.stdin has no encoding, 'ascii' is returned."""
154 # There are strange environments for which sys.stdin.encoding is None. We
154 # There are strange environments for which sys.stdin.encoding is None. We
155 # ensure that a valid encoding is returned.
155 # ensure that a valid encoding is returned.
156 encoding = getattr(sys.stdin, 'encoding', None)
156 encoding = getattr(sys.stdin, 'encoding', None)
157 if encoding is None:
157 if encoding is None:
158 encoding = 'ascii'
158 encoding = 'ascii'
159 return encoding
159 return encoding
160
160
161 #-----------------------------------------------------------------------------
161 #-----------------------------------------------------------------------------
162 # Classes and functions for normal Python syntax handling
162 # Classes and functions for normal Python syntax handling
163 #-----------------------------------------------------------------------------
163 #-----------------------------------------------------------------------------
164
164
165 class InputSplitter(object):
165 class InputSplitter(object):
166 r"""An object that can accumulate lines of Python source before execution.
166 r"""An object that can accumulate lines of Python source before execution.
167
167
168 This object is designed to be fed python source line-by-line, using
168 This object is designed to be fed python source line-by-line, using
169 :meth:`push`. It will return on each push whether the currently pushed
169 :meth:`push`. It will return on each push whether the currently pushed
170 code could be executed already. In addition, it provides a method called
170 code could be executed already. In addition, it provides a method called
171 :meth:`push_accepts_more` that can be used to query whether more input
171 :meth:`push_accepts_more` that can be used to query whether more input
172 can be pushed into a single interactive block.
172 can be pushed into a single interactive block.
173
173
174 This is a simple example of how an interactive terminal-based client can use
174 This is a simple example of how an interactive terminal-based client can use
175 this tool::
175 this tool::
176
176
177 isp = InputSplitter()
177 isp = InputSplitter()
178 while isp.push_accepts_more():
178 while isp.push_accepts_more():
179 indent = ' '*isp.indent_spaces
179 indent = ' '*isp.indent_spaces
180 prompt = '>>> ' + indent
180 prompt = '>>> ' + indent
181 line = indent + raw_input(prompt)
181 line = indent + raw_input(prompt)
182 isp.push(line)
182 isp.push(line)
183 print 'Input source was:\n', isp.source_reset(),
183 print 'Input source was:\n', isp.source_reset(),
184 """
184 """
185 # Number of spaces of indentation computed from input that has been pushed
185 # Number of spaces of indentation computed from input that has been pushed
186 # so far. This is the attributes callers should query to get the current
186 # so far. This is the attributes callers should query to get the current
187 # indentation level, in order to provide auto-indent facilities.
187 # indentation level, in order to provide auto-indent facilities.
188 indent_spaces = 0
188 indent_spaces = 0
189 # String, indicating the default input encoding. It is computed by default
189 # String, indicating the default input encoding. It is computed by default
190 # at initialization time via get_input_encoding(), but it can be reset by a
190 # at initialization time via get_input_encoding(), but it can be reset by a
191 # client with specific knowledge of the encoding.
191 # client with specific knowledge of the encoding.
192 encoding = ''
192 encoding = ''
193 # String where the current full source input is stored, properly encoded.
193 # String where the current full source input is stored, properly encoded.
194 # Reading this attribute is the normal way of querying the currently pushed
194 # Reading this attribute is the normal way of querying the currently pushed
195 # source code, that has been properly encoded.
195 # source code, that has been properly encoded.
196 source = ''
196 source = ''
197 # Code object corresponding to the current source. It is automatically
197 # Code object corresponding to the current source. It is automatically
198 # synced to the source, so it can be queried at any time to obtain the code
198 # synced to the source, so it can be queried at any time to obtain the code
199 # object; it will be None if the source doesn't compile to valid Python.
199 # object; it will be None if the source doesn't compile to valid Python.
200 code = None
200 code = None
201
201
202 # Private attributes
202 # Private attributes
203
203
204 # List with lines of input accumulated so far
204 # List with lines of input accumulated so far
205 _buffer = None
205 _buffer = None
206 # Command compiler
206 # Command compiler
207 _compile = None
207 _compile = None
208 # Mark when input has changed indentation all the way back to flush-left
208 # Mark when input has changed indentation all the way back to flush-left
209 _full_dedent = False
209 _full_dedent = False
210 # Boolean indicating whether the current block is complete
210 # Boolean indicating whether the current block is complete
211 _is_complete = None
211 _is_complete = None
212 # Boolean indicating whether the current block has an unrecoverable syntax error
212 # Boolean indicating whether the current block has an unrecoverable syntax error
213 _is_invalid = False
213 _is_invalid = False
214
214
215 def __init__(self):
215 def __init__(self):
216 """Create a new InputSplitter instance.
216 """Create a new InputSplitter instance.
217 """
217 """
218 self._buffer = []
218 self._buffer = []
219 self._compile = codeop.CommandCompiler()
219 self._compile = codeop.CommandCompiler()
220 self.encoding = get_input_encoding()
220 self.encoding = get_input_encoding()
221
221
222 def reset(self):
222 def reset(self):
223 """Reset the input buffer and associated state."""
223 """Reset the input buffer and associated state."""
224 self.indent_spaces = 0
224 self.indent_spaces = 0
225 self._buffer[:] = []
225 self._buffer[:] = []
226 self.source = ''
226 self.source = ''
227 self.code = None
227 self.code = None
228 self._is_complete = False
228 self._is_complete = False
229 self._is_invalid = False
229 self._is_invalid = False
230 self._full_dedent = False
230 self._full_dedent = False
231
231
232 def source_reset(self):
232 def source_reset(self):
233 """Return the input source and perform a full reset.
233 """Return the input source and perform a full reset.
234 """
234 """
235 out = self.source
235 out = self.source
236 self.reset()
236 self.reset()
237 return out
237 return out
238
238
239 def check_complete(self, source):
239 def check_complete(self, source):
240 """Return whether a block of code is ready to execute, or should be continued
240 """Return whether a block of code is ready to execute, or should be continued
241
241
242 This is a non-stateful API, and will reset the state of this InputSplitter.
242 This is a non-stateful API, and will reset the state of this InputSplitter.
243
243
244 Parameters
244 Parameters
245 ----------
245 ----------
246 source : string
246 source : string
247 Python input code, which can be multiline.
247 Python input code, which can be multiline.
248
248
249 Returns
249 Returns
250 -------
250 -------
251 status : str
251 status : str
252 One of 'complete', 'incomplete', or 'invalid' if source is not a
252 One of 'complete', 'incomplete', or 'invalid' if source is not a
253 prefix of valid code.
253 prefix of valid code.
254 indent_spaces : int or None
254 indent_spaces : int or None
255 The number of spaces by which to indent the next line of code. If
255 The number of spaces by which to indent the next line of code. If
256 status is not 'incomplete', this is None.
256 status is not 'incomplete', this is None.
257 """
257 """
258 self.reset()
258 self.reset()
259 try:
259 try:
260 self.push(source)
260 self.push(source)
261 except SyntaxError:
261 except SyntaxError:
262 # Transformers in IPythonInputSplitter can raise SyntaxError,
262 # Transformers in IPythonInputSplitter can raise SyntaxError,
263 # which push() will not catch.
263 # which push() will not catch.
264 return 'invalid', None
264 return 'invalid', None
265 else:
265 else:
266 if self._is_invalid:
266 if self._is_invalid:
267 return 'invalid', None
267 return 'invalid', None
268 elif self.push_accepts_more():
268 elif self.push_accepts_more():
269 return 'incomplete', self.indent_spaces
269 return 'incomplete', self.indent_spaces
270 else:
270 else:
271 return 'complete', None
271 return 'complete', None
272 finally:
272 finally:
273 self.reset()
273 self.reset()
274
274
275 def push(self, lines):
275 def push(self, lines):
276 """Push one or more lines of input.
276 """Push one or more lines of input.
277
277
278 This stores the given lines and returns a status code indicating
278 This stores the given lines and returns a status code indicating
279 whether the code forms a complete Python block or not.
279 whether the code forms a complete Python block or not.
280
280
281 Any exceptions generated in compilation are swallowed, but if an
281 Any exceptions generated in compilation are swallowed, but if an
282 exception was produced, the method returns True.
282 exception was produced, the method returns True.
283
283
284 Parameters
284 Parameters
285 ----------
285 ----------
286 lines : string
286 lines : string
287 One or more lines of Python input.
287 One or more lines of Python input.
288
288
289 Returns
289 Returns
290 -------
290 -------
291 is_complete : boolean
291 is_complete : boolean
292 True if the current input source (the result of the current input
292 True if the current input source (the result of the current input
293 plus prior inputs) forms a complete Python execution block. Note that
293 plus prior inputs) forms a complete Python execution block. Note that
294 this value is also stored as a private attribute (``_is_complete``), so it
294 this value is also stored as a private attribute (``_is_complete``), so it
295 can be queried at any time.
295 can be queried at any time.
296 """
296 """
297 self._store(lines)
297 self._store(lines)
298 source = self.source
298 source = self.source
299
299
300 # Before calling _compile(), reset the code object to None so that if an
300 # Before calling _compile(), reset the code object to None so that if an
301 # exception is raised in compilation, we don't mislead by having
301 # exception is raised in compilation, we don't mislead by having
302 # inconsistent code/source attributes.
302 # inconsistent code/source attributes.
303 self.code, self._is_complete = None, None
303 self.code, self._is_complete = None, None
304 self._is_invalid = False
304 self._is_invalid = False
305
305
306 # Honor termination lines properly
306 # Honor termination lines properly
307 if source.endswith('\\\n'):
307 if source.endswith('\\\n'):
308 return False
308 return False
309
309
310 self._update_indent(lines)
310 self._update_indent(lines)
311 try:
311 try:
312 with warnings.catch_warnings():
312 with warnings.catch_warnings():
313 warnings.simplefilter('error', SyntaxWarning)
313 warnings.simplefilter('error', SyntaxWarning)
314 self.code = self._compile(source, symbol="exec")
314 self.code = self._compile(source, symbol="exec")
315 # Invalid syntax can produce any of a number of different errors from
315 # Invalid syntax can produce any of a number of different errors from
316 # inside the compiler, so we have to catch them all. Syntax errors
316 # inside the compiler, so we have to catch them all. Syntax errors
317 # immediately produce a 'ready' block, so the invalid Python can be
317 # immediately produce a 'ready' block, so the invalid Python can be
318 # sent to the kernel for evaluation with possible ipython
318 # sent to the kernel for evaluation with possible ipython
319 # special-syntax conversion.
319 # special-syntax conversion.
320 except (SyntaxError, OverflowError, ValueError, TypeError,
320 except (SyntaxError, OverflowError, ValueError, TypeError,
321 MemoryError, SyntaxWarning):
321 MemoryError, SyntaxWarning):
322 self._is_complete = True
322 self._is_complete = True
323 self._is_invalid = True
323 self._is_invalid = True
324 else:
324 else:
325 # Compilation didn't produce any exceptions (though it may not have
325 # Compilation didn't produce any exceptions (though it may not have
326 # given a complete code object)
326 # given a complete code object)
327 self._is_complete = self.code is not None
327 self._is_complete = self.code is not None
328
328
329 return self._is_complete
329 return self._is_complete
330
330
331 def push_accepts_more(self):
331 def push_accepts_more(self):
332 """Return whether a block of interactive input can accept more input.
332 """Return whether a block of interactive input can accept more input.
333
333
334 This method is meant to be used by line-oriented frontends, who need to
334 This method is meant to be used by line-oriented frontends, who need to
335 guess whether a block is complete or not based solely on prior and
335 guess whether a block is complete or not based solely on prior and
336 current input lines. The InputSplitter considers it has a complete
336 current input lines. The InputSplitter considers it has a complete
337 interactive block and will not accept more input when either:
337 interactive block and will not accept more input when either:
338
338
339 * A SyntaxError is raised
339 * A SyntaxError is raised
340
340
341 * The code is complete and consists of a single line or a single
341 * The code is complete and consists of a single line or a single
342 non-compound statement
342 non-compound statement
343
343
344 * The code is complete and has a blank line at the end
344 * The code is complete and has a blank line at the end
345
345
346 If the current input produces a syntax error, this method immediately
346 If the current input produces a syntax error, this method immediately
347 returns False but does *not* raise the syntax error exception, as
347 returns False but does *not* raise the syntax error exception, as
348 typically clients will want to send invalid syntax to an execution
348 typically clients will want to send invalid syntax to an execution
349 backend which might convert the invalid syntax into valid Python via
349 backend which might convert the invalid syntax into valid Python via
350 one of the dynamic IPython mechanisms.
350 one of the dynamic IPython mechanisms.
351 """
351 """
352
352
353 # With incomplete input, unconditionally accept more
353 # With incomplete input, unconditionally accept more
354 # A syntax error also sets _is_complete to True - see push()
354 # A syntax error also sets _is_complete to True - see push()
355 if not self._is_complete:
355 if not self._is_complete:
356 #print("Not complete") # debug
356 #print("Not complete") # debug
357 return True
357 return True
358
358
359 # The user can make any (complete) input execute by leaving a blank line
359 # The user can make any (complete) input execute by leaving a blank line
360 last_line = self.source.splitlines()[-1]
360 last_line = self.source.splitlines()[-1]
361 if (not last_line) or last_line.isspace():
361 if (not last_line) or last_line.isspace():
362 #print("Blank line") # debug
362 #print("Blank line") # debug
363 return False
363 return False
364
364
365 # If there's just a single line or AST node, and we're flush left, as is
365 # If there's just a single line or AST node, and we're flush left, as is
366 # the case after a simple statement such as 'a=1', we want to execute it
366 # the case after a simple statement such as 'a=1', we want to execute it
367 # straight away.
367 # straight away.
368 if self.indent_spaces==0:
368 if self.indent_spaces==0:
369 if len(self.source.splitlines()) <= 1:
369 if len(self.source.splitlines()) <= 1:
370 return False
370 return False
371
371
372 try:
372 try:
373 code_ast = ast.parse(u''.join(self._buffer))
373 code_ast = ast.parse(u''.join(self._buffer))
374 except Exception:
374 except Exception:
375 #print("Can't parse AST") # debug
375 #print("Can't parse AST") # debug
376 return False
376 return False
377 else:
377 else:
378 if len(code_ast.body) == 1 and \
378 if len(code_ast.body) == 1 and \
379 not hasattr(code_ast.body[0], 'body'):
379 not hasattr(code_ast.body[0], 'body'):
380 #print("Simple statement") # debug
380 #print("Simple statement") # debug
381 return False
381 return False
382
382
383 # General fallback - accept more code
383 # General fallback - accept more code
384 return True
384 return True
385
385
386 #------------------------------------------------------------------------
386 #------------------------------------------------------------------------
387 # Private interface
387 # Private interface
388 #------------------------------------------------------------------------
388 #------------------------------------------------------------------------
389
389
390 def _find_indent(self, line):
390 def _find_indent(self, line):
391 """Compute the new indentation level for a single line.
391 """Compute the new indentation level for a single line.
392
392
393 Parameters
393 Parameters
394 ----------
394 ----------
395 line : str
395 line : str
396 A single new line of non-whitespace, non-comment Python input.
396 A single new line of non-whitespace, non-comment Python input.
397
397
398 Returns
398 Returns
399 -------
399 -------
400 indent_spaces : int
400 indent_spaces : int
401 New value for the indent level (it may be equal to self.indent_spaces
401 New value for the indent level (it may be equal to self.indent_spaces
402 if indentation doesn't change.
402 if indentation doesn't change.
403
403
404 full_dedent : boolean
404 full_dedent : boolean
405 Whether the new line causes a full flush-left dedent.
405 Whether the new line causes a full flush-left dedent.
406 """
406 """
407 indent_spaces = self.indent_spaces
407 indent_spaces = self.indent_spaces
408 full_dedent = self._full_dedent
408 full_dedent = self._full_dedent
409
409
410 inisp = num_ini_spaces(line)
410 inisp = num_ini_spaces(line)
411 if inisp < indent_spaces:
411 if inisp < indent_spaces:
412 indent_spaces = inisp
412 indent_spaces = inisp
413 if indent_spaces <= 0:
413 if indent_spaces <= 0:
414 #print 'Full dedent in text',self.source # dbg
414 #print 'Full dedent in text',self.source # dbg
415 full_dedent = True
415 full_dedent = True
416
416
417 if line.rstrip()[-1] == ':':
417 if line.rstrip()[-1] == ':':
418 indent_spaces += 4
418 indent_spaces += 4
419 elif dedent_re.match(line):
419 elif dedent_re.match(line):
420 indent_spaces -= 4
420 indent_spaces -= 4
421 if indent_spaces <= 0:
421 if indent_spaces <= 0:
422 full_dedent = True
422 full_dedent = True
423
423
424 # Safety
424 # Safety
425 if indent_spaces < 0:
425 if indent_spaces < 0:
426 indent_spaces = 0
426 indent_spaces = 0
427 #print 'safety' # dbg
427 #print 'safety' # dbg
428
428
429 return indent_spaces, full_dedent
429 return indent_spaces, full_dedent
430
430
431 def _update_indent(self, lines):
431 def _update_indent(self, lines):
432 for line in remove_comments(lines).splitlines():
432 for line in remove_comments(lines).splitlines():
433 if line and not line.isspace():
433 if line and not line.isspace():
434 self.indent_spaces, self._full_dedent = self._find_indent(line)
434 self.indent_spaces, self._full_dedent = self._find_indent(line)
435
435
436 def _store(self, lines, buffer=None, store='source'):
436 def _store(self, lines, buffer=None, store='source'):
437 """Store one or more lines of input.
437 """Store one or more lines of input.
438
438
439 If input lines are not newline-terminated, a newline is automatically
439 If input lines are not newline-terminated, a newline is automatically
440 appended."""
440 appended."""
441
441
442 if buffer is None:
442 if buffer is None:
443 buffer = self._buffer
443 buffer = self._buffer
444
444
445 if lines.endswith('\n'):
445 if lines.endswith('\n'):
446 buffer.append(lines)
446 buffer.append(lines)
447 else:
447 else:
448 buffer.append(lines+'\n')
448 buffer.append(lines+'\n')
449 setattr(self, store, self._set_source(buffer))
449 setattr(self, store, self._set_source(buffer))
450
450
451 def _set_source(self, buffer):
451 def _set_source(self, buffer):
452 return u''.join(buffer)
452 return u''.join(buffer)
453
453
454
454
455 class IPythonInputSplitter(InputSplitter):
455 class IPythonInputSplitter(InputSplitter):
456 """An input splitter that recognizes all of IPython's special syntax."""
456 """An input splitter that recognizes all of IPython's special syntax."""
457
457
458 # String with raw, untransformed input.
458 # String with raw, untransformed input.
459 source_raw = ''
459 source_raw = ''
460
460
461 # Flag to track when a transformer has stored input that it hasn't given
461 # Flag to track when a transformer has stored input that it hasn't given
462 # back yet.
462 # back yet.
463 transformer_accumulating = False
463 transformer_accumulating = False
464
464
465 # Flag to track when assemble_python_lines has stored input that it hasn't
465 # Flag to track when assemble_python_lines has stored input that it hasn't
466 # given back yet.
466 # given back yet.
467 within_python_line = False
467 within_python_line = False
468
468
469 # Private attributes
469 # Private attributes
470
470
471 # List with lines of raw input accumulated so far.
471 # List with lines of raw input accumulated so far.
472 _buffer_raw = None
472 _buffer_raw = None
473
473
474 def __init__(self, line_input_checker=True, physical_line_transforms=None,
474 def __init__(self, line_input_checker=True, physical_line_transforms=None,
475 logical_line_transforms=None, python_line_transforms=None):
475 logical_line_transforms=None, python_line_transforms=None):
476 super(IPythonInputSplitter, self).__init__()
476 super(IPythonInputSplitter, self).__init__()
477 self._buffer_raw = []
477 self._buffer_raw = []
478 self._validate = True
478 self._validate = True
479
479
480 if physical_line_transforms is not None:
480 if physical_line_transforms is not None:
481 self.physical_line_transforms = physical_line_transforms
481 self.physical_line_transforms = physical_line_transforms
482 else:
482 else:
483 self.physical_line_transforms = [
483 self.physical_line_transforms = [
484 leading_indent(),
484 leading_indent(),
485 classic_prompt(),
485 classic_prompt(),
486 ipy_prompt(),
486 ipy_prompt(),
487 cellmagic(end_on_blank_line=line_input_checker),
487 cellmagic(end_on_blank_line=line_input_checker),
488 strip_encoding_cookie(),
488 strip_encoding_cookie(),
489 ]
489 ]
490
490
491 self.assemble_logical_lines = assemble_logical_lines()
491 self.assemble_logical_lines = assemble_logical_lines()
492 if logical_line_transforms is not None:
492 if logical_line_transforms is not None:
493 self.logical_line_transforms = logical_line_transforms
493 self.logical_line_transforms = logical_line_transforms
494 else:
494 else:
495 self.logical_line_transforms = [
495 self.logical_line_transforms = [
496 help_end(),
496 help_end(),
497 escaped_commands(),
497 escaped_commands(),
498 assign_from_magic(),
498 assign_from_magic(),
499 assign_from_system(),
499 assign_from_system(),
500 ]
500 ]
501
501
502 self.assemble_python_lines = assemble_python_lines()
502 self.assemble_python_lines = assemble_python_lines()
503 if python_line_transforms is not None:
503 if python_line_transforms is not None:
504 self.python_line_transforms = python_line_transforms
504 self.python_line_transforms = python_line_transforms
505 else:
505 else:
506 # We don't use any of these at present
506 # We don't use any of these at present
507 self.python_line_transforms = []
507 self.python_line_transforms = []
508
508
509 @property
509 @property
510 def transforms(self):
510 def transforms(self):
511 "Quick access to all transformers."
511 "Quick access to all transformers."
512 return self.physical_line_transforms + \
512 return self.physical_line_transforms + \
513 [self.assemble_logical_lines] + self.logical_line_transforms + \
513 [self.assemble_logical_lines] + self.logical_line_transforms + \
514 [self.assemble_python_lines] + self.python_line_transforms
514 [self.assemble_python_lines] + self.python_line_transforms
515
515
516 @property
516 @property
517 def transforms_in_use(self):
517 def transforms_in_use(self):
518 """Transformers, excluding logical line transformers if we're in a
518 """Transformers, excluding logical line transformers if we're in a
519 Python line."""
519 Python line."""
520 t = self.physical_line_transforms[:]
520 t = self.physical_line_transforms[:]
521 if not self.within_python_line:
521 if not self.within_python_line:
522 t += [self.assemble_logical_lines] + self.logical_line_transforms
522 t += [self.assemble_logical_lines] + self.logical_line_transforms
523 return t + [self.assemble_python_lines] + self.python_line_transforms
523 return t + [self.assemble_python_lines] + self.python_line_transforms
524
524
525 def reset(self):
525 def reset(self):
526 """Reset the input buffer and associated state."""
526 """Reset the input buffer and associated state."""
527 super(IPythonInputSplitter, self).reset()
527 super(IPythonInputSplitter, self).reset()
528 self._buffer_raw[:] = []
528 self._buffer_raw[:] = []
529 self.source_raw = ''
529 self.source_raw = ''
530 self.transformer_accumulating = False
530 self.transformer_accumulating = False
531 self.within_python_line = False
531 self.within_python_line = False
532
532
533 for t in self.transforms:
533 for t in self.transforms:
534 try:
534 try:
535 t.reset()
535 t.reset()
536 except SyntaxError:
536 except SyntaxError:
537 # Nothing that calls reset() expects to handle transformer
537 # Nothing that calls reset() expects to handle transformer
538 # errors
538 # errors
539 pass
539 pass
540
540
541 def flush_transformers(self):
541 def flush_transformers(self):
542 def _flush(transform, outs):
542 def _flush(transform, outs):
543 """yield transformed lines
543 """yield transformed lines
544
544
545 always strings, never None
545 always strings, never None
546
546
547 transform: the current transform
547 transform: the current transform
548 outs: an iterable of previously transformed inputs.
548 outs: an iterable of previously transformed inputs.
549 Each may be multiline, which will be passed
549 Each may be multiline, which will be passed
550 one line at a time to transform.
550 one line at a time to transform.
551 """
551 """
552 for out in outs:
552 for out in outs:
553 for line in out.splitlines():
553 for line in out.splitlines():
554 # push one line at a time
554 # push one line at a time
555 tmp = transform.push(line)
555 tmp = transform.push(line)
556 if tmp is not None:
556 if tmp is not None:
557 yield tmp
557 yield tmp
558
558
559 # reset the transform
559 # reset the transform
560 tmp = transform.reset()
560 tmp = transform.reset()
561 if tmp is not None:
561 if tmp is not None:
562 yield tmp
562 yield tmp
563
563
564 out = []
564 out = []
565 for t in self.transforms_in_use:
565 for t in self.transforms_in_use:
566 out = _flush(t, out)
566 out = _flush(t, out)
567
567
568 out = list(out)
568 out = list(out)
569 if out:
569 if out:
570 self._store('\n'.join(out))
570 self._store('\n'.join(out))
571
571
572 def raw_reset(self):
572 def raw_reset(self):
573 """Return raw input only and perform a full reset.
573 """Return raw input only and perform a full reset.
574 """
574 """
575 out = self.source_raw
575 out = self.source_raw
576 self.reset()
576 self.reset()
577 return out
577 return out
578
578
579 def source_reset(self):
579 def source_reset(self):
580 try:
580 try:
581 self.flush_transformers()
581 self.flush_transformers()
582 return self.source
582 return self.source
583 finally:
583 finally:
584 self.reset()
584 self.reset()
585
585
586 def push_accepts_more(self):
586 def push_accepts_more(self):
587 if self.transformer_accumulating:
587 if self.transformer_accumulating:
588 return True
588 return True
589 else:
589 else:
590 return super(IPythonInputSplitter, self).push_accepts_more()
590 return super(IPythonInputSplitter, self).push_accepts_more()
591
591
592 def transform_cell(self, cell):
592 def transform_cell(self, cell):
593 """Process and translate a cell of input.
593 """Process and translate a cell of input.
594 """
594 """
595 self.reset()
595 self.reset()
596 try:
596 try:
597 self.push(cell)
597 self.push(cell)
598 self.flush_transformers()
598 self.flush_transformers()
599 return self.source
599 return self.source
600 finally:
600 finally:
601 self.reset()
601 self.reset()
602
602
603 def push(self, lines):
603 def push(self, lines):
604 """Push one or more lines of IPython input.
604 """Push one or more lines of IPython input.
605
605
606 This stores the given lines and returns a status code indicating
606 This stores the given lines and returns a status code indicating
607 whether the code forms a complete Python block or not, after processing
607 whether the code forms a complete Python block or not, after processing
608 all input lines for special IPython syntax.
608 all input lines for special IPython syntax.
609
609
610 Any exceptions generated in compilation are swallowed, but if an
610 Any exceptions generated in compilation are swallowed, but if an
611 exception was produced, the method returns True.
611 exception was produced, the method returns True.
612
612
613 Parameters
613 Parameters
614 ----------
614 ----------
615 lines : string
615 lines : string
616 One or more lines of Python input.
616 One or more lines of Python input.
617
617
618 Returns
618 Returns
619 -------
619 -------
620 is_complete : boolean
620 is_complete : boolean
621 True if the current input source (the result of the current input
621 True if the current input source (the result of the current input
622 plus prior inputs) forms a complete Python execution block. Note that
622 plus prior inputs) forms a complete Python execution block. Note that
623 this value is also stored as a private attribute (_is_complete), so it
623 this value is also stored as a private attribute (_is_complete), so it
624 can be queried at any time.
624 can be queried at any time.
625 """
625 """
626
626
627 # We must ensure all input is pure unicode
627 # We must ensure all input is pure unicode
628 lines = cast_unicode(lines, self.encoding)
628 lines = cast_unicode(lines, self.encoding)
629 # ''.splitlines() --> [], but we need to push the empty line to transformers
629 # ''.splitlines() --> [], but we need to push the empty line to transformers
630 lines_list = lines.splitlines()
630 lines_list = lines.splitlines()
631 if not lines_list:
631 if not lines_list:
632 lines_list = ['']
632 lines_list = ['']
633
633
634 # interpet trailing newline as a blank line
635 if lines.endswith('\n'):
636 lines_list += ['']
637
638 # Store raw source before applying any transformations to it. Note
634 # Store raw source before applying any transformations to it. Note
639 # that this must be done *after* the reset() call that would otherwise
635 # that this must be done *after* the reset() call that would otherwise
640 # flush the buffer.
636 # flush the buffer.
641 self._store(lines, self._buffer_raw, 'source_raw')
637 self._store(lines, self._buffer_raw, 'source_raw')
642
638
643 for line in lines_list:
639 for line in lines_list:
644 out = self.push_line(line)
640 out = self.push_line(line)
645
641
646 return out
642 return out
647
643
648 def push_line(self, line):
644 def push_line(self, line):
649 buf = self._buffer
645 buf = self._buffer
650
646
651 def _accumulating(dbg):
647 def _accumulating(dbg):
652 #print(dbg)
648 #print(dbg)
653 self.transformer_accumulating = True
649 self.transformer_accumulating = True
654 return False
650 return False
655
651
656 for transformer in self.physical_line_transforms:
652 for transformer in self.physical_line_transforms:
657 line = transformer.push(line)
653 line = transformer.push(line)
658 if line is None:
654 if line is None:
659 return _accumulating(transformer)
655 return _accumulating(transformer)
660
656
661 if not self.within_python_line:
657 if not self.within_python_line:
662 line = self.assemble_logical_lines.push(line)
658 line = self.assemble_logical_lines.push(line)
663 if line is None:
659 if line is None:
664 return _accumulating('acc logical line')
660 return _accumulating('acc logical line')
665
661
666 for transformer in self.logical_line_transforms:
662 for transformer in self.logical_line_transforms:
667 line = transformer.push(line)
663 line = transformer.push(line)
668 if line is None:
664 if line is None:
669 return _accumulating(transformer)
665 return _accumulating(transformer)
670
666
671 line = self.assemble_python_lines.push(line)
667 line = self.assemble_python_lines.push(line)
672 if line is None:
668 if line is None:
673 self.within_python_line = True
669 self.within_python_line = True
674 return _accumulating('acc python line')
670 return _accumulating('acc python line')
675 else:
671 else:
676 self.within_python_line = False
672 self.within_python_line = False
677
673
678 for transformer in self.python_line_transforms:
674 for transformer in self.python_line_transforms:
679 line = transformer.push(line)
675 line = transformer.push(line)
680 if line is None:
676 if line is None:
681 return _accumulating(transformer)
677 return _accumulating(transformer)
682
678
683 #print("transformers clear") #debug
679 #print("transformers clear") #debug
684 self.transformer_accumulating = False
680 self.transformer_accumulating = False
685 return super(IPythonInputSplitter, self).push(line)
681 return super(IPythonInputSplitter, self).push(line)
@@ -1,540 +1,540 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 from warnings import warn
7 from warnings import warn
8
8
9 from IPython.core.error import TryNext
9 from IPython.core.error import TryNext
10 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
10 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
11 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
11 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
13 from IPython.utils.process import abbrev_cwd
13 from IPython.utils.process import abbrev_cwd
14 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default
14 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default
15
15
16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
17 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone, HasCompletions
17 from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone, HasCompletions
18 from prompt_toolkit.history import InMemoryHistory
18 from prompt_toolkit.history import InMemoryHistory
19 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
19 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
20 from prompt_toolkit.interface import CommandLineInterface
20 from prompt_toolkit.interface import CommandLineInterface
21 from prompt_toolkit.key_binding.manager import KeyBindingManager
21 from prompt_toolkit.key_binding.manager import KeyBindingManager
22 from prompt_toolkit.keys import Keys
22 from prompt_toolkit.keys import Keys
23 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
23 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
24 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
24 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
25
25
26 from pygments.styles import get_style_by_name, get_all_styles
26 from pygments.styles import get_style_by_name, get_all_styles
27 from pygments.token import Token
27 from pygments.token import Token
28
28
29 from .debugger import TerminalPdb, Pdb
29 from .debugger import TerminalPdb, Pdb
30 from .magics import TerminalMagics
30 from .magics import TerminalMagics
31 from .pt_inputhooks import get_inputhook_func
31 from .pt_inputhooks import get_inputhook_func
32 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
32 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
33 from .ptutils import IPythonPTCompleter, IPythonPTLexer
33 from .ptutils import IPythonPTCompleter, IPythonPTLexer
34
34
35
35
36 def get_default_editor():
36 def get_default_editor():
37 try:
37 try:
38 ed = os.environ['EDITOR']
38 ed = os.environ['EDITOR']
39 if not PY3:
39 if not PY3:
40 ed = ed.decode()
40 ed = ed.decode()
41 return ed
41 return ed
42 except KeyError:
42 except KeyError:
43 pass
43 pass
44 except UnicodeError:
44 except UnicodeError:
45 warn("$EDITOR environment variable is not pure ASCII. Using platform "
45 warn("$EDITOR environment variable is not pure ASCII. Using platform "
46 "default editor.")
46 "default editor.")
47
47
48 if os.name == 'posix':
48 if os.name == 'posix':
49 return 'vi' # the only one guaranteed to be there!
49 return 'vi' # the only one guaranteed to be there!
50 else:
50 else:
51 return 'notepad' # same in Windows!
51 return 'notepad' # same in Windows!
52
52
53
53
54 if sys.stdin and sys.stdout and sys.stderr:
54 if sys.stdin and sys.stdout and sys.stderr:
55 _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty())
55 _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty())
56 else:
56 else:
57 _is_tty = False
57 _is_tty = False
58
58
59
59
60 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
60 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
61
61
62 class TerminalInteractiveShell(InteractiveShell):
62 class TerminalInteractiveShell(InteractiveShell):
63 colors_force = True
63 colors_force = True
64
64
65 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
65 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
66 'to reserve for the completion menu'
66 'to reserve for the completion menu'
67 ).tag(config=True)
67 ).tag(config=True)
68
68
69 def _space_for_menu_changed(self, old, new):
69 def _space_for_menu_changed(self, old, new):
70 self._update_layout()
70 self._update_layout()
71
71
72 pt_cli = None
72 pt_cli = None
73 debugger_history = None
73 debugger_history = None
74
74
75 simple_prompt = Bool(_use_simple_prompt,
75 simple_prompt = Bool(_use_simple_prompt,
76 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
76 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
77
77
78 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
78 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
79 IPython own testing machinery, and emacs inferior-shell integration through elpy.
79 IPython own testing machinery, and emacs inferior-shell integration through elpy.
80
80
81 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
81 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
82 environment variable is set, or the current terminal is not a tty.
82 environment variable is set, or the current terminal is not a tty.
83
83
84 """
84 """
85 ).tag(config=True)
85 ).tag(config=True)
86
86
87 @property
87 @property
88 def debugger_cls(self):
88 def debugger_cls(self):
89 return Pdb if self.simple_prompt else TerminalPdb
89 return Pdb if self.simple_prompt else TerminalPdb
90
90
91 autoedit_syntax = Bool(False,
91 autoedit_syntax = Bool(False,
92 help="auto editing of files with syntax errors.",
92 help="auto editing of files with syntax errors.",
93 ).tag(config=True)
93 ).tag(config=True)
94
94
95
95
96 confirm_exit = Bool(True,
96 confirm_exit = Bool(True,
97 help="""
97 help="""
98 Set to confirm when you try to exit IPython with an EOF (Control-D
98 Set to confirm when you try to exit IPython with an EOF (Control-D
99 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
99 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
100 you can force a direct exit without any confirmation.""",
100 you can force a direct exit without any confirmation.""",
101 ).tag(config=True)
101 ).tag(config=True)
102
102
103 editing_mode = Unicode('emacs',
103 editing_mode = Unicode('emacs',
104 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
104 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
105 ).tag(config=True)
105 ).tag(config=True)
106
106
107 mouse_support = Bool(False,
107 mouse_support = Bool(False,
108 help="Enable mouse support in the prompt"
108 help="Enable mouse support in the prompt"
109 ).tag(config=True)
109 ).tag(config=True)
110
110
111 highlighting_style = Unicode('default',
111 highlighting_style = Unicode('default',
112 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
112 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
113 ).tag(config=True)
113 ).tag(config=True)
114
114
115
115
116 @observe('highlighting_style')
116 @observe('highlighting_style')
117 def _highlighting_style_changed(self, change):
117 def _highlighting_style_changed(self, change):
118 self._style = self._make_style_from_name(self.highlighting_style)
118 self._style = self._make_style_from_name(self.highlighting_style)
119
119
120 highlighting_style_overrides = Dict(
120 highlighting_style_overrides = Dict(
121 help="Override highlighting format for specific tokens"
121 help="Override highlighting format for specific tokens"
122 ).tag(config=True)
122 ).tag(config=True)
123
123
124 editor = Unicode(get_default_editor(),
124 editor = Unicode(get_default_editor(),
125 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
125 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
126 ).tag(config=True)
126 ).tag(config=True)
127
127
128 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
128 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
129
129
130 prompts = Instance(Prompts)
130 prompts = Instance(Prompts)
131
131
132 @default('prompts')
132 @default('prompts')
133 def _prompts_default(self):
133 def _prompts_default(self):
134 return self.prompts_class(self)
134 return self.prompts_class(self)
135
135
136 @observe('prompts')
136 @observe('prompts')
137 def _(self, change):
137 def _(self, change):
138 self._update_layout()
138 self._update_layout()
139
139
140 @default('displayhook_class')
140 @default('displayhook_class')
141 def _displayhook_class_default(self):
141 def _displayhook_class_default(self):
142 return RichPromptDisplayHook
142 return RichPromptDisplayHook
143
143
144 term_title = Bool(True,
144 term_title = Bool(True,
145 help="Automatically set the terminal title"
145 help="Automatically set the terminal title"
146 ).tag(config=True)
146 ).tag(config=True)
147
147
148 display_completions_in_columns = Bool(False,
148 display_completions_in_columns = Bool(False,
149 help="Display a multi column completion menu.",
149 help="Display a multi column completion menu.",
150 ).tag(config=True)
150 ).tag(config=True)
151
151
152 highlight_matching_brackets = Bool(True,
152 highlight_matching_brackets = Bool(True,
153 help="Highlight matching brackets .",
153 help="Highlight matching brackets .",
154 ).tag(config=True)
154 ).tag(config=True)
155
155
156 @observe('term_title')
156 @observe('term_title')
157 def init_term_title(self, change=None):
157 def init_term_title(self, change=None):
158 # Enable or disable the terminal title.
158 # Enable or disable the terminal title.
159 if self.term_title:
159 if self.term_title:
160 toggle_set_term_title(True)
160 toggle_set_term_title(True)
161 set_term_title('IPython: ' + abbrev_cwd())
161 set_term_title('IPython: ' + abbrev_cwd())
162 else:
162 else:
163 toggle_set_term_title(False)
163 toggle_set_term_title(False)
164
164
165 def init_prompt_toolkit_cli(self):
165 def init_prompt_toolkit_cli(self):
166 self._app = None
166 self._app = None
167 if self.simple_prompt:
167 if self.simple_prompt:
168 # Fall back to plain non-interactive output for tests.
168 # Fall back to plain non-interactive output for tests.
169 # This is very limited, and only accepts a single line.
169 # This is very limited, and only accepts a single line.
170 def prompt():
170 def prompt():
171 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
171 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
172 self.prompt_for_code = prompt
172 self.prompt_for_code = prompt
173 return
173 return
174
174
175 kbmanager = KeyBindingManager.for_prompt()
175 kbmanager = KeyBindingManager.for_prompt()
176 insert_mode = ViInsertMode() | EmacsInsertMode()
176 insert_mode = ViInsertMode() | EmacsInsertMode()
177 # Ctrl+J == Enter, seemingly
177 # Ctrl+J == Enter, seemingly
178 @kbmanager.registry.add_binding(Keys.ControlJ,
178 @kbmanager.registry.add_binding(Keys.ControlJ,
179 filter=(HasFocus(DEFAULT_BUFFER)
179 filter=(HasFocus(DEFAULT_BUFFER)
180 & ~HasSelection()
180 & ~HasSelection()
181 & insert_mode
181 & insert_mode
182 ))
182 ))
183 def _(event):
183 def _(event):
184 b = event.current_buffer
184 b = event.current_buffer
185 d = b.document
185 d = b.document
186
186
187 if b.complete_state:
187 if b.complete_state:
188 cc = b.complete_state.current_completion
188 cc = b.complete_state.current_completion
189 if cc:
189 if cc:
190 b.apply_completion(cc)
190 b.apply_completion(cc)
191 return
191 return
192
192
193 if not (d.on_last_line or d.cursor_position_row >= d.line_count
193 if not (d.on_last_line or d.cursor_position_row >= d.line_count
194 - d.empty_line_count_at_the_end()):
194 - d.empty_line_count_at_the_end()):
195 b.newline()
195 b.newline()
196 return
196 return
197
197
198 status, indent = self.input_splitter.check_complete(d.text)
198 status, indent = self.input_splitter.check_complete(d.text + '\n')
199
199
200 if (status != 'incomplete') and b.accept_action.is_returnable:
200 if (status != 'incomplete') and b.accept_action.is_returnable:
201 b.accept_action.validate_and_handle(event.cli, b)
201 b.accept_action.validate_and_handle(event.cli, b)
202 else:
202 else:
203 b.insert_text('\n' + (' ' * (indent or 0)))
203 b.insert_text('\n' + (' ' * (indent or 0)))
204
204
205 @kbmanager.registry.add_binding(Keys.ControlP, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)))
205 @kbmanager.registry.add_binding(Keys.ControlP, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)))
206 def _previous_history_or_previous_completion(event):
206 def _previous_history_or_previous_completion(event):
207 """
207 """
208 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
208 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
209
209
210 If completer is open this still select previous completion.
210 If completer is open this still select previous completion.
211 """
211 """
212 event.current_buffer.auto_up()
212 event.current_buffer.auto_up()
213
213
214 @kbmanager.registry.add_binding(Keys.ControlN, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)))
214 @kbmanager.registry.add_binding(Keys.ControlN, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)))
215 def _next_history_or_next_completion(event):
215 def _next_history_or_next_completion(event):
216 """
216 """
217 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
217 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
218
218
219 If completer is open this still select next completion.
219 If completer is open this still select next completion.
220 """
220 """
221 event.current_buffer.auto_down()
221 event.current_buffer.auto_down()
222
222
223 @kbmanager.registry.add_binding(Keys.ControlG, filter=(
223 @kbmanager.registry.add_binding(Keys.ControlG, filter=(
224 HasFocus(DEFAULT_BUFFER) & HasCompletions()
224 HasFocus(DEFAULT_BUFFER) & HasCompletions()
225 ))
225 ))
226 def _dismiss_completion(event):
226 def _dismiss_completion(event):
227 b = event.current_buffer
227 b = event.current_buffer
228 if b.complete_state:
228 if b.complete_state:
229 b.cancel_completion()
229 b.cancel_completion()
230
230
231 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
231 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
232 def _reset_buffer(event):
232 def _reset_buffer(event):
233 b = event.current_buffer
233 b = event.current_buffer
234 if b.complete_state:
234 if b.complete_state:
235 b.cancel_completion()
235 b.cancel_completion()
236 else:
236 else:
237 b.reset()
237 b.reset()
238
238
239 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
239 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
240 def _reset_search_buffer(event):
240 def _reset_search_buffer(event):
241 if event.current_buffer.document.text:
241 if event.current_buffer.document.text:
242 event.current_buffer.reset()
242 event.current_buffer.reset()
243 else:
243 else:
244 event.cli.push_focus(DEFAULT_BUFFER)
244 event.cli.push_focus(DEFAULT_BUFFER)
245
245
246 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
246 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
247
247
248 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
248 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
249 def _suspend_to_bg(event):
249 def _suspend_to_bg(event):
250 event.cli.suspend_to_background()
250 event.cli.suspend_to_background()
251
251
252 @Condition
252 @Condition
253 def cursor_in_leading_ws(cli):
253 def cursor_in_leading_ws(cli):
254 before = cli.application.buffer.document.current_line_before_cursor
254 before = cli.application.buffer.document.current_line_before_cursor
255 return (not before) or before.isspace()
255 return (not before) or before.isspace()
256
256
257 # Ctrl+I == Tab
257 # Ctrl+I == Tab
258 @kbmanager.registry.add_binding(Keys.ControlI,
258 @kbmanager.registry.add_binding(Keys.ControlI,
259 filter=(HasFocus(DEFAULT_BUFFER)
259 filter=(HasFocus(DEFAULT_BUFFER)
260 & ~HasSelection()
260 & ~HasSelection()
261 & insert_mode
261 & insert_mode
262 & cursor_in_leading_ws
262 & cursor_in_leading_ws
263 ))
263 ))
264 def _indent_buffer(event):
264 def _indent_buffer(event):
265 event.current_buffer.insert_text(' ' * 4)
265 event.current_buffer.insert_text(' ' * 4)
266
266
267 # Pre-populate history from IPython's history database
267 # Pre-populate history from IPython's history database
268 history = InMemoryHistory()
268 history = InMemoryHistory()
269 last_cell = u""
269 last_cell = u""
270 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
270 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
271 include_latest=True):
271 include_latest=True):
272 # Ignore blank lines and consecutive duplicates
272 # Ignore blank lines and consecutive duplicates
273 cell = cell.rstrip()
273 cell = cell.rstrip()
274 if cell and (cell != last_cell):
274 if cell and (cell != last_cell):
275 history.append(cell)
275 history.append(cell)
276
276
277 self._style = self._make_style_from_name(self.highlighting_style)
277 self._style = self._make_style_from_name(self.highlighting_style)
278 style = DynamicStyle(lambda: self._style)
278 style = DynamicStyle(lambda: self._style)
279
279
280 editing_mode = getattr(EditingMode, self.editing_mode.upper())
280 editing_mode = getattr(EditingMode, self.editing_mode.upper())
281
281
282 self._app = create_prompt_application(
282 self._app = create_prompt_application(
283 editing_mode=editing_mode,
283 editing_mode=editing_mode,
284 key_bindings_registry=kbmanager.registry,
284 key_bindings_registry=kbmanager.registry,
285 history=history,
285 history=history,
286 completer=IPythonPTCompleter(self.Completer),
286 completer=IPythonPTCompleter(self.Completer),
287 enable_history_search=True,
287 enable_history_search=True,
288 style=style,
288 style=style,
289 mouse_support=self.mouse_support,
289 mouse_support=self.mouse_support,
290 **self._layout_options()
290 **self._layout_options()
291 )
291 )
292 self._eventloop = create_eventloop(self.inputhook)
292 self._eventloop = create_eventloop(self.inputhook)
293 self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop)
293 self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop)
294
294
295 def _make_style_from_name(self, name):
295 def _make_style_from_name(self, name):
296 """
296 """
297 Small wrapper that make an IPython compatible style from a style name
297 Small wrapper that make an IPython compatible style from a style name
298
298
299 We need that to add style for prompt ... etc.
299 We need that to add style for prompt ... etc.
300 """
300 """
301 style_cls = get_style_by_name(name)
301 style_cls = get_style_by_name(name)
302 style_overrides = {
302 style_overrides = {
303 Token.Prompt: '#009900',
303 Token.Prompt: '#009900',
304 Token.PromptNum: '#00ff00 bold',
304 Token.PromptNum: '#00ff00 bold',
305 Token.OutPrompt: '#990000',
305 Token.OutPrompt: '#990000',
306 Token.OutPromptNum: '#ff0000 bold',
306 Token.OutPromptNum: '#ff0000 bold',
307 }
307 }
308 if name == 'default':
308 if name == 'default':
309 style_cls = get_style_by_name('default')
309 style_cls = get_style_by_name('default')
310 # The default theme needs to be visible on both a dark background
310 # The default theme needs to be visible on both a dark background
311 # and a light background, because we can't tell what the terminal
311 # and a light background, because we can't tell what the terminal
312 # looks like. These tweaks to the default theme help with that.
312 # looks like. These tweaks to the default theme help with that.
313 style_overrides.update({
313 style_overrides.update({
314 Token.Number: '#007700',
314 Token.Number: '#007700',
315 Token.Operator: 'noinherit',
315 Token.Operator: 'noinherit',
316 Token.String: '#BB6622',
316 Token.String: '#BB6622',
317 Token.Name.Function: '#2080D0',
317 Token.Name.Function: '#2080D0',
318 Token.Name.Class: 'bold #2080D0',
318 Token.Name.Class: 'bold #2080D0',
319 Token.Name.Namespace: 'bold #2080D0',
319 Token.Name.Namespace: 'bold #2080D0',
320 })
320 })
321 style_overrides.update(self.highlighting_style_overrides)
321 style_overrides.update(self.highlighting_style_overrides)
322 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
322 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
323 style_dict=style_overrides)
323 style_dict=style_overrides)
324
324
325 return style
325 return style
326
326
327 def _layout_options(self):
327 def _layout_options(self):
328 """
328 """
329 Return the current layout option for the current Terminal InteractiveShell
329 Return the current layout option for the current Terminal InteractiveShell
330 """
330 """
331 return {
331 return {
332 'lexer':IPythonPTLexer(),
332 'lexer':IPythonPTLexer(),
333 'reserve_space_for_menu':self.space_for_menu,
333 'reserve_space_for_menu':self.space_for_menu,
334 'get_prompt_tokens':self.prompts.in_prompt_tokens,
334 'get_prompt_tokens':self.prompts.in_prompt_tokens,
335 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
335 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
336 'multiline':True,
336 'multiline':True,
337 'display_completions_in_columns': self.display_completions_in_columns,
337 'display_completions_in_columns': self.display_completions_in_columns,
338
338
339 # Highlight matching brackets, but only when this setting is
339 # Highlight matching brackets, but only when this setting is
340 # enabled, and only when the DEFAULT_BUFFER has the focus.
340 # enabled, and only when the DEFAULT_BUFFER has the focus.
341 'extra_input_processors': [ConditionalProcessor(
341 'extra_input_processors': [ConditionalProcessor(
342 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
342 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
343 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
343 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
344 Condition(lambda cli: self.highlight_matching_brackets))],
344 Condition(lambda cli: self.highlight_matching_brackets))],
345 }
345 }
346
346
347 def _update_layout(self):
347 def _update_layout(self):
348 """
348 """
349 Ask for a re computation of the application layout, if for example ,
349 Ask for a re computation of the application layout, if for example ,
350 some configuration options have changed.
350 some configuration options have changed.
351 """
351 """
352 if getattr(self, '._app', None):
352 if getattr(self, '._app', None):
353 self._app.layout = create_prompt_layout(**self._layout_options())
353 self._app.layout = create_prompt_layout(**self._layout_options())
354
354
355 def prompt_for_code(self):
355 def prompt_for_code(self):
356 document = self.pt_cli.run(
356 document = self.pt_cli.run(
357 pre_run=self.pre_prompt, reset_current_buffer=True)
357 pre_run=self.pre_prompt, reset_current_buffer=True)
358 return document.text
358 return document.text
359
359
360 def init_io(self):
360 def init_io(self):
361 if sys.platform not in {'win32', 'cli'}:
361 if sys.platform not in {'win32', 'cli'}:
362 return
362 return
363
363
364 import colorama
364 import colorama
365 colorama.init()
365 colorama.init()
366
366
367 # For some reason we make these wrappers around stdout/stderr.
367 # For some reason we make these wrappers around stdout/stderr.
368 # For now, we need to reset them so all output gets coloured.
368 # For now, we need to reset them so all output gets coloured.
369 # https://github.com/ipython/ipython/issues/8669
369 # https://github.com/ipython/ipython/issues/8669
370 from IPython.utils import io
370 from IPython.utils import io
371 io.stdout = io.IOStream(sys.stdout)
371 io.stdout = io.IOStream(sys.stdout)
372 io.stderr = io.IOStream(sys.stderr)
372 io.stderr = io.IOStream(sys.stderr)
373
373
374 def init_magics(self):
374 def init_magics(self):
375 super(TerminalInteractiveShell, self).init_magics()
375 super(TerminalInteractiveShell, self).init_magics()
376 self.register_magics(TerminalMagics)
376 self.register_magics(TerminalMagics)
377
377
378 def init_alias(self):
378 def init_alias(self):
379 # The parent class defines aliases that can be safely used with any
379 # The parent class defines aliases that can be safely used with any
380 # frontend.
380 # frontend.
381 super(TerminalInteractiveShell, self).init_alias()
381 super(TerminalInteractiveShell, self).init_alias()
382
382
383 # Now define aliases that only make sense on the terminal, because they
383 # Now define aliases that only make sense on the terminal, because they
384 # need direct access to the console in a way that we can't emulate in
384 # need direct access to the console in a way that we can't emulate in
385 # GUI or web frontend
385 # GUI or web frontend
386 if os.name == 'posix':
386 if os.name == 'posix':
387 for cmd in ['clear', 'more', 'less', 'man']:
387 for cmd in ['clear', 'more', 'less', 'man']:
388 self.alias_manager.soft_define_alias(cmd, cmd)
388 self.alias_manager.soft_define_alias(cmd, cmd)
389
389
390
390
391 def __init__(self, *args, **kwargs):
391 def __init__(self, *args, **kwargs):
392 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
392 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
393 self.init_prompt_toolkit_cli()
393 self.init_prompt_toolkit_cli()
394 self.init_term_title()
394 self.init_term_title()
395 self.keep_running = True
395 self.keep_running = True
396
396
397 self.debugger_history = InMemoryHistory()
397 self.debugger_history = InMemoryHistory()
398
398
399 def ask_exit(self):
399 def ask_exit(self):
400 self.keep_running = False
400 self.keep_running = False
401
401
402 rl_next_input = None
402 rl_next_input = None
403
403
404 def pre_prompt(self):
404 def pre_prompt(self):
405 if self.rl_next_input:
405 if self.rl_next_input:
406 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
406 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
407 self.rl_next_input = None
407 self.rl_next_input = None
408
408
409 def interact(self):
409 def interact(self):
410 while self.keep_running:
410 while self.keep_running:
411 print(self.separate_in, end='')
411 print(self.separate_in, end='')
412
412
413 try:
413 try:
414 code = self.prompt_for_code()
414 code = self.prompt_for_code()
415 except EOFError:
415 except EOFError:
416 if (not self.confirm_exit) \
416 if (not self.confirm_exit) \
417 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
417 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
418 self.ask_exit()
418 self.ask_exit()
419
419
420 else:
420 else:
421 if code:
421 if code:
422 self.run_cell(code, store_history=True)
422 self.run_cell(code, store_history=True)
423 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
423 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
424 self.edit_syntax_error()
424 self.edit_syntax_error()
425
425
426 def mainloop(self):
426 def mainloop(self):
427 # An extra layer of protection in case someone mashing Ctrl-C breaks
427 # An extra layer of protection in case someone mashing Ctrl-C breaks
428 # out of our internal code.
428 # out of our internal code.
429 while True:
429 while True:
430 try:
430 try:
431 self.interact()
431 self.interact()
432 break
432 break
433 except KeyboardInterrupt:
433 except KeyboardInterrupt:
434 print("\nKeyboardInterrupt escaped interact()\n")
434 print("\nKeyboardInterrupt escaped interact()\n")
435
435
436 if hasattr(self, '_eventloop'):
436 if hasattr(self, '_eventloop'):
437 self._eventloop.close()
437 self._eventloop.close()
438
438
439 _inputhook = None
439 _inputhook = None
440 def inputhook(self, context):
440 def inputhook(self, context):
441 if self._inputhook is not None:
441 if self._inputhook is not None:
442 self._inputhook(context)
442 self._inputhook(context)
443
443
444 def enable_gui(self, gui=None):
444 def enable_gui(self, gui=None):
445 if gui:
445 if gui:
446 self._inputhook = get_inputhook_func(gui)
446 self._inputhook = get_inputhook_func(gui)
447 else:
447 else:
448 self._inputhook = None
448 self._inputhook = None
449
449
450 # Methods to support auto-editing of SyntaxErrors:
450 # Methods to support auto-editing of SyntaxErrors:
451
451
452 def edit_syntax_error(self):
452 def edit_syntax_error(self):
453 """The bottom half of the syntax error handler called in the main loop.
453 """The bottom half of the syntax error handler called in the main loop.
454
454
455 Loop until syntax error is fixed or user cancels.
455 Loop until syntax error is fixed or user cancels.
456 """
456 """
457
457
458 while self.SyntaxTB.last_syntax_error:
458 while self.SyntaxTB.last_syntax_error:
459 # copy and clear last_syntax_error
459 # copy and clear last_syntax_error
460 err = self.SyntaxTB.clear_err_state()
460 err = self.SyntaxTB.clear_err_state()
461 if not self._should_recompile(err):
461 if not self._should_recompile(err):
462 return
462 return
463 try:
463 try:
464 # may set last_syntax_error again if a SyntaxError is raised
464 # may set last_syntax_error again if a SyntaxError is raised
465 self.safe_execfile(err.filename, self.user_ns)
465 self.safe_execfile(err.filename, self.user_ns)
466 except:
466 except:
467 self.showtraceback()
467 self.showtraceback()
468 else:
468 else:
469 try:
469 try:
470 with open(err.filename) as f:
470 with open(err.filename) as f:
471 # This should be inside a display_trap block and I
471 # This should be inside a display_trap block and I
472 # think it is.
472 # think it is.
473 sys.displayhook(f.read())
473 sys.displayhook(f.read())
474 except:
474 except:
475 self.showtraceback()
475 self.showtraceback()
476
476
477 def _should_recompile(self, e):
477 def _should_recompile(self, e):
478 """Utility routine for edit_syntax_error"""
478 """Utility routine for edit_syntax_error"""
479
479
480 if e.filename in ('<ipython console>', '<input>', '<string>',
480 if e.filename in ('<ipython console>', '<input>', '<string>',
481 '<console>', '<BackgroundJob compilation>',
481 '<console>', '<BackgroundJob compilation>',
482 None):
482 None):
483 return False
483 return False
484 try:
484 try:
485 if (self.autoedit_syntax and
485 if (self.autoedit_syntax and
486 not self.ask_yes_no(
486 not self.ask_yes_no(
487 'Return to editor to correct syntax error? '
487 'Return to editor to correct syntax error? '
488 '[Y/n] ', 'y')):
488 '[Y/n] ', 'y')):
489 return False
489 return False
490 except EOFError:
490 except EOFError:
491 return False
491 return False
492
492
493 def int0(x):
493 def int0(x):
494 try:
494 try:
495 return int(x)
495 return int(x)
496 except TypeError:
496 except TypeError:
497 return 0
497 return 0
498
498
499 # always pass integer line and offset values to editor hook
499 # always pass integer line and offset values to editor hook
500 try:
500 try:
501 self.hooks.fix_error_editor(e.filename,
501 self.hooks.fix_error_editor(e.filename,
502 int0(e.lineno), int0(e.offset),
502 int0(e.lineno), int0(e.offset),
503 e.msg)
503 e.msg)
504 except TryNext:
504 except TryNext:
505 warn('Could not open editor')
505 warn('Could not open editor')
506 return False
506 return False
507 return True
507 return True
508
508
509 # Run !system commands directly, not through pipes, so terminal programs
509 # Run !system commands directly, not through pipes, so terminal programs
510 # work correctly.
510 # work correctly.
511 system = InteractiveShell.system_raw
511 system = InteractiveShell.system_raw
512
512
513 def auto_rewrite_input(self, cmd):
513 def auto_rewrite_input(self, cmd):
514 """Overridden from the parent class to use fancy rewriting prompt"""
514 """Overridden from the parent class to use fancy rewriting prompt"""
515 if not self.show_rewritten_input:
515 if not self.show_rewritten_input:
516 return
516 return
517
517
518 tokens = self.prompts.rewrite_prompt_tokens()
518 tokens = self.prompts.rewrite_prompt_tokens()
519 if self.pt_cli:
519 if self.pt_cli:
520 self.pt_cli.print_tokens(tokens)
520 self.pt_cli.print_tokens(tokens)
521 print(cmd)
521 print(cmd)
522 else:
522 else:
523 prompt = ''.join(s for t, s in tokens)
523 prompt = ''.join(s for t, s in tokens)
524 print(prompt, cmd, sep='')
524 print(prompt, cmd, sep='')
525
525
526 _prompts_before = None
526 _prompts_before = None
527 def switch_doctest_mode(self, mode):
527 def switch_doctest_mode(self, mode):
528 """Switch prompts to classic for %doctest_mode"""
528 """Switch prompts to classic for %doctest_mode"""
529 if mode:
529 if mode:
530 self._prompts_before = self.prompts
530 self._prompts_before = self.prompts
531 self.prompts = ClassicPrompts(self)
531 self.prompts = ClassicPrompts(self)
532 elif self._prompts_before:
532 elif self._prompts_before:
533 self.prompts = self._prompts_before
533 self.prompts = self._prompts_before
534 self._prompts_before = None
534 self._prompts_before = None
535
535
536
536
537 InteractiveShellABC.register(TerminalInteractiveShell)
537 InteractiveShellABC.register(TerminalInteractiveShell)
538
538
539 if __name__ == '__main__':
539 if __name__ == '__main__':
540 TerminalInteractiveShell.instance().interact()
540 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now