##// END OF EJS Templates
Merge pull request #13475 from asteppke/master...
Matthias Bussonnier -
r27460:97e3d9ec merge
parent child Browse files
Show More
@@ -1,700 +1,724 b''
1 """IPython terminal interface using prompt_toolkit"""
1 """IPython terminal interface using prompt_toolkit"""
2
2
3 import asyncio
3 import asyncio
4 import os
4 import os
5 import sys
5 import sys
6 import warnings
6 import warnings
7 from warnings import warn
7 from warnings import warn
8
8
9 from IPython.core.async_helpers import get_asyncio_loop
9 from IPython.core.async_helpers import get_asyncio_loop
10 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
10 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
11 from IPython.utils import io
11 from IPython.utils import io
12 from IPython.utils.py3compat import input
12 from IPython.utils.py3compat import input
13 from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
13 from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
14 from IPython.utils.process import abbrev_cwd
14 from IPython.utils.process import abbrev_cwd
15 from traitlets import (
15 from traitlets import (
16 Bool,
16 Bool,
17 Unicode,
17 Unicode,
18 Dict,
18 Dict,
19 Integer,
19 Integer,
20 observe,
20 observe,
21 Instance,
21 Instance,
22 Type,
22 Type,
23 default,
23 default,
24 Enum,
24 Enum,
25 Union,
25 Union,
26 Any,
26 Any,
27 validate,
27 validate,
28 Float,
28 Float,
29 )
29 )
30
30
31 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
31 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
32 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
32 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
33 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
33 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
34 from prompt_toolkit.formatted_text import PygmentsTokens
34 from prompt_toolkit.formatted_text import PygmentsTokens
35 from prompt_toolkit.history import InMemoryHistory
35 from prompt_toolkit.history import InMemoryHistory
36 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
36 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
37 from prompt_toolkit.output import ColorDepth
37 from prompt_toolkit.output import ColorDepth
38 from prompt_toolkit.patch_stdout import patch_stdout
38 from prompt_toolkit.patch_stdout import patch_stdout
39 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
39 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
40 from prompt_toolkit.styles import DynamicStyle, merge_styles
40 from prompt_toolkit.styles import DynamicStyle, merge_styles
41 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
41 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
42 from prompt_toolkit import __version__ as ptk_version
42 from prompt_toolkit import __version__ as ptk_version
43
43
44 from pygments.styles import get_style_by_name
44 from pygments.styles import get_style_by_name
45 from pygments.style import Style
45 from pygments.style import Style
46 from pygments.token import Token
46 from pygments.token import Token
47
47
48 from .debugger import TerminalPdb, Pdb
48 from .debugger import TerminalPdb, Pdb
49 from .magics import TerminalMagics
49 from .magics import TerminalMagics
50 from .pt_inputhooks import get_inputhook_name_and_func
50 from .pt_inputhooks import get_inputhook_name_and_func
51 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
51 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
52 from .ptutils import IPythonPTCompleter, IPythonPTLexer
52 from .ptutils import IPythonPTCompleter, IPythonPTLexer
53 from .shortcuts import create_ipython_shortcuts
53 from .shortcuts import create_ipython_shortcuts
54
54
55 PTK3 = ptk_version.startswith('3.')
55 PTK3 = ptk_version.startswith('3.')
56
56
57
57
58 class _NoStyle(Style): pass
58 class _NoStyle(Style): pass
59
59
60
60
61
61
62 _style_overrides_light_bg = {
62 _style_overrides_light_bg = {
63 Token.Prompt: '#ansibrightblue',
63 Token.Prompt: '#ansibrightblue',
64 Token.PromptNum: '#ansiblue bold',
64 Token.PromptNum: '#ansiblue bold',
65 Token.OutPrompt: '#ansibrightred',
65 Token.OutPrompt: '#ansibrightred',
66 Token.OutPromptNum: '#ansired bold',
66 Token.OutPromptNum: '#ansired bold',
67 }
67 }
68
68
69 _style_overrides_linux = {
69 _style_overrides_linux = {
70 Token.Prompt: '#ansibrightgreen',
70 Token.Prompt: '#ansibrightgreen',
71 Token.PromptNum: '#ansigreen bold',
71 Token.PromptNum: '#ansigreen bold',
72 Token.OutPrompt: '#ansibrightred',
72 Token.OutPrompt: '#ansibrightred',
73 Token.OutPromptNum: '#ansired bold',
73 Token.OutPromptNum: '#ansired bold',
74 }
74 }
75
75
76 def get_default_editor():
76 def get_default_editor():
77 try:
77 try:
78 return os.environ['EDITOR']
78 return os.environ['EDITOR']
79 except KeyError:
79 except KeyError:
80 pass
80 pass
81 except UnicodeError:
81 except UnicodeError:
82 warn("$EDITOR environment variable is not pure ASCII. Using platform "
82 warn("$EDITOR environment variable is not pure ASCII. Using platform "
83 "default editor.")
83 "default editor.")
84
84
85 if os.name == 'posix':
85 if os.name == 'posix':
86 return 'vi' # the only one guaranteed to be there!
86 return 'vi' # the only one guaranteed to be there!
87 else:
87 else:
88 return 'notepad' # same in Windows!
88 return 'notepad' # same in Windows!
89
89
90 # conservatively check for tty
90 # conservatively check for tty
91 # overridden streams can result in things like:
91 # overridden streams can result in things like:
92 # - sys.stdin = None
92 # - sys.stdin = None
93 # - no isatty method
93 # - no isatty method
94 for _name in ('stdin', 'stdout', 'stderr'):
94 for _name in ('stdin', 'stdout', 'stderr'):
95 _stream = getattr(sys, _name)
95 _stream = getattr(sys, _name)
96 if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
96 if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
97 _is_tty = False
97 _is_tty = False
98 break
98 break
99 else:
99 else:
100 _is_tty = True
100 _is_tty = True
101
101
102
102
103 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
103 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
104
104
105 def black_reformat_handler(text_before_cursor):
105 def black_reformat_handler(text_before_cursor):
106 """
106 """
107 We do not need to protect against error,
107 We do not need to protect against error,
108 this is taken care at a higher level where any reformat error is ignored.
108 this is taken care at a higher level where any reformat error is ignored.
109 Indeed we may call reformatting on incomplete code.
109 Indeed we may call reformatting on incomplete code.
110 """
110 """
111 import black
111 import black
112
112
113 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
113 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
114 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
114 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
115 formatted_text = formatted_text[:-1]
115 formatted_text = formatted_text[:-1]
116 return formatted_text
116 return formatted_text
117
117
118
118
119 class TerminalInteractiveShell(InteractiveShell):
119 class TerminalInteractiveShell(InteractiveShell):
120 mime_renderers = Dict().tag(config=True)
120 mime_renderers = Dict().tag(config=True)
121
121
122 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
122 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
123 'to reserve for the tab completion menu, '
123 'to reserve for the tab completion menu, '
124 'search history, ...etc, the height of '
124 'search history, ...etc, the height of '
125 'these menus will at most this value. '
125 'these menus will at most this value. '
126 'Increase it is you prefer long and skinny '
126 'Increase it is you prefer long and skinny '
127 'menus, decrease for short and wide.'
127 'menus, decrease for short and wide.'
128 ).tag(config=True)
128 ).tag(config=True)
129
129
130 pt_app = None
130 pt_app = None
131 debugger_history = None
131 debugger_history = None
132
132
133 debugger_history_file = Unicode(
133 debugger_history_file = Unicode(
134 "~/.pdbhistory", help="File in which to store and read history"
134 "~/.pdbhistory", help="File in which to store and read history"
135 ).tag(config=True)
135 ).tag(config=True)
136
136
137 simple_prompt = Bool(_use_simple_prompt,
137 simple_prompt = Bool(_use_simple_prompt,
138 help="""Use `raw_input` for the REPL, without completion and prompt colors.
138 help="""Use `raw_input` for the REPL, without completion and prompt colors.
139
139
140 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
140 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
141 IPython own testing machinery, and emacs inferior-shell integration through elpy.
141 IPython own testing machinery, and emacs inferior-shell integration through elpy.
142
142
143 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
143 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
144 environment variable is set, or the current terminal is not a tty."""
144 environment variable is set, or the current terminal is not a tty."""
145 ).tag(config=True)
145 ).tag(config=True)
146
146
147 @property
147 @property
148 def debugger_cls(self):
148 def debugger_cls(self):
149 return Pdb if self.simple_prompt else TerminalPdb
149 return Pdb if self.simple_prompt else TerminalPdb
150
150
151 confirm_exit = Bool(True,
151 confirm_exit = Bool(True,
152 help="""
152 help="""
153 Set to confirm when you try to exit IPython with an EOF (Control-D
153 Set to confirm when you try to exit IPython with an EOF (Control-D
154 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
154 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
155 you can force a direct exit without any confirmation.""",
155 you can force a direct exit without any confirmation.""",
156 ).tag(config=True)
156 ).tag(config=True)
157
157
158 editing_mode = Unicode('emacs',
158 editing_mode = Unicode('emacs',
159 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
159 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
160 ).tag(config=True)
160 ).tag(config=True)
161
161
162 emacs_bindings_in_vi_insert_mode = Bool(
162 emacs_bindings_in_vi_insert_mode = Bool(
163 True,
163 True,
164 help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
164 help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
165 ).tag(config=True)
165 ).tag(config=True)
166
166
167 modal_cursor = Bool(
167 modal_cursor = Bool(
168 True,
168 True,
169 help="""
169 help="""
170 Cursor shape changes depending on vi mode: beam in vi insert mode,
170 Cursor shape changes depending on vi mode: beam in vi insert mode,
171 block in nav mode, underscore in replace mode.""",
171 block in nav mode, underscore in replace mode.""",
172 ).tag(config=True)
172 ).tag(config=True)
173
173
174 ttimeoutlen = Float(
174 ttimeoutlen = Float(
175 0.01,
175 0.01,
176 help="""The time in milliseconds that is waited for a key code
176 help="""The time in milliseconds that is waited for a key code
177 to complete.""",
177 to complete.""",
178 ).tag(config=True)
178 ).tag(config=True)
179
179
180 timeoutlen = Float(
180 timeoutlen = Float(
181 0.5,
181 0.5,
182 help="""The time in milliseconds that is waited for a mapped key
182 help="""The time in milliseconds that is waited for a mapped key
183 sequence to complete.""",
183 sequence to complete.""",
184 ).tag(config=True)
184 ).tag(config=True)
185
185
186 autoformatter = Unicode(
186 autoformatter = Unicode(
187 "black",
187 "black",
188 help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
188 help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
189 allow_none=True
189 allow_none=True
190 ).tag(config=True)
190 ).tag(config=True)
191
191
192 auto_match = Bool(
192 auto_match = Bool(
193 False,
193 False,
194 help="""
194 help="""
195 Automatically add/delete closing bracket or quote when opening bracket or quote is entered/deleted.
195 Automatically add/delete closing bracket or quote when opening bracket or quote is entered/deleted.
196 Brackets: (), [], {}
196 Brackets: (), [], {}
197 Quotes: '', \"\"
197 Quotes: '', \"\"
198 """,
198 """,
199 ).tag(config=True)
199 ).tag(config=True)
200
200
201 mouse_support = Bool(False,
201 mouse_support = Bool(False,
202 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
202 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
203 ).tag(config=True)
203 ).tag(config=True)
204
204
205 # We don't load the list of styles for the help string, because loading
205 # We don't load the list of styles for the help string, because loading
206 # Pygments plugins takes time and can cause unexpected errors.
206 # Pygments plugins takes time and can cause unexpected errors.
207 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
207 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
208 help="""The name or class of a Pygments style to use for syntax
208 help="""The name or class of a Pygments style to use for syntax
209 highlighting. To see available styles, run `pygmentize -L styles`."""
209 highlighting. To see available styles, run `pygmentize -L styles`."""
210 ).tag(config=True)
210 ).tag(config=True)
211
211
212 @validate('editing_mode')
212 @validate('editing_mode')
213 def _validate_editing_mode(self, proposal):
213 def _validate_editing_mode(self, proposal):
214 if proposal['value'].lower() == 'vim':
214 if proposal['value'].lower() == 'vim':
215 proposal['value']= 'vi'
215 proposal['value']= 'vi'
216 elif proposal['value'].lower() == 'default':
216 elif proposal['value'].lower() == 'default':
217 proposal['value']= 'emacs'
217 proposal['value']= 'emacs'
218
218
219 if hasattr(EditingMode, proposal['value'].upper()):
219 if hasattr(EditingMode, proposal['value'].upper()):
220 return proposal['value'].lower()
220 return proposal['value'].lower()
221
221
222 return self.editing_mode
222 return self.editing_mode
223
223
224
224
225 @observe('editing_mode')
225 @observe('editing_mode')
226 def _editing_mode(self, change):
226 def _editing_mode(self, change):
227 if self.pt_app:
227 if self.pt_app:
228 self.pt_app.editing_mode = getattr(EditingMode, change.new.upper())
228 self.pt_app.editing_mode = getattr(EditingMode, change.new.upper())
229
229
230 def _set_formatter(self, formatter):
230 def _set_formatter(self, formatter):
231 if formatter is None:
231 if formatter is None:
232 self.reformat_handler = lambda x:x
232 self.reformat_handler = lambda x:x
233 elif formatter == 'black':
233 elif formatter == 'black':
234 self.reformat_handler = black_reformat_handler
234 self.reformat_handler = black_reformat_handler
235 else:
235 else:
236 raise ValueError
236 raise ValueError
237
237
238 @observe("autoformatter")
238 @observe("autoformatter")
239 def _autoformatter_changed(self, change):
239 def _autoformatter_changed(self, change):
240 formatter = change.new
240 formatter = change.new
241 self._set_formatter(formatter)
241 self._set_formatter(formatter)
242
242
243 @observe('highlighting_style')
243 @observe('highlighting_style')
244 @observe('colors')
244 @observe('colors')
245 def _highlighting_style_changed(self, change):
245 def _highlighting_style_changed(self, change):
246 self.refresh_style()
246 self.refresh_style()
247
247
248 def refresh_style(self):
248 def refresh_style(self):
249 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
249 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
250
250
251
251
252 highlighting_style_overrides = Dict(
252 highlighting_style_overrides = Dict(
253 help="Override highlighting format for specific tokens"
253 help="Override highlighting format for specific tokens"
254 ).tag(config=True)
254 ).tag(config=True)
255
255
256 true_color = Bool(False,
256 true_color = Bool(False,
257 help="""Use 24bit colors instead of 256 colors in prompt highlighting.
257 help="""Use 24bit colors instead of 256 colors in prompt highlighting.
258 If your terminal supports true color, the following command should
258 If your terminal supports true color, the following command should
259 print ``TRUECOLOR`` in orange::
259 print ``TRUECOLOR`` in orange::
260
260
261 printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
261 printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
262 """,
262 """,
263 ).tag(config=True)
263 ).tag(config=True)
264
264
265 editor = Unicode(get_default_editor(),
265 editor = Unicode(get_default_editor(),
266 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
266 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
267 ).tag(config=True)
267 ).tag(config=True)
268
268
269 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
269 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
270
270
271 prompts = Instance(Prompts)
271 prompts = Instance(Prompts)
272
272
273 @default('prompts')
273 @default('prompts')
274 def _prompts_default(self):
274 def _prompts_default(self):
275 return self.prompts_class(self)
275 return self.prompts_class(self)
276
276
277 # @observe('prompts')
277 # @observe('prompts')
278 # def _(self, change):
278 # def _(self, change):
279 # self._update_layout()
279 # self._update_layout()
280
280
281 @default('displayhook_class')
281 @default('displayhook_class')
282 def _displayhook_class_default(self):
282 def _displayhook_class_default(self):
283 return RichPromptDisplayHook
283 return RichPromptDisplayHook
284
284
285 term_title = Bool(True,
285 term_title = Bool(True,
286 help="Automatically set the terminal title"
286 help="Automatically set the terminal title"
287 ).tag(config=True)
287 ).tag(config=True)
288
288
289 term_title_format = Unicode("IPython: {cwd}",
289 term_title_format = Unicode("IPython: {cwd}",
290 help="Customize the terminal title format. This is a python format string. " +
290 help="Customize the terminal title format. This is a python format string. " +
291 "Available substitutions are: {cwd}."
291 "Available substitutions are: {cwd}."
292 ).tag(config=True)
292 ).tag(config=True)
293
293
294 display_completions = Enum(('column', 'multicolumn','readlinelike'),
294 display_completions = Enum(('column', 'multicolumn','readlinelike'),
295 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
295 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
296 "'readlinelike'. These options are for `prompt_toolkit`, see "
296 "'readlinelike'. These options are for `prompt_toolkit`, see "
297 "`prompt_toolkit` documentation for more information."
297 "`prompt_toolkit` documentation for more information."
298 ),
298 ),
299 default_value='multicolumn').tag(config=True)
299 default_value='multicolumn').tag(config=True)
300
300
301 highlight_matching_brackets = Bool(True,
301 highlight_matching_brackets = Bool(True,
302 help="Highlight matching brackets.",
302 help="Highlight matching brackets.",
303 ).tag(config=True)
303 ).tag(config=True)
304
304
305 extra_open_editor_shortcuts = Bool(False,
305 extra_open_editor_shortcuts = Bool(False,
306 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
306 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
307 "This is in addition to the F2 binding, which is always enabled."
307 "This is in addition to the F2 binding, which is always enabled."
308 ).tag(config=True)
308 ).tag(config=True)
309
309
310 handle_return = Any(None,
310 handle_return = Any(None,
311 help="Provide an alternative handler to be called when the user presses "
311 help="Provide an alternative handler to be called when the user presses "
312 "Return. This is an advanced option intended for debugging, which "
312 "Return. This is an advanced option intended for debugging, which "
313 "may be changed or removed in later releases."
313 "may be changed or removed in later releases."
314 ).tag(config=True)
314 ).tag(config=True)
315
315
316 enable_history_search = Bool(True,
316 enable_history_search = Bool(True,
317 help="Allows to enable/disable the prompt toolkit history search"
317 help="Allows to enable/disable the prompt toolkit history search"
318 ).tag(config=True)
318 ).tag(config=True)
319
319
320 autosuggestions_provider = Unicode(
321 "AutoSuggestFromHistory",
322 help="Specifies from which source automatic suggestions are provided. "
323 "Can be set to `'AutoSuggestFromHistory`' or `None` to disable"
324 "automatic suggestions. Default is `'AutoSuggestFromHistory`'.",
325 allow_none=True,
326 ).tag(config=True)
327
328 def _set_autosuggestions(self, provider):
329 if provider is None:
330 self.auto_suggest = None
331 elif provider == "AutoSuggestFromHistory":
332 self.auto_suggest = AutoSuggestFromHistory()
333 else:
334 raise ValueError("No valid provider.")
335 if self.pt_app:
336 self.pt_app.auto_suggest = self.auto_suggest
337
338 @observe("autosuggestions_provider")
339 def _autosuggestions_provider_changed(self, change):
340 provider = change.new
341 self._set_autosuggestions(provider)
342
320 prompt_includes_vi_mode = Bool(True,
343 prompt_includes_vi_mode = Bool(True,
321 help="Display the current vi mode (when using vi editing mode)."
344 help="Display the current vi mode (when using vi editing mode)."
322 ).tag(config=True)
345 ).tag(config=True)
323
346
324 @observe('term_title')
347 @observe('term_title')
325 def init_term_title(self, change=None):
348 def init_term_title(self, change=None):
326 # Enable or disable the terminal title.
349 # Enable or disable the terminal title.
327 if self.term_title:
350 if self.term_title:
328 toggle_set_term_title(True)
351 toggle_set_term_title(True)
329 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
352 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
330 else:
353 else:
331 toggle_set_term_title(False)
354 toggle_set_term_title(False)
332
355
333 def restore_term_title(self):
356 def restore_term_title(self):
334 if self.term_title:
357 if self.term_title:
335 restore_term_title()
358 restore_term_title()
336
359
337 def init_display_formatter(self):
360 def init_display_formatter(self):
338 super(TerminalInteractiveShell, self).init_display_formatter()
361 super(TerminalInteractiveShell, self).init_display_formatter()
339 # terminal only supports plain text
362 # terminal only supports plain text
340 self.display_formatter.active_types = ["text/plain"]
363 self.display_formatter.active_types = ["text/plain"]
341
364
342 def init_prompt_toolkit_cli(self):
365 def init_prompt_toolkit_cli(self):
343 if self.simple_prompt:
366 if self.simple_prompt:
344 # Fall back to plain non-interactive output for tests.
367 # Fall back to plain non-interactive output for tests.
345 # This is very limited.
368 # This is very limited.
346 def prompt():
369 def prompt():
347 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
370 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
348 lines = [input(prompt_text)]
371 lines = [input(prompt_text)]
349 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
372 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
350 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
373 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
351 lines.append( input(prompt_continuation) )
374 lines.append( input(prompt_continuation) )
352 return '\n'.join(lines)
375 return '\n'.join(lines)
353 self.prompt_for_code = prompt
376 self.prompt_for_code = prompt
354 return
377 return
355
378
356 # Set up keyboard shortcuts
379 # Set up keyboard shortcuts
357 key_bindings = create_ipython_shortcuts(self)
380 key_bindings = create_ipython_shortcuts(self)
358
381
359 # Pre-populate history from IPython's history database
382 # Pre-populate history from IPython's history database
360 history = InMemoryHistory()
383 history = InMemoryHistory()
361 last_cell = u""
384 last_cell = u""
362 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
385 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
363 include_latest=True):
386 include_latest=True):
364 # Ignore blank lines and consecutive duplicates
387 # Ignore blank lines and consecutive duplicates
365 cell = cell.rstrip()
388 cell = cell.rstrip()
366 if cell and (cell != last_cell):
389 if cell and (cell != last_cell):
367 history.append_string(cell)
390 history.append_string(cell)
368 last_cell = cell
391 last_cell = cell
369
392
370 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
393 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
371 self.style = DynamicStyle(lambda: self._style)
394 self.style = DynamicStyle(lambda: self._style)
372
395
373 editing_mode = getattr(EditingMode, self.editing_mode.upper())
396 editing_mode = getattr(EditingMode, self.editing_mode.upper())
374
397
375 self.pt_loop = asyncio.new_event_loop()
398 self.pt_loop = asyncio.new_event_loop()
376 self.pt_app = PromptSession(
399 self.pt_app = PromptSession(
377 auto_suggest=AutoSuggestFromHistory(),
400 auto_suggest=self.auto_suggest,
378 editing_mode=editing_mode,
401 editing_mode=editing_mode,
379 key_bindings=key_bindings,
402 key_bindings=key_bindings,
380 history=history,
403 history=history,
381 completer=IPythonPTCompleter(shell=self),
404 completer=IPythonPTCompleter(shell=self),
382 enable_history_search=self.enable_history_search,
405 enable_history_search=self.enable_history_search,
383 style=self.style,
406 style=self.style,
384 include_default_pygments_style=False,
407 include_default_pygments_style=False,
385 mouse_support=self.mouse_support,
408 mouse_support=self.mouse_support,
386 enable_open_in_editor=self.extra_open_editor_shortcuts,
409 enable_open_in_editor=self.extra_open_editor_shortcuts,
387 color_depth=self.color_depth,
410 color_depth=self.color_depth,
388 tempfile_suffix=".py",
411 tempfile_suffix=".py",
389 **self._extra_prompt_options()
412 **self._extra_prompt_options()
390 )
413 )
391
414
392 def _make_style_from_name_or_cls(self, name_or_cls):
415 def _make_style_from_name_or_cls(self, name_or_cls):
393 """
416 """
394 Small wrapper that make an IPython compatible style from a style name
417 Small wrapper that make an IPython compatible style from a style name
395
418
396 We need that to add style for prompt ... etc.
419 We need that to add style for prompt ... etc.
397 """
420 """
398 style_overrides = {}
421 style_overrides = {}
399 if name_or_cls == 'legacy':
422 if name_or_cls == 'legacy':
400 legacy = self.colors.lower()
423 legacy = self.colors.lower()
401 if legacy == 'linux':
424 if legacy == 'linux':
402 style_cls = get_style_by_name('monokai')
425 style_cls = get_style_by_name('monokai')
403 style_overrides = _style_overrides_linux
426 style_overrides = _style_overrides_linux
404 elif legacy == 'lightbg':
427 elif legacy == 'lightbg':
405 style_overrides = _style_overrides_light_bg
428 style_overrides = _style_overrides_light_bg
406 style_cls = get_style_by_name('pastie')
429 style_cls = get_style_by_name('pastie')
407 elif legacy == 'neutral':
430 elif legacy == 'neutral':
408 # The default theme needs to be visible on both a dark background
431 # The default theme needs to be visible on both a dark background
409 # and a light background, because we can't tell what the terminal
432 # and a light background, because we can't tell what the terminal
410 # looks like. These tweaks to the default theme help with that.
433 # looks like. These tweaks to the default theme help with that.
411 style_cls = get_style_by_name('default')
434 style_cls = get_style_by_name('default')
412 style_overrides.update({
435 style_overrides.update({
413 Token.Number: '#ansigreen',
436 Token.Number: '#ansigreen',
414 Token.Operator: 'noinherit',
437 Token.Operator: 'noinherit',
415 Token.String: '#ansiyellow',
438 Token.String: '#ansiyellow',
416 Token.Name.Function: '#ansiblue',
439 Token.Name.Function: '#ansiblue',
417 Token.Name.Class: 'bold #ansiblue',
440 Token.Name.Class: 'bold #ansiblue',
418 Token.Name.Namespace: 'bold #ansiblue',
441 Token.Name.Namespace: 'bold #ansiblue',
419 Token.Name.Variable.Magic: '#ansiblue',
442 Token.Name.Variable.Magic: '#ansiblue',
420 Token.Prompt: '#ansigreen',
443 Token.Prompt: '#ansigreen',
421 Token.PromptNum: '#ansibrightgreen bold',
444 Token.PromptNum: '#ansibrightgreen bold',
422 Token.OutPrompt: '#ansired',
445 Token.OutPrompt: '#ansired',
423 Token.OutPromptNum: '#ansibrightred bold',
446 Token.OutPromptNum: '#ansibrightred bold',
424 })
447 })
425
448
426 # Hack: Due to limited color support on the Windows console
449 # Hack: Due to limited color support on the Windows console
427 # the prompt colors will be wrong without this
450 # the prompt colors will be wrong without this
428 if os.name == 'nt':
451 if os.name == 'nt':
429 style_overrides.update({
452 style_overrides.update({
430 Token.Prompt: '#ansidarkgreen',
453 Token.Prompt: '#ansidarkgreen',
431 Token.PromptNum: '#ansigreen bold',
454 Token.PromptNum: '#ansigreen bold',
432 Token.OutPrompt: '#ansidarkred',
455 Token.OutPrompt: '#ansidarkred',
433 Token.OutPromptNum: '#ansired bold',
456 Token.OutPromptNum: '#ansired bold',
434 })
457 })
435 elif legacy =='nocolor':
458 elif legacy =='nocolor':
436 style_cls=_NoStyle
459 style_cls=_NoStyle
437 style_overrides = {}
460 style_overrides = {}
438 else :
461 else :
439 raise ValueError('Got unknown colors: ', legacy)
462 raise ValueError('Got unknown colors: ', legacy)
440 else :
463 else :
441 if isinstance(name_or_cls, str):
464 if isinstance(name_or_cls, str):
442 style_cls = get_style_by_name(name_or_cls)
465 style_cls = get_style_by_name(name_or_cls)
443 else:
466 else:
444 style_cls = name_or_cls
467 style_cls = name_or_cls
445 style_overrides = {
468 style_overrides = {
446 Token.Prompt: '#ansigreen',
469 Token.Prompt: '#ansigreen',
447 Token.PromptNum: '#ansibrightgreen bold',
470 Token.PromptNum: '#ansibrightgreen bold',
448 Token.OutPrompt: '#ansired',
471 Token.OutPrompt: '#ansired',
449 Token.OutPromptNum: '#ansibrightred bold',
472 Token.OutPromptNum: '#ansibrightred bold',
450 }
473 }
451 style_overrides.update(self.highlighting_style_overrides)
474 style_overrides.update(self.highlighting_style_overrides)
452 style = merge_styles([
475 style = merge_styles([
453 style_from_pygments_cls(style_cls),
476 style_from_pygments_cls(style_cls),
454 style_from_pygments_dict(style_overrides),
477 style_from_pygments_dict(style_overrides),
455 ])
478 ])
456
479
457 return style
480 return style
458
481
459 @property
482 @property
460 def pt_complete_style(self):
483 def pt_complete_style(self):
461 return {
484 return {
462 'multicolumn': CompleteStyle.MULTI_COLUMN,
485 'multicolumn': CompleteStyle.MULTI_COLUMN,
463 'column': CompleteStyle.COLUMN,
486 'column': CompleteStyle.COLUMN,
464 'readlinelike': CompleteStyle.READLINE_LIKE,
487 'readlinelike': CompleteStyle.READLINE_LIKE,
465 }[self.display_completions]
488 }[self.display_completions]
466
489
467 @property
490 @property
468 def color_depth(self):
491 def color_depth(self):
469 return (ColorDepth.TRUE_COLOR if self.true_color else None)
492 return (ColorDepth.TRUE_COLOR if self.true_color else None)
470
493
471 def _extra_prompt_options(self):
494 def _extra_prompt_options(self):
472 """
495 """
473 Return the current layout option for the current Terminal InteractiveShell
496 Return the current layout option for the current Terminal InteractiveShell
474 """
497 """
475 def get_message():
498 def get_message():
476 return PygmentsTokens(self.prompts.in_prompt_tokens())
499 return PygmentsTokens(self.prompts.in_prompt_tokens())
477
500
478 if self.editing_mode == 'emacs':
501 if self.editing_mode == 'emacs':
479 # with emacs mode the prompt is (usually) static, so we call only
502 # with emacs mode the prompt is (usually) static, so we call only
480 # the function once. With VI mode it can toggle between [ins] and
503 # the function once. With VI mode it can toggle between [ins] and
481 # [nor] so we can't precompute.
504 # [nor] so we can't precompute.
482 # here I'm going to favor the default keybinding which almost
505 # here I'm going to favor the default keybinding which almost
483 # everybody uses to decrease CPU usage.
506 # everybody uses to decrease CPU usage.
484 # if we have issues with users with custom Prompts we can see how to
507 # if we have issues with users with custom Prompts we can see how to
485 # work around this.
508 # work around this.
486 get_message = get_message()
509 get_message = get_message()
487
510
488 options = {
511 options = {
489 'complete_in_thread': False,
512 'complete_in_thread': False,
490 'lexer':IPythonPTLexer(),
513 'lexer':IPythonPTLexer(),
491 'reserve_space_for_menu':self.space_for_menu,
514 'reserve_space_for_menu':self.space_for_menu,
492 'message': get_message,
515 'message': get_message,
493 'prompt_continuation': (
516 'prompt_continuation': (
494 lambda width, lineno, is_soft_wrap:
517 lambda width, lineno, is_soft_wrap:
495 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
518 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
496 'multiline': True,
519 'multiline': True,
497 'complete_style': self.pt_complete_style,
520 'complete_style': self.pt_complete_style,
498
521
499 # Highlight matching brackets, but only when this setting is
522 # Highlight matching brackets, but only when this setting is
500 # enabled, and only when the DEFAULT_BUFFER has the focus.
523 # enabled, and only when the DEFAULT_BUFFER has the focus.
501 'input_processors': [ConditionalProcessor(
524 'input_processors': [ConditionalProcessor(
502 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
525 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
503 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
526 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
504 Condition(lambda: self.highlight_matching_brackets))],
527 Condition(lambda: self.highlight_matching_brackets))],
505 }
528 }
506 if not PTK3:
529 if not PTK3:
507 options['inputhook'] = self.inputhook
530 options['inputhook'] = self.inputhook
508
531
509 return options
532 return options
510
533
511 def prompt_for_code(self):
534 def prompt_for_code(self):
512 if self.rl_next_input:
535 if self.rl_next_input:
513 default = self.rl_next_input
536 default = self.rl_next_input
514 self.rl_next_input = None
537 self.rl_next_input = None
515 else:
538 else:
516 default = ''
539 default = ''
517
540
518 # In order to make sure that asyncio code written in the
541 # In order to make sure that asyncio code written in the
519 # interactive shell doesn't interfere with the prompt, we run the
542 # interactive shell doesn't interfere with the prompt, we run the
520 # prompt in a different event loop.
543 # prompt in a different event loop.
521 # If we don't do this, people could spawn coroutine with a
544 # If we don't do this, people could spawn coroutine with a
522 # while/true inside which will freeze the prompt.
545 # while/true inside which will freeze the prompt.
523
546
524 policy = asyncio.get_event_loop_policy()
547 policy = asyncio.get_event_loop_policy()
525 old_loop = get_asyncio_loop()
548 old_loop = get_asyncio_loop()
526
549
527 # FIXME: prompt_toolkit is using the deprecated `asyncio.get_event_loop`
550 # FIXME: prompt_toolkit is using the deprecated `asyncio.get_event_loop`
528 # to get the current event loop.
551 # to get the current event loop.
529 # This will probably be replaced by an attribute or input argument,
552 # This will probably be replaced by an attribute or input argument,
530 # at which point we can stop calling the soon-to-be-deprecated `set_event_loop` here.
553 # at which point we can stop calling the soon-to-be-deprecated `set_event_loop` here.
531 if old_loop is not self.pt_loop:
554 if old_loop is not self.pt_loop:
532 policy.set_event_loop(self.pt_loop)
555 policy.set_event_loop(self.pt_loop)
533 try:
556 try:
534 with patch_stdout(raw=True):
557 with patch_stdout(raw=True):
535 text = self.pt_app.prompt(
558 text = self.pt_app.prompt(
536 default=default,
559 default=default,
537 **self._extra_prompt_options())
560 **self._extra_prompt_options())
538 finally:
561 finally:
539 # Restore the original event loop.
562 # Restore the original event loop.
540 if old_loop is not None and old_loop is not self.pt_loop:
563 if old_loop is not None and old_loop is not self.pt_loop:
541 policy.set_event_loop(old_loop)
564 policy.set_event_loop(old_loop)
542
565
543 return text
566 return text
544
567
545 def enable_win_unicode_console(self):
568 def enable_win_unicode_console(self):
546 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
569 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
547 # console by default, so WUC shouldn't be needed.
570 # console by default, so WUC shouldn't be needed.
548 from warnings import warn
571 from warnings import warn
549 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
572 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
550 DeprecationWarning,
573 DeprecationWarning,
551 stacklevel=2)
574 stacklevel=2)
552
575
553 def init_io(self):
576 def init_io(self):
554 if sys.platform not in {'win32', 'cli'}:
577 if sys.platform not in {'win32', 'cli'}:
555 return
578 return
556
579
557 import colorama
580 import colorama
558 colorama.init()
581 colorama.init()
559
582
560 def init_magics(self):
583 def init_magics(self):
561 super(TerminalInteractiveShell, self).init_magics()
584 super(TerminalInteractiveShell, self).init_magics()
562 self.register_magics(TerminalMagics)
585 self.register_magics(TerminalMagics)
563
586
564 def init_alias(self):
587 def init_alias(self):
565 # The parent class defines aliases that can be safely used with any
588 # The parent class defines aliases that can be safely used with any
566 # frontend.
589 # frontend.
567 super(TerminalInteractiveShell, self).init_alias()
590 super(TerminalInteractiveShell, self).init_alias()
568
591
569 # Now define aliases that only make sense on the terminal, because they
592 # Now define aliases that only make sense on the terminal, because they
570 # need direct access to the console in a way that we can't emulate in
593 # need direct access to the console in a way that we can't emulate in
571 # GUI or web frontend
594 # GUI or web frontend
572 if os.name == 'posix':
595 if os.name == 'posix':
573 for cmd in ('clear', 'more', 'less', 'man'):
596 for cmd in ('clear', 'more', 'less', 'man'):
574 self.alias_manager.soft_define_alias(cmd, cmd)
597 self.alias_manager.soft_define_alias(cmd, cmd)
575
598
576
599
577 def __init__(self, *args, **kwargs):
600 def __init__(self, *args, **kwargs):
578 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
601 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
602 self._set_autosuggestions(self.autosuggestions_provider)
579 self.init_prompt_toolkit_cli()
603 self.init_prompt_toolkit_cli()
580 self.init_term_title()
604 self.init_term_title()
581 self.keep_running = True
605 self.keep_running = True
582 self._set_formatter(self.autoformatter)
606 self._set_formatter(self.autoformatter)
583
607
584
608
585 def ask_exit(self):
609 def ask_exit(self):
586 self.keep_running = False
610 self.keep_running = False
587
611
588 rl_next_input = None
612 rl_next_input = None
589
613
590 def interact(self):
614 def interact(self):
591 self.keep_running = True
615 self.keep_running = True
592 while self.keep_running:
616 while self.keep_running:
593 print(self.separate_in, end='')
617 print(self.separate_in, end='')
594
618
595 try:
619 try:
596 code = self.prompt_for_code()
620 code = self.prompt_for_code()
597 except EOFError:
621 except EOFError:
598 if (not self.confirm_exit) \
622 if (not self.confirm_exit) \
599 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
623 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
600 self.ask_exit()
624 self.ask_exit()
601
625
602 else:
626 else:
603 if code:
627 if code:
604 self.run_cell(code, store_history=True)
628 self.run_cell(code, store_history=True)
605
629
606 def mainloop(self):
630 def mainloop(self):
607 # An extra layer of protection in case someone mashing Ctrl-C breaks
631 # An extra layer of protection in case someone mashing Ctrl-C breaks
608 # out of our internal code.
632 # out of our internal code.
609 while True:
633 while True:
610 try:
634 try:
611 self.interact()
635 self.interact()
612 break
636 break
613 except KeyboardInterrupt as e:
637 except KeyboardInterrupt as e:
614 print("\n%s escaped interact()\n" % type(e).__name__)
638 print("\n%s escaped interact()\n" % type(e).__name__)
615 finally:
639 finally:
616 # An interrupt during the eventloop will mess up the
640 # An interrupt during the eventloop will mess up the
617 # internal state of the prompt_toolkit library.
641 # internal state of the prompt_toolkit library.
618 # Stopping the eventloop fixes this, see
642 # Stopping the eventloop fixes this, see
619 # https://github.com/ipython/ipython/pull/9867
643 # https://github.com/ipython/ipython/pull/9867
620 if hasattr(self, '_eventloop'):
644 if hasattr(self, '_eventloop'):
621 self._eventloop.stop()
645 self._eventloop.stop()
622
646
623 self.restore_term_title()
647 self.restore_term_title()
624
648
625 # try to call some at-exit operation optimistically as some things can't
649 # try to call some at-exit operation optimistically as some things can't
626 # be done during interpreter shutdown. this is technically inaccurate as
650 # be done during interpreter shutdown. this is technically inaccurate as
627 # this make mainlool not re-callable, but that should be a rare if not
651 # this make mainlool not re-callable, but that should be a rare if not
628 # in existent use case.
652 # in existent use case.
629
653
630 self._atexit_once()
654 self._atexit_once()
631
655
632
656
633 _inputhook = None
657 _inputhook = None
634 def inputhook(self, context):
658 def inputhook(self, context):
635 if self._inputhook is not None:
659 if self._inputhook is not None:
636 self._inputhook(context)
660 self._inputhook(context)
637
661
638 active_eventloop = None
662 active_eventloop = None
639 def enable_gui(self, gui=None):
663 def enable_gui(self, gui=None):
640 if gui and (gui != 'inline') :
664 if gui and (gui != 'inline') :
641 self.active_eventloop, self._inputhook =\
665 self.active_eventloop, self._inputhook =\
642 get_inputhook_name_and_func(gui)
666 get_inputhook_name_and_func(gui)
643 else:
667 else:
644 self.active_eventloop = self._inputhook = None
668 self.active_eventloop = self._inputhook = None
645
669
646 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
670 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
647 # this inputhook.
671 # this inputhook.
648 if PTK3:
672 if PTK3:
649 import asyncio
673 import asyncio
650 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
674 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
651
675
652 if gui == 'asyncio':
676 if gui == 'asyncio':
653 # When we integrate the asyncio event loop, run the UI in the
677 # When we integrate the asyncio event loop, run the UI in the
654 # same event loop as the rest of the code. don't use an actual
678 # same event loop as the rest of the code. don't use an actual
655 # input hook. (Asyncio is not made for nesting event loops.)
679 # input hook. (Asyncio is not made for nesting event loops.)
656 self.pt_loop = get_asyncio_loop()
680 self.pt_loop = get_asyncio_loop()
657
681
658 elif self._inputhook:
682 elif self._inputhook:
659 # If an inputhook was set, create a new asyncio event loop with
683 # If an inputhook was set, create a new asyncio event loop with
660 # this inputhook for the prompt.
684 # this inputhook for the prompt.
661 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
685 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
662 else:
686 else:
663 # When there's no inputhook, run the prompt in a separate
687 # When there's no inputhook, run the prompt in a separate
664 # asyncio event loop.
688 # asyncio event loop.
665 self.pt_loop = asyncio.new_event_loop()
689 self.pt_loop = asyncio.new_event_loop()
666
690
667 # Run !system commands directly, not through pipes, so terminal programs
691 # Run !system commands directly, not through pipes, so terminal programs
668 # work correctly.
692 # work correctly.
669 system = InteractiveShell.system_raw
693 system = InteractiveShell.system_raw
670
694
671 def auto_rewrite_input(self, cmd):
695 def auto_rewrite_input(self, cmd):
672 """Overridden from the parent class to use fancy rewriting prompt"""
696 """Overridden from the parent class to use fancy rewriting prompt"""
673 if not self.show_rewritten_input:
697 if not self.show_rewritten_input:
674 return
698 return
675
699
676 tokens = self.prompts.rewrite_prompt_tokens()
700 tokens = self.prompts.rewrite_prompt_tokens()
677 if self.pt_app:
701 if self.pt_app:
678 print_formatted_text(PygmentsTokens(tokens), end='',
702 print_formatted_text(PygmentsTokens(tokens), end='',
679 style=self.pt_app.app.style)
703 style=self.pt_app.app.style)
680 print(cmd)
704 print(cmd)
681 else:
705 else:
682 prompt = ''.join(s for t, s in tokens)
706 prompt = ''.join(s for t, s in tokens)
683 print(prompt, cmd, sep='')
707 print(prompt, cmd, sep='')
684
708
685 _prompts_before = None
709 _prompts_before = None
686 def switch_doctest_mode(self, mode):
710 def switch_doctest_mode(self, mode):
687 """Switch prompts to classic for %doctest_mode"""
711 """Switch prompts to classic for %doctest_mode"""
688 if mode:
712 if mode:
689 self._prompts_before = self.prompts
713 self._prompts_before = self.prompts
690 self.prompts = ClassicPrompts(self)
714 self.prompts = ClassicPrompts(self)
691 elif self._prompts_before:
715 elif self._prompts_before:
692 self.prompts = self._prompts_before
716 self.prompts = self._prompts_before
693 self._prompts_before = None
717 self._prompts_before = None
694 # self._update_layout()
718 # self._update_layout()
695
719
696
720
697 InteractiveShellABC.register(TerminalInteractiveShell)
721 InteractiveShellABC.register(TerminalInteractiveShell)
698
722
699 if __name__ == '__main__':
723 if __name__ == '__main__':
700 TerminalInteractiveShell.instance().interact()
724 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now