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