##// END OF EJS Templates
Remove unused variable
Artur Svistunov -
Show More
@@ -1,692 +1,691 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 @observe("editing_mode")
205 205 def _editing_mode_changed(self, change):
206 u_mode = change.new.upper()
207 206 if self.pt_app:
208 207 self.init_prompt_toolkit_cli()
209 208
210 209 @observe('autoformatter')
211 210 def _autoformatter_changed(self, change):
212 211 formatter = change.new
213 212 if formatter is None:
214 213 self.reformat_handler = lambda x:x
215 214 elif formatter == 'black':
216 215 self.reformat_handler = black_reformat_handler
217 216 else:
218 217 raise ValueError
219 218
220 219 @observe('highlighting_style')
221 220 @observe('colors')
222 221 def _highlighting_style_changed(self, change):
223 222 self.refresh_style()
224 223
225 224 def refresh_style(self):
226 225 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
227 226
228 227
229 228 highlighting_style_overrides = Dict(
230 229 help="Override highlighting format for specific tokens"
231 230 ).tag(config=True)
232 231
233 232 true_color = Bool(False,
234 233 help="""Use 24bit colors instead of 256 colors in prompt highlighting.
235 234 If your terminal supports true color, the following command should
236 235 print ``TRUECOLOR`` in orange::
237 236
238 237 printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
239 238 """,
240 239 ).tag(config=True)
241 240
242 241 editor = Unicode(get_default_editor(),
243 242 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
244 243 ).tag(config=True)
245 244
246 245 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
247 246
248 247 prompts = Instance(Prompts)
249 248
250 249 @default('prompts')
251 250 def _prompts_default(self):
252 251 return self.prompts_class(self)
253 252
254 253 # @observe('prompts')
255 254 # def _(self, change):
256 255 # self._update_layout()
257 256
258 257 @default('displayhook_class')
259 258 def _displayhook_class_default(self):
260 259 return RichPromptDisplayHook
261 260
262 261 term_title = Bool(True,
263 262 help="Automatically set the terminal title"
264 263 ).tag(config=True)
265 264
266 265 term_title_format = Unicode("IPython: {cwd}",
267 266 help="Customize the terminal title format. This is a python format string. " +
268 267 "Available substitutions are: {cwd}."
269 268 ).tag(config=True)
270 269
271 270 display_completions = Enum(('column', 'multicolumn','readlinelike'),
272 271 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
273 272 "'readlinelike'. These options are for `prompt_toolkit`, see "
274 273 "`prompt_toolkit` documentation for more information."
275 274 ),
276 275 default_value='multicolumn').tag(config=True)
277 276
278 277 highlight_matching_brackets = Bool(True,
279 278 help="Highlight matching brackets.",
280 279 ).tag(config=True)
281 280
282 281 extra_open_editor_shortcuts = Bool(False,
283 282 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
284 283 "This is in addition to the F2 binding, which is always enabled."
285 284 ).tag(config=True)
286 285
287 286 handle_return = Any(None,
288 287 help="Provide an alternative handler to be called when the user presses "
289 288 "Return. This is an advanced option intended for debugging, which "
290 289 "may be changed or removed in later releases."
291 290 ).tag(config=True)
292 291
293 292 enable_history_search = Bool(True,
294 293 help="Allows to enable/disable the prompt toolkit history search"
295 294 ).tag(config=True)
296 295
297 296 prompt_includes_vi_mode = Bool(True,
298 297 help="Display the current vi mode (when using vi editing mode)."
299 298 ).tag(config=True)
300 299
301 300 @observe('term_title')
302 301 def init_term_title(self, change=None):
303 302 # Enable or disable the terminal title.
304 303 if self.term_title:
305 304 toggle_set_term_title(True)
306 305 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
307 306 else:
308 307 toggle_set_term_title(False)
309 308
310 309 def restore_term_title(self):
311 310 if self.term_title:
312 311 restore_term_title()
313 312
314 313 def init_display_formatter(self):
315 314 super(TerminalInteractiveShell, self).init_display_formatter()
316 315 # terminal only supports plain text
317 316 self.display_formatter.active_types = ['text/plain']
318 317 # disable `_ipython_display_`
319 318 self.display_formatter.ipython_display_formatter.enabled = False
320 319
321 320 def init_prompt_toolkit_cli(self):
322 321 if self.simple_prompt:
323 322 # Fall back to plain non-interactive output for tests.
324 323 # This is very limited.
325 324 def prompt():
326 325 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
327 326 lines = [input(prompt_text)]
328 327 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
329 328 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
330 329 lines.append( input(prompt_continuation) )
331 330 return '\n'.join(lines)
332 331 self.prompt_for_code = prompt
333 332 return
334 333
335 334 # Set up keyboard shortcuts
336 335 key_bindings = create_ipython_shortcuts(self)
337 336
338 337 # Pre-populate history from IPython's history database
339 338 history = InMemoryHistory()
340 339 last_cell = u""
341 340 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
342 341 include_latest=True):
343 342 # Ignore blank lines and consecutive duplicates
344 343 cell = cell.rstrip()
345 344 if cell and (cell != last_cell):
346 345 history.append_string(cell)
347 346 last_cell = cell
348 347
349 348 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
350 349 self.style = DynamicStyle(lambda: self._style)
351 350
352 351 editing_mode = getattr(EditingMode, self.editing_mode.upper())
353 352
354 353 self.pt_loop = asyncio.new_event_loop()
355 354 self.pt_app = PromptSession(
356 355 auto_suggest=AutoSuggestFromHistory(),
357 356 editing_mode=editing_mode,
358 357 key_bindings=key_bindings,
359 358 history=history,
360 359 completer=IPythonPTCompleter(shell=self),
361 360 enable_history_search=self.enable_history_search,
362 361 style=self.style,
363 362 include_default_pygments_style=False,
364 363 mouse_support=self.mouse_support,
365 364 enable_open_in_editor=self.extra_open_editor_shortcuts,
366 365 color_depth=self.color_depth,
367 366 tempfile_suffix=".py",
368 367 **self._extra_prompt_options()
369 368 )
370 369
371 370 def _make_style_from_name_or_cls(self, name_or_cls):
372 371 """
373 372 Small wrapper that make an IPython compatible style from a style name
374 373
375 374 We need that to add style for prompt ... etc.
376 375 """
377 376 style_overrides = {}
378 377 if name_or_cls == 'legacy':
379 378 legacy = self.colors.lower()
380 379 if legacy == 'linux':
381 380 style_cls = get_style_by_name('monokai')
382 381 style_overrides = _style_overrides_linux
383 382 elif legacy == 'lightbg':
384 383 style_overrides = _style_overrides_light_bg
385 384 style_cls = get_style_by_name('pastie')
386 385 elif legacy == 'neutral':
387 386 # The default theme needs to be visible on both a dark background
388 387 # and a light background, because we can't tell what the terminal
389 388 # looks like. These tweaks to the default theme help with that.
390 389 style_cls = get_style_by_name('default')
391 390 style_overrides.update({
392 391 Token.Number: '#ansigreen',
393 392 Token.Operator: 'noinherit',
394 393 Token.String: '#ansiyellow',
395 394 Token.Name.Function: '#ansiblue',
396 395 Token.Name.Class: 'bold #ansiblue',
397 396 Token.Name.Namespace: 'bold #ansiblue',
398 397 Token.Name.Variable.Magic: '#ansiblue',
399 398 Token.Prompt: '#ansigreen',
400 399 Token.PromptNum: '#ansibrightgreen bold',
401 400 Token.OutPrompt: '#ansired',
402 401 Token.OutPromptNum: '#ansibrightred bold',
403 402 })
404 403
405 404 # Hack: Due to limited color support on the Windows console
406 405 # the prompt colors will be wrong without this
407 406 if os.name == 'nt':
408 407 style_overrides.update({
409 408 Token.Prompt: '#ansidarkgreen',
410 409 Token.PromptNum: '#ansigreen bold',
411 410 Token.OutPrompt: '#ansidarkred',
412 411 Token.OutPromptNum: '#ansired bold',
413 412 })
414 413 elif legacy =='nocolor':
415 414 style_cls=_NoStyle
416 415 style_overrides = {}
417 416 else :
418 417 raise ValueError('Got unknown colors: ', legacy)
419 418 else :
420 419 if isinstance(name_or_cls, str):
421 420 style_cls = get_style_by_name(name_or_cls)
422 421 else:
423 422 style_cls = name_or_cls
424 423 style_overrides = {
425 424 Token.Prompt: '#ansigreen',
426 425 Token.PromptNum: '#ansibrightgreen bold',
427 426 Token.OutPrompt: '#ansired',
428 427 Token.OutPromptNum: '#ansibrightred bold',
429 428 }
430 429 style_overrides.update(self.highlighting_style_overrides)
431 430 style = merge_styles([
432 431 style_from_pygments_cls(style_cls),
433 432 style_from_pygments_dict(style_overrides),
434 433 ])
435 434
436 435 return style
437 436
438 437 @property
439 438 def pt_complete_style(self):
440 439 return {
441 440 'multicolumn': CompleteStyle.MULTI_COLUMN,
442 441 'column': CompleteStyle.COLUMN,
443 442 'readlinelike': CompleteStyle.READLINE_LIKE,
444 443 }[self.display_completions]
445 444
446 445 @property
447 446 def color_depth(self):
448 447 return (ColorDepth.TRUE_COLOR if self.true_color else None)
449 448
450 449 def _extra_prompt_options(self):
451 450 """
452 451 Return the current layout option for the current Terminal InteractiveShell
453 452 """
454 453 def get_message():
455 454 return PygmentsTokens(self.prompts.in_prompt_tokens())
456 455
457 456 if self.editing_mode == 'emacs':
458 457 # with emacs mode the prompt is (usually) static, so we call only
459 458 # the function once. With VI mode it can toggle between [ins] and
460 459 # [nor] so we can't precompute.
461 460 # here I'm going to favor the default keybinding which almost
462 461 # everybody uses to decrease CPU usage.
463 462 # if we have issues with users with custom Prompts we can see how to
464 463 # work around this.
465 464 get_message = get_message()
466 465
467 466 options = {
468 467 'complete_in_thread': False,
469 468 'lexer':IPythonPTLexer(),
470 469 'reserve_space_for_menu':self.space_for_menu,
471 470 'message': get_message,
472 471 'prompt_continuation': (
473 472 lambda width, lineno, is_soft_wrap:
474 473 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
475 474 'multiline': True,
476 475 'complete_style': self.pt_complete_style,
477 476
478 477 # Highlight matching brackets, but only when this setting is
479 478 # enabled, and only when the DEFAULT_BUFFER has the focus.
480 479 'input_processors': [ConditionalProcessor(
481 480 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
482 481 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
483 482 Condition(lambda: self.highlight_matching_brackets))],
484 483 }
485 484 if not PTK3:
486 485 options['inputhook'] = self.inputhook
487 486
488 487 return options
489 488
490 489 def prompt_for_code(self):
491 490 if self.rl_next_input:
492 491 default = self.rl_next_input
493 492 self.rl_next_input = None
494 493 else:
495 494 default = ''
496 495
497 496 # In order to make sure that asyncio code written in the
498 497 # interactive shell doesn't interfere with the prompt, we run the
499 498 # prompt in a different event loop.
500 499 # If we don't do this, people could spawn coroutine with a
501 500 # while/true inside which will freeze the prompt.
502 501
503 502 try:
504 503 old_loop = asyncio.get_event_loop()
505 504 except RuntimeError:
506 505 # This happens when the user used `asyncio.run()`.
507 506 old_loop = None
508 507
509 508 asyncio.set_event_loop(self.pt_loop)
510 509 try:
511 510 with patch_stdout(raw=True):
512 511 text = self.pt_app.prompt(
513 512 default=default,
514 513 **self._extra_prompt_options())
515 514 finally:
516 515 # Restore the original event loop.
517 516 asyncio.set_event_loop(old_loop)
518 517
519 518 return text
520 519
521 520 def enable_win_unicode_console(self):
522 521 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
523 522 # console by default, so WUC shouldn't be needed.
524 523 from warnings import warn
525 524 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
526 525 DeprecationWarning,
527 526 stacklevel=2)
528 527
529 528 def init_io(self):
530 529 if sys.platform not in {'win32', 'cli'}:
531 530 return
532 531
533 532 import colorama
534 533 colorama.init()
535 534
536 535 # For some reason we make these wrappers around stdout/stderr.
537 536 # For now, we need to reset them so all output gets coloured.
538 537 # https://github.com/ipython/ipython/issues/8669
539 538 # io.std* are deprecated, but don't show our own deprecation warnings
540 539 # during initialization of the deprecated API.
541 540 with warnings.catch_warnings():
542 541 warnings.simplefilter('ignore', DeprecationWarning)
543 542 io.stdout = io.IOStream(sys.stdout)
544 543 io.stderr = io.IOStream(sys.stderr)
545 544
546 545 def init_magics(self):
547 546 super(TerminalInteractiveShell, self).init_magics()
548 547 self.register_magics(TerminalMagics)
549 548
550 549 def init_alias(self):
551 550 # The parent class defines aliases that can be safely used with any
552 551 # frontend.
553 552 super(TerminalInteractiveShell, self).init_alias()
554 553
555 554 # Now define aliases that only make sense on the terminal, because they
556 555 # need direct access to the console in a way that we can't emulate in
557 556 # GUI or web frontend
558 557 if os.name == 'posix':
559 558 for cmd in ('clear', 'more', 'less', 'man'):
560 559 self.alias_manager.soft_define_alias(cmd, cmd)
561 560
562 561
563 562 def __init__(self, *args, **kwargs):
564 563 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
565 564 self.init_prompt_toolkit_cli()
566 565 self.init_term_title()
567 566 self.keep_running = True
568 567
569 568 self.debugger_history = InMemoryHistory()
570 569
571 570 def ask_exit(self):
572 571 self.keep_running = False
573 572
574 573 rl_next_input = None
575 574
576 575 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
577 576
578 577 if display_banner is not DISPLAY_BANNER_DEPRECATED:
579 578 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
580 579
581 580 self.keep_running = True
582 581 while self.keep_running:
583 582 print(self.separate_in, end='')
584 583
585 584 try:
586 585 code = self.prompt_for_code()
587 586 except EOFError:
588 587 if (not self.confirm_exit) \
589 588 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
590 589 self.ask_exit()
591 590
592 591 else:
593 592 if code:
594 593 self.run_cell(code, store_history=True)
595 594
596 595 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
597 596 # An extra layer of protection in case someone mashing Ctrl-C breaks
598 597 # out of our internal code.
599 598 if display_banner is not DISPLAY_BANNER_DEPRECATED:
600 599 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
601 600 while True:
602 601 try:
603 602 self.interact()
604 603 break
605 604 except KeyboardInterrupt as e:
606 605 print("\n%s escaped interact()\n" % type(e).__name__)
607 606 finally:
608 607 # An interrupt during the eventloop will mess up the
609 608 # internal state of the prompt_toolkit library.
610 609 # Stopping the eventloop fixes this, see
611 610 # https://github.com/ipython/ipython/pull/9867
612 611 if hasattr(self, '_eventloop'):
613 612 self._eventloop.stop()
614 613
615 614 self.restore_term_title()
616 615
617 616 # try to call some at-exit operation optimistically as some things can't
618 617 # be done during interpreter shutdown. this is technically inaccurate as
619 618 # this make mainlool not re-callable, but that should be a rare if not
620 619 # in existent use case.
621 620
622 621 self._atexit_once()
623 622
624 623
625 624 _inputhook = None
626 625 def inputhook(self, context):
627 626 if self._inputhook is not None:
628 627 self._inputhook(context)
629 628
630 629 active_eventloop = None
631 630 def enable_gui(self, gui=None):
632 631 if gui and (gui != 'inline') :
633 632 self.active_eventloop, self._inputhook =\
634 633 get_inputhook_name_and_func(gui)
635 634 else:
636 635 self.active_eventloop = self._inputhook = None
637 636
638 637 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
639 638 # this inputhook.
640 639 if PTK3:
641 640 import asyncio
642 641 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
643 642
644 643 if gui == 'asyncio':
645 644 # When we integrate the asyncio event loop, run the UI in the
646 645 # same event loop as the rest of the code. don't use an actual
647 646 # input hook. (Asyncio is not made for nesting event loops.)
648 647 self.pt_loop = asyncio.get_event_loop()
649 648
650 649 elif self._inputhook:
651 650 # If an inputhook was set, create a new asyncio event loop with
652 651 # this inputhook for the prompt.
653 652 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
654 653 else:
655 654 # When there's no inputhook, run the prompt in a separate
656 655 # asyncio event loop.
657 656 self.pt_loop = asyncio.new_event_loop()
658 657
659 658 # Run !system commands directly, not through pipes, so terminal programs
660 659 # work correctly.
661 660 system = InteractiveShell.system_raw
662 661
663 662 def auto_rewrite_input(self, cmd):
664 663 """Overridden from the parent class to use fancy rewriting prompt"""
665 664 if not self.show_rewritten_input:
666 665 return
667 666
668 667 tokens = self.prompts.rewrite_prompt_tokens()
669 668 if self.pt_app:
670 669 print_formatted_text(PygmentsTokens(tokens), end='',
671 670 style=self.pt_app.app.style)
672 671 print(cmd)
673 672 else:
674 673 prompt = ''.join(s for t, s in tokens)
675 674 print(prompt, cmd, sep='')
676 675
677 676 _prompts_before = None
678 677 def switch_doctest_mode(self, mode):
679 678 """Switch prompts to classic for %doctest_mode"""
680 679 if mode:
681 680 self._prompts_before = self.prompts
682 681 self.prompts = ClassicPrompts(self)
683 682 elif self._prompts_before:
684 683 self.prompts = self._prompts_before
685 684 self._prompts_before = None
686 685 # self._update_layout()
687 686
688 687
689 688 InteractiveShellABC.register(TerminalInteractiveShell)
690 689
691 690 if __name__ == '__main__':
692 691 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now