##// END OF EJS Templates
undeprecate terminal.interactiveshell...
Min RK -
Show More
@@ -365,22 +365,22 b' class InteractiveShell(SingletonConfigurable):'
365 365 # deprecated prompt traits:
366 366
367 367 prompt_in1 = Unicode('In [\\#]: ',
368 help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly."
368 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
369 369 ).tag(config=True)
370 370 prompt_in2 = Unicode(' .\\D.: ',
371 help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly."
371 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
372 372 ).tag(config=True)
373 373 prompt_out = Unicode('Out[\\#]: ',
374 help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly."
374 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
375 375 ).tag(config=True)
376 376 prompts_pad_left = Bool(True,
377 help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly."
377 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
378 378 ).tag(config=True)
379 379
380 380 @observe('prompt_in1', 'prompt_in2', 'prompt_out', 'prompt_pad_left')
381 381 def _prompt_trait_changed(self, change):
382 382 name = change['name']
383 warn("InteractiveShell.{name} is deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly.".format(
383 warn("InteractiveShell.{name} is deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly.".format(
384 384 name=name)
385 385 )
386 386 # protect against weird cases where self.config may not exist:
@@ -13,9 +13,8 b' import warnings'
13 13
14 14 from IPython.core import ultratb, compilerop
15 15 from IPython.core.magic import Magics, magics_class, line_magic
16 from IPython.core.interactiveshell import DummyMod
17 from IPython.core.interactiveshell import InteractiveShell
18 from IPython.terminal.ptshell import TerminalInteractiveShell
16 from IPython.core.interactiveshell import DummyMod, InteractiveShell
17 from IPython.terminal.interactiveshell import TerminalInteractiveShell
19 18 from IPython.terminal.ipapp import load_default_config
20 19
21 20 from traitlets import Bool, CBool, Unicode
This diff has been collapsed as it changes many lines, (578 lines changed) Show them Hide them
@@ -1,21 +1,569 b''
1 # -*- coding: utf-8 -*-
2 """DEPRECATED: old import location of TerminalInteractiveShell"""
3
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
1 """IPython terminal interface using prompt_toolkit in place of readline"""
2 from __future__ import print_function
6 3
4 import os
5 import sys
6 import signal
7 7 from warnings import warn
8 8
9 from IPython.utils.decorators import undoc
10 from .ptshell import TerminalInteractiveShell as PromptToolkitShell
9 from IPython.core.error import TryNext
10 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
11 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
13 from IPython.utils.process import abbrev_cwd
14 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default
15
16 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode
17 from prompt_toolkit.filters import (HasFocus, HasSelection, Condition,
18 ViInsertMode, EmacsInsertMode, IsDone, HasCompletions)
19 from prompt_toolkit.filters.cli import ViMode
20 from prompt_toolkit.history import InMemoryHistory
21 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout
22 from prompt_toolkit.interface import CommandLineInterface
23 from prompt_toolkit.key_binding.manager import KeyBindingManager
24 from prompt_toolkit.keys import Keys
25 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
26 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
27
28 from pygments.styles import get_style_by_name, get_all_styles
29 from pygments.token import Token
30
31 from .debugger import TerminalPdb, Pdb
32 from .magics import TerminalMagics
33 from .pt_inputhooks import get_inputhook_func
34 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
35 from .ptutils import IPythonPTCompleter, IPythonPTLexer
36
37
38 def get_default_editor():
39 try:
40 ed = os.environ['EDITOR']
41 if not PY3:
42 ed = ed.decode()
43 return ed
44 except KeyError:
45 pass
46 except UnicodeError:
47 warn("$EDITOR environment variable is not pure ASCII. Using platform "
48 "default editor.")
49
50 if os.name == 'posix':
51 return 'vi' # the only one guaranteed to be there!
52 else:
53 return 'notepad' # same in Windows!
54
55
56 if sys.stdin and sys.stdout and sys.stderr:
57 _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty())
58 else:
59 _is_tty = False
60
61
62 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
63
64 class TerminalInteractiveShell(InteractiveShell):
65 colors_force = True
66
67 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
68 'to reserve for the completion menu'
69 ).tag(config=True)
70
71 def _space_for_menu_changed(self, old, new):
72 self._update_layout()
73
74 pt_cli = None
75 debugger_history = None
76
77 simple_prompt = Bool(_use_simple_prompt,
78 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
79
80 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
81 IPython own testing machinery, and emacs inferior-shell integration through elpy.
82
83 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
84 environment variable is set, or the current terminal is not a tty.
85
86 """
87 ).tag(config=True)
88
89 @property
90 def debugger_cls(self):
91 return Pdb if self.simple_prompt else TerminalPdb
92
93 autoedit_syntax = Bool(False,
94 help="auto editing of files with syntax errors.",
95 ).tag(config=True)
96
97
98 confirm_exit = Bool(True,
99 help="""
100 Set to confirm when you try to exit IPython with an EOF (Control-D
101 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
102 you can force a direct exit without any confirmation.""",
103 ).tag(config=True)
104
105 editing_mode = Unicode('emacs',
106 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
107 ).tag(config=True)
108
109 mouse_support = Bool(False,
110 help="Enable mouse support in the prompt"
111 ).tag(config=True)
112
113 highlighting_style = Unicode('default',
114 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
115 ).tag(config=True)
116
117
118 @observe('highlighting_style')
119 def _highlighting_style_changed(self, change):
120 self._style = self._make_style_from_name(self.highlighting_style)
121
122 highlighting_style_overrides = Dict(
123 help="Override highlighting format for specific tokens"
124 ).tag(config=True)
125
126 editor = Unicode(get_default_editor(),
127 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
128 ).tag(config=True)
129
130 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
131
132 prompts = Instance(Prompts)
133
134 @default('prompts')
135 def _prompts_default(self):
136 return self.prompts_class(self)
137
138 @observe('prompts')
139 def _(self, change):
140 self._update_layout()
141
142 @default('displayhook_class')
143 def _displayhook_class_default(self):
144 return RichPromptDisplayHook
145
146 term_title = Bool(True,
147 help="Automatically set the terminal title"
148 ).tag(config=True)
149
150 display_completions_in_columns = Bool(False,
151 help="Display a multi column completion menu.",
152 ).tag(config=True)
153
154 highlight_matching_brackets = Bool(True,
155 help="Highlight matching brackets .",
156 ).tag(config=True)
157
158 @observe('term_title')
159 def init_term_title(self, change=None):
160 # Enable or disable the terminal title.
161 if self.term_title:
162 toggle_set_term_title(True)
163 set_term_title('IPython: ' + abbrev_cwd())
164 else:
165 toggle_set_term_title(False)
166
167 def init_display_formatter(self):
168 super(TerminalInteractiveShell, self).init_display_formatter()
169 # terminal only supports plain text
170 self.display_formatter.active_types = ['text/plain']
171
172 def init_prompt_toolkit_cli(self):
173 self._app = None
174 if self.simple_prompt:
175 # Fall back to plain non-interactive output for tests.
176 # This is very limited, and only accepts a single line.
177 def prompt():
178 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
179 self.prompt_for_code = prompt
180 return
181
182 kbmanager = KeyBindingManager.for_prompt()
183 insert_mode = ViInsertMode() | EmacsInsertMode()
184 # Ctrl+J == Enter, seemingly
185 @kbmanager.registry.add_binding(Keys.ControlJ,
186 filter=(HasFocus(DEFAULT_BUFFER)
187 & ~HasSelection()
188 & insert_mode
189 ))
190 def _(event):
191 b = event.current_buffer
192 d = b.document
193
194 if b.complete_state:
195 cc = b.complete_state.current_completion
196 if cc:
197 b.apply_completion(cc)
198 else:
199 b.cancel_completion()
200 return
201
202 if not (d.on_last_line or d.cursor_position_row >= d.line_count
203 - d.empty_line_count_at_the_end()):
204 b.newline()
205 return
206
207 status, indent = self.input_splitter.check_complete(d.text + '\n')
208
209 if (status != 'incomplete') and b.accept_action.is_returnable:
210 b.accept_action.validate_and_handle(event.cli, b)
211 else:
212 b.insert_text('\n' + (' ' * (indent or 0)))
213
214 @kbmanager.registry.add_binding(Keys.ControlP, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)))
215 def _previous_history_or_previous_completion(event):
216 """
217 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
218
219 If completer is open this still select previous completion.
220 """
221 event.current_buffer.auto_up()
222
223 @kbmanager.registry.add_binding(Keys.ControlN, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)))
224 def _next_history_or_next_completion(event):
225 """
226 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
227
228 If completer is open this still select next completion.
229 """
230 event.current_buffer.auto_down()
231
232 @kbmanager.registry.add_binding(Keys.ControlG, filter=(
233 HasFocus(DEFAULT_BUFFER) & HasCompletions()
234 ))
235 def _dismiss_completion(event):
236 b = event.current_buffer
237 if b.complete_state:
238 b.cancel_completion()
239
240 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
241 def _reset_buffer(event):
242 b = event.current_buffer
243 if b.complete_state:
244 b.cancel_completion()
245 else:
246 b.reset()
247
248 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER))
249 def _reset_search_buffer(event):
250 if event.current_buffer.document.text:
251 event.current_buffer.reset()
252 else:
253 event.cli.push_focus(DEFAULT_BUFFER)
254
255 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
256
257 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
258 def _suspend_to_bg(event):
259 event.cli.suspend_to_background()
260
261 @Condition
262 def cursor_in_leading_ws(cli):
263 before = cli.application.buffer.document.current_line_before_cursor
264 return (not before) or before.isspace()
265
266 # Ctrl+I == Tab
267 @kbmanager.registry.add_binding(Keys.ControlI,
268 filter=(HasFocus(DEFAULT_BUFFER)
269 & ~HasSelection()
270 & insert_mode
271 & cursor_in_leading_ws
272 ))
273 def _indent_buffer(event):
274 event.current_buffer.insert_text(' ' * 4)
275
276 if sys.platform == 'win32':
277 from IPython.lib.clipboard import (ClipboardEmpty,
278 win32_clipboard_get, tkinter_clipboard_get)
279 @kbmanager.registry.add_binding(Keys.ControlV,
280 filter=(HasFocus(DEFAULT_BUFFER) & ~ViMode()))
281 def _paste(event):
282 try:
283 text = win32_clipboard_get()
284 except TryNext:
285 try:
286 text = tkinter_clipboard_get()
287 except (TryNext, ClipboardEmpty):
288 return
289 except ClipboardEmpty:
290 return
291 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
292
293 # Pre-populate history from IPython's history database
294 history = InMemoryHistory()
295 last_cell = u""
296 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
297 include_latest=True):
298 # Ignore blank lines and consecutive duplicates
299 cell = cell.rstrip()
300 if cell and (cell != last_cell):
301 history.append(cell)
302
303 self._style = self._make_style_from_name(self.highlighting_style)
304 style = DynamicStyle(lambda: self._style)
305
306 editing_mode = getattr(EditingMode, self.editing_mode.upper())
307
308 self._app = create_prompt_application(
309 editing_mode=editing_mode,
310 key_bindings_registry=kbmanager.registry,
311 history=history,
312 completer=IPythonPTCompleter(self.Completer),
313 enable_history_search=True,
314 style=style,
315 mouse_support=self.mouse_support,
316 **self._layout_options()
317 )
318 self._eventloop = create_eventloop(self.inputhook)
319 self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop)
320
321 def _make_style_from_name(self, name):
322 """
323 Small wrapper that make an IPython compatible style from a style name
324
325 We need that to add style for prompt ... etc.
326 """
327 style_cls = get_style_by_name(name)
328 style_overrides = {
329 Token.Prompt: '#009900',
330 Token.PromptNum: '#00ff00 bold',
331 Token.OutPrompt: '#990000',
332 Token.OutPromptNum: '#ff0000 bold',
333 }
334 if name == 'default':
335 style_cls = get_style_by_name('default')
336 # The default theme needs to be visible on both a dark background
337 # and a light background, because we can't tell what the terminal
338 # looks like. These tweaks to the default theme help with that.
339 style_overrides.update({
340 Token.Number: '#007700',
341 Token.Operator: 'noinherit',
342 Token.String: '#BB6622',
343 Token.Name.Function: '#2080D0',
344 Token.Name.Class: 'bold #2080D0',
345 Token.Name.Namespace: 'bold #2080D0',
346 })
347 style_overrides.update(self.highlighting_style_overrides)
348 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
349 style_dict=style_overrides)
350
351 return style
352
353 def _layout_options(self):
354 """
355 Return the current layout option for the current Terminal InteractiveShell
356 """
357 return {
358 'lexer':IPythonPTLexer(),
359 'reserve_space_for_menu':self.space_for_menu,
360 'get_prompt_tokens':self.prompts.in_prompt_tokens,
361 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
362 'multiline':True,
363 'display_completions_in_columns': self.display_completions_in_columns,
364
365 # Highlight matching brackets, but only when this setting is
366 # enabled, and only when the DEFAULT_BUFFER has the focus.
367 'extra_input_processors': [ConditionalProcessor(
368 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
369 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
370 Condition(lambda cli: self.highlight_matching_brackets))],
371 }
372
373 def _update_layout(self):
374 """
375 Ask for a re computation of the application layout, if for example ,
376 some configuration options have changed.
377 """
378 if getattr(self, '._app', None):
379 self._app.layout = create_prompt_layout(**self._layout_options())
380
381 def prompt_for_code(self):
382 document = self.pt_cli.run(
383 pre_run=self.pre_prompt, reset_current_buffer=True)
384 return document.text
385
386 def init_io(self):
387 if sys.platform not in {'win32', 'cli'}:
388 return
389
390 import win_unicode_console
391 import colorama
392
393 win_unicode_console.enable()
394 colorama.init()
395
396 # For some reason we make these wrappers around stdout/stderr.
397 # For now, we need to reset them so all output gets coloured.
398 # https://github.com/ipython/ipython/issues/8669
399 from IPython.utils import io
400 io.stdout = io.IOStream(sys.stdout)
401 io.stderr = io.IOStream(sys.stderr)
402
403 def init_magics(self):
404 super(TerminalInteractiveShell, self).init_magics()
405 self.register_magics(TerminalMagics)
406
407 def init_alias(self):
408 # The parent class defines aliases that can be safely used with any
409 # frontend.
410 super(TerminalInteractiveShell, self).init_alias()
411
412 # Now define aliases that only make sense on the terminal, because they
413 # need direct access to the console in a way that we can't emulate in
414 # GUI or web frontend
415 if os.name == 'posix':
416 for cmd in ['clear', 'more', 'less', 'man']:
417 self.alias_manager.soft_define_alias(cmd, cmd)
11 418
12 warn("Since IPython 5.0 `IPython.terminal.interactiveshell` is deprecated in favor of `IPython.terminal.ptshell`.",
13 DeprecationWarning)
14 419
15 @undoc
16 class TerminalInteractiveShell(PromptToolkitShell):
17 420 def __init__(self, *args, **kwargs):
18 warn("Since IPython 5.0 this is a deprecated alias for IPython.terminal.ptshell.TerminalInteractiveShell. "
19 "The terminal interface of this class now uses prompt_toolkit instead of readline.",
20 DeprecationWarning, stacklevel=2)
21 PromptToolkitShell.__init__(self, *args, **kwargs)
421 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
422 self.init_prompt_toolkit_cli()
423 self.init_term_title()
424 self.keep_running = True
425
426 self.debugger_history = InMemoryHistory()
427
428 def ask_exit(self):
429 self.keep_running = False
430
431 rl_next_input = None
432
433 def pre_prompt(self):
434 if self.rl_next_input:
435 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
436 self.rl_next_input = None
437
438 def interact(self):
439 while self.keep_running:
440 print(self.separate_in, end='')
441
442 try:
443 code = self.prompt_for_code()
444 except EOFError:
445 if (not self.confirm_exit) \
446 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
447 self.ask_exit()
448
449 else:
450 if code:
451 self.run_cell(code, store_history=True)
452 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
453 self.edit_syntax_error()
454
455 def mainloop(self):
456 # An extra layer of protection in case someone mashing Ctrl-C breaks
457 # out of our internal code.
458 while True:
459 try:
460 self.interact()
461 break
462 except KeyboardInterrupt:
463 print("\nKeyboardInterrupt escaped interact()\n")
464
465 if hasattr(self, '_eventloop'):
466 self._eventloop.close()
467
468 _inputhook = None
469 def inputhook(self, context):
470 if self._inputhook is not None:
471 self._inputhook(context)
472
473 def enable_gui(self, gui=None):
474 if gui:
475 self._inputhook = get_inputhook_func(gui)
476 else:
477 self._inputhook = None
478
479 # Methods to support auto-editing of SyntaxErrors:
480
481 def edit_syntax_error(self):
482 """The bottom half of the syntax error handler called in the main loop.
483
484 Loop until syntax error is fixed or user cancels.
485 """
486
487 while self.SyntaxTB.last_syntax_error:
488 # copy and clear last_syntax_error
489 err = self.SyntaxTB.clear_err_state()
490 if not self._should_recompile(err):
491 return
492 try:
493 # may set last_syntax_error again if a SyntaxError is raised
494 self.safe_execfile(err.filename, self.user_ns)
495 except:
496 self.showtraceback()
497 else:
498 try:
499 with open(err.filename) as f:
500 # This should be inside a display_trap block and I
501 # think it is.
502 sys.displayhook(f.read())
503 except:
504 self.showtraceback()
505
506 def _should_recompile(self, e):
507 """Utility routine for edit_syntax_error"""
508
509 if e.filename in ('<ipython console>', '<input>', '<string>',
510 '<console>', '<BackgroundJob compilation>',
511 None):
512 return False
513 try:
514 if (self.autoedit_syntax and
515 not self.ask_yes_no(
516 'Return to editor to correct syntax error? '
517 '[Y/n] ', 'y')):
518 return False
519 except EOFError:
520 return False
521
522 def int0(x):
523 try:
524 return int(x)
525 except TypeError:
526 return 0
527
528 # always pass integer line and offset values to editor hook
529 try:
530 self.hooks.fix_error_editor(e.filename,
531 int0(e.lineno), int0(e.offset),
532 e.msg)
533 except TryNext:
534 warn('Could not open editor')
535 return False
536 return True
537
538 # Run !system commands directly, not through pipes, so terminal programs
539 # work correctly.
540 system = InteractiveShell.system_raw
541
542 def auto_rewrite_input(self, cmd):
543 """Overridden from the parent class to use fancy rewriting prompt"""
544 if not self.show_rewritten_input:
545 return
546
547 tokens = self.prompts.rewrite_prompt_tokens()
548 if self.pt_cli:
549 self.pt_cli.print_tokens(tokens)
550 print(cmd)
551 else:
552 prompt = ''.join(s for t, s in tokens)
553 print(prompt, cmd, sep='')
554
555 _prompts_before = None
556 def switch_doctest_mode(self, mode):
557 """Switch prompts to classic for %doctest_mode"""
558 if mode:
559 self._prompts_before = self.prompts
560 self.prompts = ClassicPrompts(self)
561 elif self._prompts_before:
562 self.prompts = self._prompts_before
563 self._prompts_before = None
564
565
566 InteractiveShellABC.register(TerminalInteractiveShell)
567
568 if __name__ == '__main__':
569 TerminalInteractiveShell.instance().interact()
@@ -32,7 +32,7 b' from IPython.core.shellapp import ('
32 32 InteractiveShellApp, shell_flags, shell_aliases
33 33 )
34 34 from IPython.extensions.storemagic import StoreMagics
35 from .ptshell import TerminalInteractiveShell
35 from .interactiveshell import TerminalInteractiveShell
36 36 from IPython.paths import get_ipython_dir
37 37 from traitlets import (
38 38 Bool, List, Dict, default, observe,
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (569 lines changed) Show them Hide them
General Comments 0
You need to be logged in to leave comments. Login now