##// END OF EJS Templates
Merge pull request #10479 from memeplex/pdbstyle...
Thomas Kluyver -
r23572:075c197e merge
parent child Browse files
Show More
@@ -1,123 +1,124 b''
1 import signal
1 import signal
2 import sys
2 import sys
3
3
4 from IPython.core.debugger import Pdb
4 from IPython.core.debugger import Pdb
5
5
6 from IPython.core.completer import IPCompleter
6 from IPython.core.completer import IPCompleter
7 from .ptutils import IPythonPTCompleter
7 from .ptutils import IPythonPTCompleter
8 from .shortcuts import suspend_to_bg, cursor_in_leading_ws
8 from .shortcuts import suspend_to_bg, cursor_in_leading_ws
9
9
10 from prompt_toolkit.enums import DEFAULT_BUFFER
10 from prompt_toolkit.enums import DEFAULT_BUFFER
11 from prompt_toolkit.filters import (Condition, HasFocus, HasSelection,
11 from prompt_toolkit.filters import (Condition, HasFocus, HasSelection,
12 ViInsertMode, EmacsInsertMode)
12 ViInsertMode, EmacsInsertMode)
13 from prompt_toolkit.keys import Keys
13 from prompt_toolkit.keys import Keys
14 from prompt_toolkit.key_binding.manager import KeyBindingManager
14 from prompt_toolkit.key_binding.manager import KeyBindingManager
15 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
15 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
16 from prompt_toolkit.token import Token
16 from prompt_toolkit.token import Token
17 from prompt_toolkit.shortcuts import create_prompt_application
17 from prompt_toolkit.shortcuts import create_prompt_application
18 from prompt_toolkit.interface import CommandLineInterface
18 from prompt_toolkit.interface import CommandLineInterface
19 from prompt_toolkit.enums import EditingMode
19 from prompt_toolkit.enums import EditingMode
20
20
21
21
22 class TerminalPdb(Pdb):
22 class TerminalPdb(Pdb):
23 def __init__(self, *args, **kwargs):
23 def __init__(self, *args, **kwargs):
24 Pdb.__init__(self, *args, **kwargs)
24 Pdb.__init__(self, *args, **kwargs)
25 self._ptcomp = None
25 self._ptcomp = None
26 self.pt_init()
26 self.pt_init()
27
27
28 def pt_init(self):
28 def pt_init(self):
29 def get_prompt_tokens(cli):
29 def get_prompt_tokens(cli):
30 return [(Token.Prompt, self.prompt)]
30 return [(Token.Prompt, self.prompt)]
31
31
32 def patch_stdout(**kwargs):
32 def patch_stdout(**kwargs):
33 return self.pt_cli.patch_stdout_context(**kwargs)
33 return self.pt_cli.patch_stdout_context(**kwargs)
34
34
35 if self._ptcomp is None:
35 if self._ptcomp is None:
36 compl = IPCompleter(shell=self.shell,
36 compl = IPCompleter(shell=self.shell,
37 namespace={},
37 namespace={},
38 global_namespace={},
38 global_namespace={},
39 parent=self.shell,
39 parent=self.shell,
40 )
40 )
41 self._ptcomp = IPythonPTCompleter(compl, patch_stdout=patch_stdout)
41 self._ptcomp = IPythonPTCompleter(compl, patch_stdout=patch_stdout)
42
42
43 kbmanager = KeyBindingManager.for_prompt()
43 kbmanager = KeyBindingManager.for_prompt()
44 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
44 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
45 kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend
45 kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend
46 )(suspend_to_bg)
46 )(suspend_to_bg)
47
47
48 if self.shell.display_completions == 'readlinelike':
48 if self.shell.display_completions == 'readlinelike':
49 kbmanager.registry.add_binding(Keys.ControlI,
49 kbmanager.registry.add_binding(Keys.ControlI,
50 filter=(HasFocus(DEFAULT_BUFFER)
50 filter=(HasFocus(DEFAULT_BUFFER)
51 & ~HasSelection()
51 & ~HasSelection()
52 & ViInsertMode() | EmacsInsertMode()
52 & ViInsertMode() | EmacsInsertMode()
53 & ~cursor_in_leading_ws
53 & ~cursor_in_leading_ws
54 ))(display_completions_like_readline)
54 ))(display_completions_like_readline)
55 multicolumn = (self.shell.display_completions == 'multicolumn')
55 multicolumn = (self.shell.display_completions == 'multicolumn')
56
56
57 self._pt_app = create_prompt_application(
57 self._pt_app = create_prompt_application(
58 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
58 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
59 key_bindings_registry=kbmanager.registry,
59 key_bindings_registry=kbmanager.registry,
60 history=self.shell.debugger_history,
60 history=self.shell.debugger_history,
61 completer= self._ptcomp,
61 completer= self._ptcomp,
62 enable_history_search=True,
62 enable_history_search=True,
63 mouse_support=self.shell.mouse_support,
63 mouse_support=self.shell.mouse_support,
64 get_prompt_tokens=get_prompt_tokens,
64 get_prompt_tokens=get_prompt_tokens,
65 display_completions_in_columns=multicolumn,
65 display_completions_in_columns=multicolumn,
66 style=self.shell.style
66 )
67 )
67 self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop)
68 self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop)
68
69
69 def cmdloop(self, intro=None):
70 def cmdloop(self, intro=None):
70 """Repeatedly issue a prompt, accept input, parse an initial prefix
71 """Repeatedly issue a prompt, accept input, parse an initial prefix
71 off the received input, and dispatch to action methods, passing them
72 off the received input, and dispatch to action methods, passing them
72 the remainder of the line as argument.
73 the remainder of the line as argument.
73
74
74 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
75 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
75 """
76 """
76 if not self.use_rawinput:
77 if not self.use_rawinput:
77 raise ValueError('Sorry ipdb does not support use_rawinput=False')
78 raise ValueError('Sorry ipdb does not support use_rawinput=False')
78
79
79 self.preloop()
80 self.preloop()
80
81
81 try:
82 try:
82 if intro is not None:
83 if intro is not None:
83 self.intro = intro
84 self.intro = intro
84 if self.intro:
85 if self.intro:
85 self.stdout.write(str(self.intro)+"\n")
86 self.stdout.write(str(self.intro)+"\n")
86 stop = None
87 stop = None
87 while not stop:
88 while not stop:
88 if self.cmdqueue:
89 if self.cmdqueue:
89 line = self.cmdqueue.pop(0)
90 line = self.cmdqueue.pop(0)
90 else:
91 else:
91 self._ptcomp.ipy_completer.namespace = self.curframe_locals
92 self._ptcomp.ipy_completer.namespace = self.curframe_locals
92 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
93 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
93 try:
94 try:
94 line = self.pt_cli.run(reset_current_buffer=True).text
95 line = self.pt_cli.run(reset_current_buffer=True).text
95 except EOFError:
96 except EOFError:
96 line = 'EOF'
97 line = 'EOF'
97 line = self.precmd(line)
98 line = self.precmd(line)
98 stop = self.onecmd(line)
99 stop = self.onecmd(line)
99 stop = self.postcmd(stop, line)
100 stop = self.postcmd(stop, line)
100 self.postloop()
101 self.postloop()
101 except Exception:
102 except Exception:
102 raise
103 raise
103
104
104
105
105 def set_trace(frame=None):
106 def set_trace(frame=None):
106 """
107 """
107 Start debugging from `frame`.
108 Start debugging from `frame`.
108
109
109 If frame is not specified, debugging starts from caller's frame.
110 If frame is not specified, debugging starts from caller's frame.
110 """
111 """
111 TerminalPdb().set_trace(frame or sys._getframe().f_back)
112 TerminalPdb().set_trace(frame or sys._getframe().f_back)
112
113
113
114
114 if __name__ == '__main__':
115 if __name__ == '__main__':
115 import pdb
116 import pdb
116 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
117 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
117 # bdb.BdbQuit. When started through __main__ and an exception
118 # bdb.BdbQuit. When started through __main__ and an exception
118 # happened after hitting "c", this is needed in order to
119 # happened after hitting "c", this is needed in order to
119 # be able to quit the debugging session (see #9950).
120 # be able to quit the debugging session (see #9950).
120 old_trace_dispatch = pdb.Pdb.trace_dispatch
121 old_trace_dispatch = pdb.Pdb.trace_dispatch
121 pdb.Pdb = TerminalPdb
122 pdb.Pdb = TerminalPdb
122 pdb.Pdb.trace_dispatch = old_trace_dispatch
123 pdb.Pdb.trace_dispatch = old_trace_dispatch
123 pdb.main()
124 pdb.main()
@@ -1,516 +1,516 b''
1 """IPython terminal interface using prompt_toolkit"""
1 """IPython terminal interface using prompt_toolkit"""
2
2
3 import os
3 import os
4 import sys
4 import sys
5 import warnings
5 import warnings
6 from warnings import warn
6 from warnings import warn
7
7
8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
9 from IPython.utils import io
9 from IPython.utils import io
10 from IPython.utils.py3compat import cast_unicode_py2, input
10 from IPython.utils.py3compat import cast_unicode_py2, input
11 from IPython.utils.terminal import toggle_set_term_title, set_term_title
11 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 from IPython.utils.process import abbrev_cwd
12 from IPython.utils.process import abbrev_cwd
13 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union
13 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union
14
14
15 from prompt_toolkit.document import Document
15 from prompt_toolkit.document import Document
16 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
16 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
17 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
17 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
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, create_output
19 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
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.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
22 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
23 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
23 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
24
24
25 from pygments.styles import get_style_by_name, get_all_styles
25 from pygments.styles import get_style_by_name, get_all_styles
26 from pygments.style import Style
26 from pygments.style import Style
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_name_and_func
31 from .pt_inputhooks import get_inputhook_name_and_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 from .shortcuts import register_ipython_shortcuts
34 from .shortcuts import register_ipython_shortcuts
35
35
36 DISPLAY_BANNER_DEPRECATED = object()
36 DISPLAY_BANNER_DEPRECATED = object()
37
37
38
38
39 class _NoStyle(Style): pass
39 class _NoStyle(Style): pass
40
40
41
41
42
42
43 _style_overrides_light_bg = {
43 _style_overrides_light_bg = {
44 Token.Prompt: '#0000ff',
44 Token.Prompt: '#0000ff',
45 Token.PromptNum: '#0000ee bold',
45 Token.PromptNum: '#0000ee bold',
46 Token.OutPrompt: '#cc0000',
46 Token.OutPrompt: '#cc0000',
47 Token.OutPromptNum: '#bb0000 bold',
47 Token.OutPromptNum: '#bb0000 bold',
48 }
48 }
49
49
50 _style_overrides_linux = {
50 _style_overrides_linux = {
51 Token.Prompt: '#00cc00',
51 Token.Prompt: '#00cc00',
52 Token.PromptNum: '#00bb00 bold',
52 Token.PromptNum: '#00bb00 bold',
53 Token.OutPrompt: '#cc0000',
53 Token.OutPrompt: '#cc0000',
54 Token.OutPromptNum: '#bb0000 bold',
54 Token.OutPromptNum: '#bb0000 bold',
55 }
55 }
56
56
57
57
58
58
59 def get_default_editor():
59 def get_default_editor():
60 try:
60 try:
61 return os.environ['EDITOR']
61 return os.environ['EDITOR']
62 except KeyError:
62 except KeyError:
63 pass
63 pass
64 except UnicodeError:
64 except UnicodeError:
65 warn("$EDITOR environment variable is not pure ASCII. Using platform "
65 warn("$EDITOR environment variable is not pure ASCII. Using platform "
66 "default editor.")
66 "default editor.")
67
67
68 if os.name == 'posix':
68 if os.name == 'posix':
69 return 'vi' # the only one guaranteed to be there!
69 return 'vi' # the only one guaranteed to be there!
70 else:
70 else:
71 return 'notepad' # same in Windows!
71 return 'notepad' # same in Windows!
72
72
73 # conservatively check for tty
73 # conservatively check for tty
74 # overridden streams can result in things like:
74 # overridden streams can result in things like:
75 # - sys.stdin = None
75 # - sys.stdin = None
76 # - no isatty method
76 # - no isatty method
77 for _name in ('stdin', 'stdout', 'stderr'):
77 for _name in ('stdin', 'stdout', 'stderr'):
78 _stream = getattr(sys, _name)
78 _stream = getattr(sys, _name)
79 if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
79 if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
80 _is_tty = False
80 _is_tty = False
81 break
81 break
82 else:
82 else:
83 _is_tty = True
83 _is_tty = True
84
84
85
85
86 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
86 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
87
87
88 class TerminalInteractiveShell(InteractiveShell):
88 class TerminalInteractiveShell(InteractiveShell):
89 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
89 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
90 'to reserve for the completion menu'
90 'to reserve for the completion menu'
91 ).tag(config=True)
91 ).tag(config=True)
92
92
93 def _space_for_menu_changed(self, old, new):
93 def _space_for_menu_changed(self, old, new):
94 self._update_layout()
94 self._update_layout()
95
95
96 pt_cli = None
96 pt_cli = None
97 debugger_history = None
97 debugger_history = None
98 _pt_app = None
98 _pt_app = None
99
99
100 simple_prompt = Bool(_use_simple_prompt,
100 simple_prompt = Bool(_use_simple_prompt,
101 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
101 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
102
102
103 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
103 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
104 IPython own testing machinery, and emacs inferior-shell integration through elpy.
104 IPython own testing machinery, and emacs inferior-shell integration through elpy.
105
105
106 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
106 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
107 environment variable is set, or the current terminal is not a tty."""
107 environment variable is set, or the current terminal is not a tty."""
108 ).tag(config=True)
108 ).tag(config=True)
109
109
110 @property
110 @property
111 def debugger_cls(self):
111 def debugger_cls(self):
112 return Pdb if self.simple_prompt else TerminalPdb
112 return Pdb if self.simple_prompt else TerminalPdb
113
113
114 confirm_exit = Bool(True,
114 confirm_exit = Bool(True,
115 help="""
115 help="""
116 Set to confirm when you try to exit IPython with an EOF (Control-D
116 Set to confirm when you try to exit IPython with an EOF (Control-D
117 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
117 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
118 you can force a direct exit without any confirmation.""",
118 you can force a direct exit without any confirmation.""",
119 ).tag(config=True)
119 ).tag(config=True)
120
120
121 editing_mode = Unicode('emacs',
121 editing_mode = Unicode('emacs',
122 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
122 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
123 ).tag(config=True)
123 ).tag(config=True)
124
124
125 mouse_support = Bool(False,
125 mouse_support = Bool(False,
126 help="Enable mouse support in the prompt"
126 help="Enable mouse support in the prompt"
127 ).tag(config=True)
127 ).tag(config=True)
128
128
129 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
129 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
130 help="""The name or class of a Pygments style to use for syntax
130 help="""The name or class of a Pygments style to use for syntax
131 highlighting: \n %s""" % ', '.join(get_all_styles())
131 highlighting: \n %s""" % ', '.join(get_all_styles())
132 ).tag(config=True)
132 ).tag(config=True)
133
133
134
134
135 @observe('highlighting_style')
135 @observe('highlighting_style')
136 @observe('colors')
136 @observe('colors')
137 def _highlighting_style_changed(self, change):
137 def _highlighting_style_changed(self, change):
138 self.refresh_style()
138 self.refresh_style()
139
139
140 def refresh_style(self):
140 def refresh_style(self):
141 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
141 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
142
142
143
143
144 highlighting_style_overrides = Dict(
144 highlighting_style_overrides = Dict(
145 help="Override highlighting format for specific tokens"
145 help="Override highlighting format for specific tokens"
146 ).tag(config=True)
146 ).tag(config=True)
147
147
148 true_color = Bool(False,
148 true_color = Bool(False,
149 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
149 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
150 "If your terminal supports true color, the following command "
150 "If your terminal supports true color, the following command "
151 "should print 'TRUECOLOR' in orange: "
151 "should print 'TRUECOLOR' in orange: "
152 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
152 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
153 ).tag(config=True)
153 ).tag(config=True)
154
154
155 editor = Unicode(get_default_editor(),
155 editor = Unicode(get_default_editor(),
156 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
156 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
157 ).tag(config=True)
157 ).tag(config=True)
158
158
159 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
159 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
160
160
161 prompts = Instance(Prompts)
161 prompts = Instance(Prompts)
162
162
163 @default('prompts')
163 @default('prompts')
164 def _prompts_default(self):
164 def _prompts_default(self):
165 return self.prompts_class(self)
165 return self.prompts_class(self)
166
166
167 @observe('prompts')
167 @observe('prompts')
168 def _(self, change):
168 def _(self, change):
169 self._update_layout()
169 self._update_layout()
170
170
171 @default('displayhook_class')
171 @default('displayhook_class')
172 def _displayhook_class_default(self):
172 def _displayhook_class_default(self):
173 return RichPromptDisplayHook
173 return RichPromptDisplayHook
174
174
175 term_title = Bool(True,
175 term_title = Bool(True,
176 help="Automatically set the terminal title"
176 help="Automatically set the terminal title"
177 ).tag(config=True)
177 ).tag(config=True)
178
178
179 display_completions = Enum(('column', 'multicolumn','readlinelike'),
179 display_completions = Enum(('column', 'multicolumn','readlinelike'),
180 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
180 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
181 "'readlinelike'. These options are for `prompt_toolkit`, see "
181 "'readlinelike'. These options are for `prompt_toolkit`, see "
182 "`prompt_toolkit` documentation for more information."
182 "`prompt_toolkit` documentation for more information."
183 ),
183 ),
184 default_value='multicolumn').tag(config=True)
184 default_value='multicolumn').tag(config=True)
185
185
186 highlight_matching_brackets = Bool(True,
186 highlight_matching_brackets = Bool(True,
187 help="Highlight matching brackets.",
187 help="Highlight matching brackets.",
188 ).tag(config=True)
188 ).tag(config=True)
189
189
190 extra_open_editor_shortcuts = Bool(False,
190 extra_open_editor_shortcuts = Bool(False,
191 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
191 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
192 "This is in addition to the F2 binding, which is always enabled."
192 "This is in addition to the F2 binding, which is always enabled."
193 ).tag(config=True)
193 ).tag(config=True)
194
194
195 @observe('term_title')
195 @observe('term_title')
196 def init_term_title(self, change=None):
196 def init_term_title(self, change=None):
197 # Enable or disable the terminal title.
197 # Enable or disable the terminal title.
198 if self.term_title:
198 if self.term_title:
199 toggle_set_term_title(True)
199 toggle_set_term_title(True)
200 set_term_title('IPython: ' + abbrev_cwd())
200 set_term_title('IPython: ' + abbrev_cwd())
201 else:
201 else:
202 toggle_set_term_title(False)
202 toggle_set_term_title(False)
203
203
204 def init_display_formatter(self):
204 def init_display_formatter(self):
205 super(TerminalInteractiveShell, self).init_display_formatter()
205 super(TerminalInteractiveShell, self).init_display_formatter()
206 # terminal only supports plain text
206 # terminal only supports plain text
207 self.display_formatter.active_types = ['text/plain']
207 self.display_formatter.active_types = ['text/plain']
208 # disable `_ipython_display_`
208 # disable `_ipython_display_`
209 self.display_formatter.ipython_display_formatter.enabled = False
209 self.display_formatter.ipython_display_formatter.enabled = False
210
210
211 def init_prompt_toolkit_cli(self):
211 def init_prompt_toolkit_cli(self):
212 if self.simple_prompt:
212 if self.simple_prompt:
213 # Fall back to plain non-interactive output for tests.
213 # Fall back to plain non-interactive output for tests.
214 # This is very limited, and only accepts a single line.
214 # This is very limited, and only accepts a single line.
215 def prompt():
215 def prompt():
216 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
216 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
217 self.prompt_for_code = prompt
217 self.prompt_for_code = prompt
218 return
218 return
219
219
220 # Set up keyboard shortcuts
220 # Set up keyboard shortcuts
221 kbmanager = KeyBindingManager.for_prompt(
221 kbmanager = KeyBindingManager.for_prompt(
222 enable_open_in_editor=self.extra_open_editor_shortcuts,
222 enable_open_in_editor=self.extra_open_editor_shortcuts,
223 )
223 )
224 register_ipython_shortcuts(kbmanager.registry, self)
224 register_ipython_shortcuts(kbmanager.registry, self)
225
225
226 # Pre-populate history from IPython's history database
226 # Pre-populate history from IPython's history database
227 history = InMemoryHistory()
227 history = InMemoryHistory()
228 last_cell = u""
228 last_cell = u""
229 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
229 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
230 include_latest=True):
230 include_latest=True):
231 # Ignore blank lines and consecutive duplicates
231 # Ignore blank lines and consecutive duplicates
232 cell = cell.rstrip()
232 cell = cell.rstrip()
233 if cell and (cell != last_cell):
233 if cell and (cell != last_cell):
234 history.append(cell)
234 history.append(cell)
235 last_cell = cell
235 last_cell = cell
236
236
237 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
237 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
238 style = DynamicStyle(lambda: self._style)
238 self.style = DynamicStyle(lambda: self._style)
239
239
240 editing_mode = getattr(EditingMode, self.editing_mode.upper())
240 editing_mode = getattr(EditingMode, self.editing_mode.upper())
241
241
242 def patch_stdout(**kwargs):
242 def patch_stdout(**kwargs):
243 return self.pt_cli.patch_stdout_context(**kwargs)
243 return self.pt_cli.patch_stdout_context(**kwargs)
244
244
245 self._pt_app = create_prompt_application(
245 self._pt_app = create_prompt_application(
246 editing_mode=editing_mode,
246 editing_mode=editing_mode,
247 key_bindings_registry=kbmanager.registry,
247 key_bindings_registry=kbmanager.registry,
248 history=history,
248 history=history,
249 completer=IPythonPTCompleter(shell=self,
249 completer=IPythonPTCompleter(shell=self,
250 patch_stdout=patch_stdout),
250 patch_stdout=patch_stdout),
251 enable_history_search=True,
251 enable_history_search=True,
252 style=style,
252 style=self.style,
253 mouse_support=self.mouse_support,
253 mouse_support=self.mouse_support,
254 **self._layout_options()
254 **self._layout_options()
255 )
255 )
256 self._eventloop = create_eventloop(self.inputhook)
256 self._eventloop = create_eventloop(self.inputhook)
257 self.pt_cli = CommandLineInterface(
257 self.pt_cli = CommandLineInterface(
258 self._pt_app, eventloop=self._eventloop,
258 self._pt_app, eventloop=self._eventloop,
259 output=create_output(true_color=self.true_color))
259 output=create_output(true_color=self.true_color))
260
260
261 def _make_style_from_name_or_cls(self, name_or_cls):
261 def _make_style_from_name_or_cls(self, name_or_cls):
262 """
262 """
263 Small wrapper that make an IPython compatible style from a style name
263 Small wrapper that make an IPython compatible style from a style name
264
264
265 We need that to add style for prompt ... etc.
265 We need that to add style for prompt ... etc.
266 """
266 """
267 style_overrides = {}
267 style_overrides = {}
268 if name_or_cls == 'legacy':
268 if name_or_cls == 'legacy':
269 legacy = self.colors.lower()
269 legacy = self.colors.lower()
270 if legacy == 'linux':
270 if legacy == 'linux':
271 style_cls = get_style_by_name('monokai')
271 style_cls = get_style_by_name('monokai')
272 style_overrides = _style_overrides_linux
272 style_overrides = _style_overrides_linux
273 elif legacy == 'lightbg':
273 elif legacy == 'lightbg':
274 style_overrides = _style_overrides_light_bg
274 style_overrides = _style_overrides_light_bg
275 style_cls = get_style_by_name('pastie')
275 style_cls = get_style_by_name('pastie')
276 elif legacy == 'neutral':
276 elif legacy == 'neutral':
277 # The default theme needs to be visible on both a dark background
277 # The default theme needs to be visible on both a dark background
278 # and a light background, because we can't tell what the terminal
278 # and a light background, because we can't tell what the terminal
279 # looks like. These tweaks to the default theme help with that.
279 # looks like. These tweaks to the default theme help with that.
280 style_cls = get_style_by_name('default')
280 style_cls = get_style_by_name('default')
281 style_overrides.update({
281 style_overrides.update({
282 Token.Number: '#007700',
282 Token.Number: '#007700',
283 Token.Operator: 'noinherit',
283 Token.Operator: 'noinherit',
284 Token.String: '#BB6622',
284 Token.String: '#BB6622',
285 Token.Name.Function: '#2080D0',
285 Token.Name.Function: '#2080D0',
286 Token.Name.Class: 'bold #2080D0',
286 Token.Name.Class: 'bold #2080D0',
287 Token.Name.Namespace: 'bold #2080D0',
287 Token.Name.Namespace: 'bold #2080D0',
288 Token.Prompt: '#009900',
288 Token.Prompt: '#009900',
289 Token.PromptNum: '#00ff00 bold',
289 Token.PromptNum: '#00ff00 bold',
290 Token.OutPrompt: '#990000',
290 Token.OutPrompt: '#990000',
291 Token.OutPromptNum: '#ff0000 bold',
291 Token.OutPromptNum: '#ff0000 bold',
292 })
292 })
293
293
294 # Hack: Due to limited color support on the Windows console
294 # Hack: Due to limited color support on the Windows console
295 # the prompt colors will be wrong without this
295 # the prompt colors will be wrong without this
296 if os.name == 'nt':
296 if os.name == 'nt':
297 style_overrides.update({
297 style_overrides.update({
298 Token.Prompt: '#ansidarkgreen',
298 Token.Prompt: '#ansidarkgreen',
299 Token.PromptNum: '#ansigreen bold',
299 Token.PromptNum: '#ansigreen bold',
300 Token.OutPrompt: '#ansidarkred',
300 Token.OutPrompt: '#ansidarkred',
301 Token.OutPromptNum: '#ansired bold',
301 Token.OutPromptNum: '#ansired bold',
302 })
302 })
303 elif legacy =='nocolor':
303 elif legacy =='nocolor':
304 style_cls=_NoStyle
304 style_cls=_NoStyle
305 style_overrides = {}
305 style_overrides = {}
306 else :
306 else :
307 raise ValueError('Got unknown colors: ', legacy)
307 raise ValueError('Got unknown colors: ', legacy)
308 else :
308 else :
309 if isinstance(name_or_cls, str):
309 if isinstance(name_or_cls, str):
310 style_cls = get_style_by_name(name_or_cls)
310 style_cls = get_style_by_name(name_or_cls)
311 else:
311 else:
312 style_cls = name_or_cls
312 style_cls = name_or_cls
313 style_overrides = {
313 style_overrides = {
314 Token.Prompt: '#009900',
314 Token.Prompt: '#009900',
315 Token.PromptNum: '#00ff00 bold',
315 Token.PromptNum: '#00ff00 bold',
316 Token.OutPrompt: '#990000',
316 Token.OutPrompt: '#990000',
317 Token.OutPromptNum: '#ff0000 bold',
317 Token.OutPromptNum: '#ff0000 bold',
318 }
318 }
319 style_overrides.update(self.highlighting_style_overrides)
319 style_overrides.update(self.highlighting_style_overrides)
320 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
320 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
321 style_dict=style_overrides)
321 style_dict=style_overrides)
322
322
323 return style
323 return style
324
324
325 def _layout_options(self):
325 def _layout_options(self):
326 """
326 """
327 Return the current layout option for the current Terminal InteractiveShell
327 Return the current layout option for the current Terminal InteractiveShell
328 """
328 """
329 return {
329 return {
330 'lexer':IPythonPTLexer(),
330 'lexer':IPythonPTLexer(),
331 'reserve_space_for_menu':self.space_for_menu,
331 'reserve_space_for_menu':self.space_for_menu,
332 'get_prompt_tokens':self.prompts.in_prompt_tokens,
332 'get_prompt_tokens':self.prompts.in_prompt_tokens,
333 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
333 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
334 'multiline':True,
334 'multiline':True,
335 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
335 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
336
336
337 # Highlight matching brackets, but only when this setting is
337 # Highlight matching brackets, but only when this setting is
338 # enabled, and only when the DEFAULT_BUFFER has the focus.
338 # enabled, and only when the DEFAULT_BUFFER has the focus.
339 'extra_input_processors': [ConditionalProcessor(
339 'extra_input_processors': [ConditionalProcessor(
340 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
340 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
341 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
341 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
342 Condition(lambda cli: self.highlight_matching_brackets))],
342 Condition(lambda cli: self.highlight_matching_brackets))],
343 }
343 }
344
344
345 def _update_layout(self):
345 def _update_layout(self):
346 """
346 """
347 Ask for a re computation of the application layout, if for example ,
347 Ask for a re computation of the application layout, if for example ,
348 some configuration options have changed.
348 some configuration options have changed.
349 """
349 """
350 if self._pt_app:
350 if self._pt_app:
351 self._pt_app.layout = create_prompt_layout(**self._layout_options())
351 self._pt_app.layout = create_prompt_layout(**self._layout_options())
352
352
353 def prompt_for_code(self):
353 def prompt_for_code(self):
354 document = self.pt_cli.run(
354 document = self.pt_cli.run(
355 pre_run=self.pre_prompt, reset_current_buffer=True)
355 pre_run=self.pre_prompt, reset_current_buffer=True)
356 return document.text
356 return document.text
357
357
358 def enable_win_unicode_console(self):
358 def enable_win_unicode_console(self):
359 if sys.version_info >= (3, 6):
359 if sys.version_info >= (3, 6):
360 # Since PEP 528, Python uses the unicode APIs for the Windows
360 # Since PEP 528, Python uses the unicode APIs for the Windows
361 # console by default, so WUC shouldn't be needed.
361 # console by default, so WUC shouldn't be needed.
362 return
362 return
363
363
364 import win_unicode_console
364 import win_unicode_console
365 win_unicode_console.enable()
365 win_unicode_console.enable()
366
366
367 def init_io(self):
367 def init_io(self):
368 if sys.platform not in {'win32', 'cli'}:
368 if sys.platform not in {'win32', 'cli'}:
369 return
369 return
370
370
371 self.enable_win_unicode_console()
371 self.enable_win_unicode_console()
372
372
373 import colorama
373 import colorama
374 colorama.init()
374 colorama.init()
375
375
376 # For some reason we make these wrappers around stdout/stderr.
376 # For some reason we make these wrappers around stdout/stderr.
377 # For now, we need to reset them so all output gets coloured.
377 # For now, we need to reset them so all output gets coloured.
378 # https://github.com/ipython/ipython/issues/8669
378 # https://github.com/ipython/ipython/issues/8669
379 # io.std* are deprecated, but don't show our own deprecation warnings
379 # io.std* are deprecated, but don't show our own deprecation warnings
380 # during initialization of the deprecated API.
380 # during initialization of the deprecated API.
381 with warnings.catch_warnings():
381 with warnings.catch_warnings():
382 warnings.simplefilter('ignore', DeprecationWarning)
382 warnings.simplefilter('ignore', DeprecationWarning)
383 io.stdout = io.IOStream(sys.stdout)
383 io.stdout = io.IOStream(sys.stdout)
384 io.stderr = io.IOStream(sys.stderr)
384 io.stderr = io.IOStream(sys.stderr)
385
385
386 def init_magics(self):
386 def init_magics(self):
387 super(TerminalInteractiveShell, self).init_magics()
387 super(TerminalInteractiveShell, self).init_magics()
388 self.register_magics(TerminalMagics)
388 self.register_magics(TerminalMagics)
389
389
390 def init_alias(self):
390 def init_alias(self):
391 # The parent class defines aliases that can be safely used with any
391 # The parent class defines aliases that can be safely used with any
392 # frontend.
392 # frontend.
393 super(TerminalInteractiveShell, self).init_alias()
393 super(TerminalInteractiveShell, self).init_alias()
394
394
395 # Now define aliases that only make sense on the terminal, because they
395 # Now define aliases that only make sense on the terminal, because they
396 # need direct access to the console in a way that we can't emulate in
396 # need direct access to the console in a way that we can't emulate in
397 # GUI or web frontend
397 # GUI or web frontend
398 if os.name == 'posix':
398 if os.name == 'posix':
399 for cmd in ['clear', 'more', 'less', 'man']:
399 for cmd in ['clear', 'more', 'less', 'man']:
400 self.alias_manager.soft_define_alias(cmd, cmd)
400 self.alias_manager.soft_define_alias(cmd, cmd)
401
401
402
402
403 def __init__(self, *args, **kwargs):
403 def __init__(self, *args, **kwargs):
404 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
404 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
405 self.init_prompt_toolkit_cli()
405 self.init_prompt_toolkit_cli()
406 self.init_term_title()
406 self.init_term_title()
407 self.keep_running = True
407 self.keep_running = True
408
408
409 self.debugger_history = InMemoryHistory()
409 self.debugger_history = InMemoryHistory()
410
410
411 def ask_exit(self):
411 def ask_exit(self):
412 self.keep_running = False
412 self.keep_running = False
413
413
414 rl_next_input = None
414 rl_next_input = None
415
415
416 def pre_prompt(self):
416 def pre_prompt(self):
417 if self.rl_next_input:
417 if self.rl_next_input:
418 # We can't set the buffer here, because it will be reset just after
418 # We can't set the buffer here, because it will be reset just after
419 # this. Adding a callable to pre_run_callables does what we need
419 # this. Adding a callable to pre_run_callables does what we need
420 # after the buffer is reset.
420 # after the buffer is reset.
421 s = cast_unicode_py2(self.rl_next_input)
421 s = cast_unicode_py2(self.rl_next_input)
422 def set_doc():
422 def set_doc():
423 self.pt_cli.application.buffer.document = Document(s)
423 self.pt_cli.application.buffer.document = Document(s)
424 if hasattr(self.pt_cli, 'pre_run_callables'):
424 if hasattr(self.pt_cli, 'pre_run_callables'):
425 self.pt_cli.pre_run_callables.append(set_doc)
425 self.pt_cli.pre_run_callables.append(set_doc)
426 else:
426 else:
427 # Older version of prompt_toolkit; it's OK to set the document
427 # Older version of prompt_toolkit; it's OK to set the document
428 # directly here.
428 # directly here.
429 set_doc()
429 set_doc()
430 self.rl_next_input = None
430 self.rl_next_input = None
431
431
432 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
432 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
433
433
434 if display_banner is not DISPLAY_BANNER_DEPRECATED:
434 if display_banner is not DISPLAY_BANNER_DEPRECATED:
435 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
435 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
436
436
437 self.keep_running = True
437 self.keep_running = True
438 while self.keep_running:
438 while self.keep_running:
439 print(self.separate_in, end='')
439 print(self.separate_in, end='')
440
440
441 try:
441 try:
442 code = self.prompt_for_code()
442 code = self.prompt_for_code()
443 except EOFError:
443 except EOFError:
444 if (not self.confirm_exit) \
444 if (not self.confirm_exit) \
445 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
445 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
446 self.ask_exit()
446 self.ask_exit()
447
447
448 else:
448 else:
449 if code:
449 if code:
450 self.run_cell(code, store_history=True)
450 self.run_cell(code, store_history=True)
451
451
452 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
452 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
453 # An extra layer of protection in case someone mashing Ctrl-C breaks
453 # An extra layer of protection in case someone mashing Ctrl-C breaks
454 # out of our internal code.
454 # out of our internal code.
455 if display_banner is not DISPLAY_BANNER_DEPRECATED:
455 if display_banner is not DISPLAY_BANNER_DEPRECATED:
456 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
456 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
457 while True:
457 while True:
458 try:
458 try:
459 self.interact()
459 self.interact()
460 break
460 break
461 except KeyboardInterrupt as e:
461 except KeyboardInterrupt as e:
462 print("\n%s escaped interact()\n" % type(e).__name__)
462 print("\n%s escaped interact()\n" % type(e).__name__)
463 finally:
463 finally:
464 # An interrupt during the eventloop will mess up the
464 # An interrupt during the eventloop will mess up the
465 # internal state of the prompt_toolkit library.
465 # internal state of the prompt_toolkit library.
466 # Stopping the eventloop fixes this, see
466 # Stopping the eventloop fixes this, see
467 # https://github.com/ipython/ipython/pull/9867
467 # https://github.com/ipython/ipython/pull/9867
468 if hasattr(self, '_eventloop'):
468 if hasattr(self, '_eventloop'):
469 self._eventloop.stop()
469 self._eventloop.stop()
470
470
471 _inputhook = None
471 _inputhook = None
472 def inputhook(self, context):
472 def inputhook(self, context):
473 if self._inputhook is not None:
473 if self._inputhook is not None:
474 self._inputhook(context)
474 self._inputhook(context)
475
475
476 active_eventloop = None
476 active_eventloop = None
477 def enable_gui(self, gui=None):
477 def enable_gui(self, gui=None):
478 if gui:
478 if gui:
479 self.active_eventloop, self._inputhook =\
479 self.active_eventloop, self._inputhook =\
480 get_inputhook_name_and_func(gui)
480 get_inputhook_name_and_func(gui)
481 else:
481 else:
482 self.active_eventloop = self._inputhook = None
482 self.active_eventloop = self._inputhook = None
483
483
484 # Run !system commands directly, not through pipes, so terminal programs
484 # Run !system commands directly, not through pipes, so terminal programs
485 # work correctly.
485 # work correctly.
486 system = InteractiveShell.system_raw
486 system = InteractiveShell.system_raw
487
487
488 def auto_rewrite_input(self, cmd):
488 def auto_rewrite_input(self, cmd):
489 """Overridden from the parent class to use fancy rewriting prompt"""
489 """Overridden from the parent class to use fancy rewriting prompt"""
490 if not self.show_rewritten_input:
490 if not self.show_rewritten_input:
491 return
491 return
492
492
493 tokens = self.prompts.rewrite_prompt_tokens()
493 tokens = self.prompts.rewrite_prompt_tokens()
494 if self.pt_cli:
494 if self.pt_cli:
495 self.pt_cli.print_tokens(tokens)
495 self.pt_cli.print_tokens(tokens)
496 print(cmd)
496 print(cmd)
497 else:
497 else:
498 prompt = ''.join(s for t, s in tokens)
498 prompt = ''.join(s for t, s in tokens)
499 print(prompt, cmd, sep='')
499 print(prompt, cmd, sep='')
500
500
501 _prompts_before = None
501 _prompts_before = None
502 def switch_doctest_mode(self, mode):
502 def switch_doctest_mode(self, mode):
503 """Switch prompts to classic for %doctest_mode"""
503 """Switch prompts to classic for %doctest_mode"""
504 if mode:
504 if mode:
505 self._prompts_before = self.prompts
505 self._prompts_before = self.prompts
506 self.prompts = ClassicPrompts(self)
506 self.prompts = ClassicPrompts(self)
507 elif self._prompts_before:
507 elif self._prompts_before:
508 self.prompts = self._prompts_before
508 self.prompts = self._prompts_before
509 self._prompts_before = None
509 self._prompts_before = None
510 self._update_layout()
510 self._update_layout()
511
511
512
512
513 InteractiveShellABC.register(TerminalInteractiveShell)
513 InteractiveShellABC.register(TerminalInteractiveShell)
514
514
515 if __name__ == '__main__':
515 if __name__ == '__main__':
516 TerminalInteractiveShell.instance().interact()
516 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now