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