PageRenderTime 73ms CodeModel.GetById 18ms RepoModel.GetById 7ms app.codeStats 0ms

/IPython/terminal/interactiveshell.py

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