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