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