##// END OF EJS Templates
Update IPython/terminal/interactiveshell.py
Matthias Bussonnier -
Show More
@@ -1,728 +1,725 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(
320 autosuggestions_provider = Unicode(
321 "AutoSuggestFromHistory",
321 "AutoSuggestFromHistory",
322 help="Specifies from which source automatic suggestions are provided. "
322 help="Specifies from which source automatic suggestions are provided. "
323 "Can be set to `'AutoSuggestFromHistory`' or `None` to disable"
323 "Can be set to `'AutoSuggestFromHistory`' or `None` to disable"
324 "automatic suggestions. Default is `'AutoSuggestFromHistory`'.",
324 "automatic suggestions. Default is `'AutoSuggestFromHistory`'.",
325 allow_none=True,
325 allow_none=True,
326 ).tag(config=True)
326 ).tag(config=True)
327
327
328 prompt_includes_vi_mode = Bool(
329 True, help="Display the current vi mode (when using vi editing mode)."
330 ).tag(config=True)
331
328
332 def _set_autosuggestions(self, provider):
329 def _set_autosuggestions(self, provider):
333 if provider is None:
330 if provider is None:
334 self.auto_suggest = None
331 self.auto_suggest = None
335 elif provider == "AutoSuggestFromHistory":
332 elif provider == "AutoSuggestFromHistory":
336 self.auto_suggest = AutoSuggestFromHistory()
333 self.auto_suggest = AutoSuggestFromHistory()
337 else:
334 else:
338 raise ValueError("No valid provider.")
335 raise ValueError("No valid provider.")
339 if self.pt_app:
336 if self.pt_app:
340 self.pt_app.auto_suggest = self.auto_suggest
337 self.pt_app.auto_suggest = self.auto_suggest
341
338
342 @observe("autosuggestions_provider")
339 @observe("autosuggestions_provider")
343 def _autosuggestions_provider_changed(self, change):
340 def _autosuggestions_provider_changed(self, change):
344 provider = change.new
341 provider = change.new
345 self._set_autosuggestions(provider)
342 self._set_autosuggestions(provider)
346
343
347 prompt_includes_vi_mode = Bool(True,
344 prompt_includes_vi_mode = Bool(True,
348 help="Display the current vi mode (when using vi editing mode)."
345 help="Display the current vi mode (when using vi editing mode)."
349 ).tag(config=True)
346 ).tag(config=True)
350
347
351 @observe('term_title')
348 @observe('term_title')
352 def init_term_title(self, change=None):
349 def init_term_title(self, change=None):
353 # Enable or disable the terminal title.
350 # Enable or disable the terminal title.
354 if self.term_title:
351 if self.term_title:
355 toggle_set_term_title(True)
352 toggle_set_term_title(True)
356 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
353 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
357 else:
354 else:
358 toggle_set_term_title(False)
355 toggle_set_term_title(False)
359
356
360 def restore_term_title(self):
357 def restore_term_title(self):
361 if self.term_title:
358 if self.term_title:
362 restore_term_title()
359 restore_term_title()
363
360
364 def init_display_formatter(self):
361 def init_display_formatter(self):
365 super(TerminalInteractiveShell, self).init_display_formatter()
362 super(TerminalInteractiveShell, self).init_display_formatter()
366 # terminal only supports plain text
363 # terminal only supports plain text
367 self.display_formatter.active_types = ["text/plain"]
364 self.display_formatter.active_types = ["text/plain"]
368
365
369 def init_prompt_toolkit_cli(self):
366 def init_prompt_toolkit_cli(self):
370 if self.simple_prompt:
367 if self.simple_prompt:
371 # Fall back to plain non-interactive output for tests.
368 # Fall back to plain non-interactive output for tests.
372 # This is very limited.
369 # This is very limited.
373 def prompt():
370 def prompt():
374 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
371 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
375 lines = [input(prompt_text)]
372 lines = [input(prompt_text)]
376 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
373 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
377 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
374 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
378 lines.append( input(prompt_continuation) )
375 lines.append( input(prompt_continuation) )
379 return '\n'.join(lines)
376 return '\n'.join(lines)
380 self.prompt_for_code = prompt
377 self.prompt_for_code = prompt
381 return
378 return
382
379
383 # Set up keyboard shortcuts
380 # Set up keyboard shortcuts
384 key_bindings = create_ipython_shortcuts(self)
381 key_bindings = create_ipython_shortcuts(self)
385
382
386 # Pre-populate history from IPython's history database
383 # Pre-populate history from IPython's history database
387 history = InMemoryHistory()
384 history = InMemoryHistory()
388 last_cell = u""
385 last_cell = u""
389 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
386 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
390 include_latest=True):
387 include_latest=True):
391 # Ignore blank lines and consecutive duplicates
388 # Ignore blank lines and consecutive duplicates
392 cell = cell.rstrip()
389 cell = cell.rstrip()
393 if cell and (cell != last_cell):
390 if cell and (cell != last_cell):
394 history.append_string(cell)
391 history.append_string(cell)
395 last_cell = cell
392 last_cell = cell
396
393
397 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
394 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
398 self.style = DynamicStyle(lambda: self._style)
395 self.style = DynamicStyle(lambda: self._style)
399
396
400 editing_mode = getattr(EditingMode, self.editing_mode.upper())
397 editing_mode = getattr(EditingMode, self.editing_mode.upper())
401
398
402 self.pt_loop = asyncio.new_event_loop()
399 self.pt_loop = asyncio.new_event_loop()
403 self.pt_app = PromptSession(
400 self.pt_app = PromptSession(
404 auto_suggest=self.auto_suggest,
401 auto_suggest=self.auto_suggest,
405 editing_mode=editing_mode,
402 editing_mode=editing_mode,
406 key_bindings=key_bindings,
403 key_bindings=key_bindings,
407 history=history,
404 history=history,
408 completer=IPythonPTCompleter(shell=self),
405 completer=IPythonPTCompleter(shell=self),
409 enable_history_search=self.enable_history_search,
406 enable_history_search=self.enable_history_search,
410 style=self.style,
407 style=self.style,
411 include_default_pygments_style=False,
408 include_default_pygments_style=False,
412 mouse_support=self.mouse_support,
409 mouse_support=self.mouse_support,
413 enable_open_in_editor=self.extra_open_editor_shortcuts,
410 enable_open_in_editor=self.extra_open_editor_shortcuts,
414 color_depth=self.color_depth,
411 color_depth=self.color_depth,
415 tempfile_suffix=".py",
412 tempfile_suffix=".py",
416 **self._extra_prompt_options()
413 **self._extra_prompt_options()
417 )
414 )
418
415
419 def _make_style_from_name_or_cls(self, name_or_cls):
416 def _make_style_from_name_or_cls(self, name_or_cls):
420 """
417 """
421 Small wrapper that make an IPython compatible style from a style name
418 Small wrapper that make an IPython compatible style from a style name
422
419
423 We need that to add style for prompt ... etc.
420 We need that to add style for prompt ... etc.
424 """
421 """
425 style_overrides = {}
422 style_overrides = {}
426 if name_or_cls == 'legacy':
423 if name_or_cls == 'legacy':
427 legacy = self.colors.lower()
424 legacy = self.colors.lower()
428 if legacy == 'linux':
425 if legacy == 'linux':
429 style_cls = get_style_by_name('monokai')
426 style_cls = get_style_by_name('monokai')
430 style_overrides = _style_overrides_linux
427 style_overrides = _style_overrides_linux
431 elif legacy == 'lightbg':
428 elif legacy == 'lightbg':
432 style_overrides = _style_overrides_light_bg
429 style_overrides = _style_overrides_light_bg
433 style_cls = get_style_by_name('pastie')
430 style_cls = get_style_by_name('pastie')
434 elif legacy == 'neutral':
431 elif legacy == 'neutral':
435 # The default theme needs to be visible on both a dark background
432 # The default theme needs to be visible on both a dark background
436 # and a light background, because we can't tell what the terminal
433 # and a light background, because we can't tell what the terminal
437 # looks like. These tweaks to the default theme help with that.
434 # looks like. These tweaks to the default theme help with that.
438 style_cls = get_style_by_name('default')
435 style_cls = get_style_by_name('default')
439 style_overrides.update({
436 style_overrides.update({
440 Token.Number: '#ansigreen',
437 Token.Number: '#ansigreen',
441 Token.Operator: 'noinherit',
438 Token.Operator: 'noinherit',
442 Token.String: '#ansiyellow',
439 Token.String: '#ansiyellow',
443 Token.Name.Function: '#ansiblue',
440 Token.Name.Function: '#ansiblue',
444 Token.Name.Class: 'bold #ansiblue',
441 Token.Name.Class: 'bold #ansiblue',
445 Token.Name.Namespace: 'bold #ansiblue',
442 Token.Name.Namespace: 'bold #ansiblue',
446 Token.Name.Variable.Magic: '#ansiblue',
443 Token.Name.Variable.Magic: '#ansiblue',
447 Token.Prompt: '#ansigreen',
444 Token.Prompt: '#ansigreen',
448 Token.PromptNum: '#ansibrightgreen bold',
445 Token.PromptNum: '#ansibrightgreen bold',
449 Token.OutPrompt: '#ansired',
446 Token.OutPrompt: '#ansired',
450 Token.OutPromptNum: '#ansibrightred bold',
447 Token.OutPromptNum: '#ansibrightred bold',
451 })
448 })
452
449
453 # Hack: Due to limited color support on the Windows console
450 # Hack: Due to limited color support on the Windows console
454 # the prompt colors will be wrong without this
451 # the prompt colors will be wrong without this
455 if os.name == 'nt':
452 if os.name == 'nt':
456 style_overrides.update({
453 style_overrides.update({
457 Token.Prompt: '#ansidarkgreen',
454 Token.Prompt: '#ansidarkgreen',
458 Token.PromptNum: '#ansigreen bold',
455 Token.PromptNum: '#ansigreen bold',
459 Token.OutPrompt: '#ansidarkred',
456 Token.OutPrompt: '#ansidarkred',
460 Token.OutPromptNum: '#ansired bold',
457 Token.OutPromptNum: '#ansired bold',
461 })
458 })
462 elif legacy =='nocolor':
459 elif legacy =='nocolor':
463 style_cls=_NoStyle
460 style_cls=_NoStyle
464 style_overrides = {}
461 style_overrides = {}
465 else :
462 else :
466 raise ValueError('Got unknown colors: ', legacy)
463 raise ValueError('Got unknown colors: ', legacy)
467 else :
464 else :
468 if isinstance(name_or_cls, str):
465 if isinstance(name_or_cls, str):
469 style_cls = get_style_by_name(name_or_cls)
466 style_cls = get_style_by_name(name_or_cls)
470 else:
467 else:
471 style_cls = name_or_cls
468 style_cls = name_or_cls
472 style_overrides = {
469 style_overrides = {
473 Token.Prompt: '#ansigreen',
470 Token.Prompt: '#ansigreen',
474 Token.PromptNum: '#ansibrightgreen bold',
471 Token.PromptNum: '#ansibrightgreen bold',
475 Token.OutPrompt: '#ansired',
472 Token.OutPrompt: '#ansired',
476 Token.OutPromptNum: '#ansibrightred bold',
473 Token.OutPromptNum: '#ansibrightred bold',
477 }
474 }
478 style_overrides.update(self.highlighting_style_overrides)
475 style_overrides.update(self.highlighting_style_overrides)
479 style = merge_styles([
476 style = merge_styles([
480 style_from_pygments_cls(style_cls),
477 style_from_pygments_cls(style_cls),
481 style_from_pygments_dict(style_overrides),
478 style_from_pygments_dict(style_overrides),
482 ])
479 ])
483
480
484 return style
481 return style
485
482
486 @property
483 @property
487 def pt_complete_style(self):
484 def pt_complete_style(self):
488 return {
485 return {
489 'multicolumn': CompleteStyle.MULTI_COLUMN,
486 'multicolumn': CompleteStyle.MULTI_COLUMN,
490 'column': CompleteStyle.COLUMN,
487 'column': CompleteStyle.COLUMN,
491 'readlinelike': CompleteStyle.READLINE_LIKE,
488 'readlinelike': CompleteStyle.READLINE_LIKE,
492 }[self.display_completions]
489 }[self.display_completions]
493
490
494 @property
491 @property
495 def color_depth(self):
492 def color_depth(self):
496 return (ColorDepth.TRUE_COLOR if self.true_color else None)
493 return (ColorDepth.TRUE_COLOR if self.true_color else None)
497
494
498 def _extra_prompt_options(self):
495 def _extra_prompt_options(self):
499 """
496 """
500 Return the current layout option for the current Terminal InteractiveShell
497 Return the current layout option for the current Terminal InteractiveShell
501 """
498 """
502 def get_message():
499 def get_message():
503 return PygmentsTokens(self.prompts.in_prompt_tokens())
500 return PygmentsTokens(self.prompts.in_prompt_tokens())
504
501
505 if self.editing_mode == 'emacs':
502 if self.editing_mode == 'emacs':
506 # with emacs mode the prompt is (usually) static, so we call only
503 # with emacs mode the prompt is (usually) static, so we call only
507 # the function once. With VI mode it can toggle between [ins] and
504 # the function once. With VI mode it can toggle between [ins] and
508 # [nor] so we can't precompute.
505 # [nor] so we can't precompute.
509 # here I'm going to favor the default keybinding which almost
506 # here I'm going to favor the default keybinding which almost
510 # everybody uses to decrease CPU usage.
507 # everybody uses to decrease CPU usage.
511 # if we have issues with users with custom Prompts we can see how to
508 # if we have issues with users with custom Prompts we can see how to
512 # work around this.
509 # work around this.
513 get_message = get_message()
510 get_message = get_message()
514
511
515 options = {
512 options = {
516 'complete_in_thread': False,
513 'complete_in_thread': False,
517 'lexer':IPythonPTLexer(),
514 'lexer':IPythonPTLexer(),
518 'reserve_space_for_menu':self.space_for_menu,
515 'reserve_space_for_menu':self.space_for_menu,
519 'message': get_message,
516 'message': get_message,
520 'prompt_continuation': (
517 'prompt_continuation': (
521 lambda width, lineno, is_soft_wrap:
518 lambda width, lineno, is_soft_wrap:
522 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
519 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
523 'multiline': True,
520 'multiline': True,
524 'complete_style': self.pt_complete_style,
521 'complete_style': self.pt_complete_style,
525
522
526 # Highlight matching brackets, but only when this setting is
523 # Highlight matching brackets, but only when this setting is
527 # enabled, and only when the DEFAULT_BUFFER has the focus.
524 # enabled, and only when the DEFAULT_BUFFER has the focus.
528 'input_processors': [ConditionalProcessor(
525 'input_processors': [ConditionalProcessor(
529 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
526 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
530 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
527 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
531 Condition(lambda: self.highlight_matching_brackets))],
528 Condition(lambda: self.highlight_matching_brackets))],
532 }
529 }
533 if not PTK3:
530 if not PTK3:
534 options['inputhook'] = self.inputhook
531 options['inputhook'] = self.inputhook
535
532
536 return options
533 return options
537
534
538 def prompt_for_code(self):
535 def prompt_for_code(self):
539 if self.rl_next_input:
536 if self.rl_next_input:
540 default = self.rl_next_input
537 default = self.rl_next_input
541 self.rl_next_input = None
538 self.rl_next_input = None
542 else:
539 else:
543 default = ''
540 default = ''
544
541
545 # In order to make sure that asyncio code written in the
542 # In order to make sure that asyncio code written in the
546 # interactive shell doesn't interfere with the prompt, we run the
543 # interactive shell doesn't interfere with the prompt, we run the
547 # prompt in a different event loop.
544 # prompt in a different event loop.
548 # If we don't do this, people could spawn coroutine with a
545 # If we don't do this, people could spawn coroutine with a
549 # while/true inside which will freeze the prompt.
546 # while/true inside which will freeze the prompt.
550
547
551 policy = asyncio.get_event_loop_policy()
548 policy = asyncio.get_event_loop_policy()
552 old_loop = get_asyncio_loop()
549 old_loop = get_asyncio_loop()
553
550
554 # FIXME: prompt_toolkit is using the deprecated `asyncio.get_event_loop`
551 # FIXME: prompt_toolkit is using the deprecated `asyncio.get_event_loop`
555 # to get the current event loop.
552 # to get the current event loop.
556 # This will probably be replaced by an attribute or input argument,
553 # This will probably be replaced by an attribute or input argument,
557 # at which point we can stop calling the soon-to-be-deprecated `set_event_loop` here.
554 # at which point we can stop calling the soon-to-be-deprecated `set_event_loop` here.
558 if old_loop is not self.pt_loop:
555 if old_loop is not self.pt_loop:
559 policy.set_event_loop(self.pt_loop)
556 policy.set_event_loop(self.pt_loop)
560 try:
557 try:
561 with patch_stdout(raw=True):
558 with patch_stdout(raw=True):
562 text = self.pt_app.prompt(
559 text = self.pt_app.prompt(
563 default=default,
560 default=default,
564 **self._extra_prompt_options())
561 **self._extra_prompt_options())
565 finally:
562 finally:
566 # Restore the original event loop.
563 # Restore the original event loop.
567 if old_loop is not None and old_loop is not self.pt_loop:
564 if old_loop is not None and old_loop is not self.pt_loop:
568 policy.set_event_loop(old_loop)
565 policy.set_event_loop(old_loop)
569
566
570 return text
567 return text
571
568
572 def enable_win_unicode_console(self):
569 def enable_win_unicode_console(self):
573 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
570 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
574 # console by default, so WUC shouldn't be needed.
571 # console by default, so WUC shouldn't be needed.
575 from warnings import warn
572 from warnings import warn
576 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
573 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
577 DeprecationWarning,
574 DeprecationWarning,
578 stacklevel=2)
575 stacklevel=2)
579
576
580 def init_io(self):
577 def init_io(self):
581 if sys.platform not in {'win32', 'cli'}:
578 if sys.platform not in {'win32', 'cli'}:
582 return
579 return
583
580
584 import colorama
581 import colorama
585 colorama.init()
582 colorama.init()
586
583
587 def init_magics(self):
584 def init_magics(self):
588 super(TerminalInteractiveShell, self).init_magics()
585 super(TerminalInteractiveShell, self).init_magics()
589 self.register_magics(TerminalMagics)
586 self.register_magics(TerminalMagics)
590
587
591 def init_alias(self):
588 def init_alias(self):
592 # The parent class defines aliases that can be safely used with any
589 # The parent class defines aliases that can be safely used with any
593 # frontend.
590 # frontend.
594 super(TerminalInteractiveShell, self).init_alias()
591 super(TerminalInteractiveShell, self).init_alias()
595
592
596 # Now define aliases that only make sense on the terminal, because they
593 # Now define aliases that only make sense on the terminal, because they
597 # need direct access to the console in a way that we can't emulate in
594 # need direct access to the console in a way that we can't emulate in
598 # GUI or web frontend
595 # GUI or web frontend
599 if os.name == 'posix':
596 if os.name == 'posix':
600 for cmd in ('clear', 'more', 'less', 'man'):
597 for cmd in ('clear', 'more', 'less', 'man'):
601 self.alias_manager.soft_define_alias(cmd, cmd)
598 self.alias_manager.soft_define_alias(cmd, cmd)
602
599
603
600
604 def __init__(self, *args, **kwargs):
601 def __init__(self, *args, **kwargs):
605 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
602 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
606 self._set_autosuggestions(self.autosuggestions_provider)
603 self._set_autosuggestions(self.autosuggestions_provider)
607 self.init_prompt_toolkit_cli()
604 self.init_prompt_toolkit_cli()
608 self.init_term_title()
605 self.init_term_title()
609 self.keep_running = True
606 self.keep_running = True
610 self._set_formatter(self.autoformatter)
607 self._set_formatter(self.autoformatter)
611
608
612
609
613 def ask_exit(self):
610 def ask_exit(self):
614 self.keep_running = False
611 self.keep_running = False
615
612
616 rl_next_input = None
613 rl_next_input = None
617
614
618 def interact(self):
615 def interact(self):
619 self.keep_running = True
616 self.keep_running = True
620 while self.keep_running:
617 while self.keep_running:
621 print(self.separate_in, end='')
618 print(self.separate_in, end='')
622
619
623 try:
620 try:
624 code = self.prompt_for_code()
621 code = self.prompt_for_code()
625 except EOFError:
622 except EOFError:
626 if (not self.confirm_exit) \
623 if (not self.confirm_exit) \
627 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
624 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
628 self.ask_exit()
625 self.ask_exit()
629
626
630 else:
627 else:
631 if code:
628 if code:
632 self.run_cell(code, store_history=True)
629 self.run_cell(code, store_history=True)
633
630
634 def mainloop(self):
631 def mainloop(self):
635 # An extra layer of protection in case someone mashing Ctrl-C breaks
632 # An extra layer of protection in case someone mashing Ctrl-C breaks
636 # out of our internal code.
633 # out of our internal code.
637 while True:
634 while True:
638 try:
635 try:
639 self.interact()
636 self.interact()
640 break
637 break
641 except KeyboardInterrupt as e:
638 except KeyboardInterrupt as e:
642 print("\n%s escaped interact()\n" % type(e).__name__)
639 print("\n%s escaped interact()\n" % type(e).__name__)
643 finally:
640 finally:
644 # An interrupt during the eventloop will mess up the
641 # An interrupt during the eventloop will mess up the
645 # internal state of the prompt_toolkit library.
642 # internal state of the prompt_toolkit library.
646 # Stopping the eventloop fixes this, see
643 # Stopping the eventloop fixes this, see
647 # https://github.com/ipython/ipython/pull/9867
644 # https://github.com/ipython/ipython/pull/9867
648 if hasattr(self, '_eventloop'):
645 if hasattr(self, '_eventloop'):
649 self._eventloop.stop()
646 self._eventloop.stop()
650
647
651 self.restore_term_title()
648 self.restore_term_title()
652
649
653 # try to call some at-exit operation optimistically as some things can't
650 # try to call some at-exit operation optimistically as some things can't
654 # be done during interpreter shutdown. this is technically inaccurate as
651 # be done during interpreter shutdown. this is technically inaccurate as
655 # this make mainlool not re-callable, but that should be a rare if not
652 # this make mainlool not re-callable, but that should be a rare if not
656 # in existent use case.
653 # in existent use case.
657
654
658 self._atexit_once()
655 self._atexit_once()
659
656
660
657
661 _inputhook = None
658 _inputhook = None
662 def inputhook(self, context):
659 def inputhook(self, context):
663 if self._inputhook is not None:
660 if self._inputhook is not None:
664 self._inputhook(context)
661 self._inputhook(context)
665
662
666 active_eventloop = None
663 active_eventloop = None
667 def enable_gui(self, gui=None):
664 def enable_gui(self, gui=None):
668 if gui and (gui != 'inline') :
665 if gui and (gui != 'inline') :
669 self.active_eventloop, self._inputhook =\
666 self.active_eventloop, self._inputhook =\
670 get_inputhook_name_and_func(gui)
667 get_inputhook_name_and_func(gui)
671 else:
668 else:
672 self.active_eventloop = self._inputhook = None
669 self.active_eventloop = self._inputhook = None
673
670
674 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
671 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
675 # this inputhook.
672 # this inputhook.
676 if PTK3:
673 if PTK3:
677 import asyncio
674 import asyncio
678 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
675 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
679
676
680 if gui == 'asyncio':
677 if gui == 'asyncio':
681 # When we integrate the asyncio event loop, run the UI in the
678 # When we integrate the asyncio event loop, run the UI in the
682 # same event loop as the rest of the code. don't use an actual
679 # same event loop as the rest of the code. don't use an actual
683 # input hook. (Asyncio is not made for nesting event loops.)
680 # input hook. (Asyncio is not made for nesting event loops.)
684 self.pt_loop = get_asyncio_loop()
681 self.pt_loop = get_asyncio_loop()
685
682
686 elif self._inputhook:
683 elif self._inputhook:
687 # If an inputhook was set, create a new asyncio event loop with
684 # If an inputhook was set, create a new asyncio event loop with
688 # this inputhook for the prompt.
685 # this inputhook for the prompt.
689 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
686 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
690 else:
687 else:
691 # When there's no inputhook, run the prompt in a separate
688 # When there's no inputhook, run the prompt in a separate
692 # asyncio event loop.
689 # asyncio event loop.
693 self.pt_loop = asyncio.new_event_loop()
690 self.pt_loop = asyncio.new_event_loop()
694
691
695 # Run !system commands directly, not through pipes, so terminal programs
692 # Run !system commands directly, not through pipes, so terminal programs
696 # work correctly.
693 # work correctly.
697 system = InteractiveShell.system_raw
694 system = InteractiveShell.system_raw
698
695
699 def auto_rewrite_input(self, cmd):
696 def auto_rewrite_input(self, cmd):
700 """Overridden from the parent class to use fancy rewriting prompt"""
697 """Overridden from the parent class to use fancy rewriting prompt"""
701 if not self.show_rewritten_input:
698 if not self.show_rewritten_input:
702 return
699 return
703
700
704 tokens = self.prompts.rewrite_prompt_tokens()
701 tokens = self.prompts.rewrite_prompt_tokens()
705 if self.pt_app:
702 if self.pt_app:
706 print_formatted_text(PygmentsTokens(tokens), end='',
703 print_formatted_text(PygmentsTokens(tokens), end='',
707 style=self.pt_app.app.style)
704 style=self.pt_app.app.style)
708 print(cmd)
705 print(cmd)
709 else:
706 else:
710 prompt = ''.join(s for t, s in tokens)
707 prompt = ''.join(s for t, s in tokens)
711 print(prompt, cmd, sep='')
708 print(prompt, cmd, sep='')
712
709
713 _prompts_before = None
710 _prompts_before = None
714 def switch_doctest_mode(self, mode):
711 def switch_doctest_mode(self, mode):
715 """Switch prompts to classic for %doctest_mode"""
712 """Switch prompts to classic for %doctest_mode"""
716 if mode:
713 if mode:
717 self._prompts_before = self.prompts
714 self._prompts_before = self.prompts
718 self.prompts = ClassicPrompts(self)
715 self.prompts = ClassicPrompts(self)
719 elif self._prompts_before:
716 elif self._prompts_before:
720 self.prompts = self._prompts_before
717 self.prompts = self._prompts_before
721 self._prompts_before = None
718 self._prompts_before = None
722 # self._update_layout()
719 # self._update_layout()
723
720
724
721
725 InteractiveShellABC.register(TerminalInteractiveShell)
722 InteractiveShellABC.register(TerminalInteractiveShell)
726
723
727 if __name__ == '__main__':
724 if __name__ == '__main__':
728 TerminalInteractiveShell.instance().interact()
725 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now