aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/ipython/py3/IPython/terminal
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.ru>2022-05-18 00:43:36 +0300
committerrobot-contrib <robot-contrib@yandex-team.ru>2022-05-18 00:43:36 +0300
commit9e5f436a8b2a27bcc7802e443ea3ef3e41a82a75 (patch)
tree78b522cab9f76336e62064d4d8ff7c897659b20e /contrib/python/ipython/py3/IPython/terminal
parent8113a823ffca6451bb5ff8f0334560885a939a24 (diff)
downloadydb-9e5f436a8b2a27bcc7802e443ea3ef3e41a82a75.tar.gz
Update contrib/python/ipython/py3 to 8.3.0
ref:e84342d4d30476f9148137f37fd0c6405fd36f55
Diffstat (limited to 'contrib/python/ipython/py3/IPython/terminal')
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/debugger.py55
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/embed.py91
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/interactiveshell.py297
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/ipapp.py42
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/magics.py25
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/asyncio.py11
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/glut.py6
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py4
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/qt.py2
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/ptshell.py8
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/ptutils.py4
-rw-r--r--contrib/python/ipython/py3/IPython/terminal/shortcuts.py294
12 files changed, 607 insertions, 232 deletions
diff --git a/contrib/python/ipython/py3/IPython/terminal/debugger.py b/contrib/python/ipython/py3/IPython/terminal/debugger.py
index db8ecac0d2..8448d96370 100644
--- a/contrib/python/ipython/py3/IPython/terminal/debugger.py
+++ b/contrib/python/ipython/py3/IPython/terminal/debugger.py
@@ -1,21 +1,19 @@
import asyncio
-import signal
+import os
import sys
from IPython.core.debugger import Pdb
from IPython.core.completer import IPCompleter
from .ptutils import IPythonPTCompleter
-from .shortcuts import create_ipython_shortcuts, suspend_to_bg, cursor_in_leading_ws
+from .shortcuts import create_ipython_shortcuts
+from . import embed
-from prompt_toolkit.enums import DEFAULT_BUFFER
-from prompt_toolkit.filters import (Condition, has_focus, has_selection,
- vi_insert_mode, emacs_insert_mode)
-from prompt_toolkit.key_binding import KeyBindings
-from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
+from pathlib import Path
from pygments.token import Token
from prompt_toolkit.shortcuts.prompt import PromptSession
from prompt_toolkit.enums import EditingMode
from prompt_toolkit.formatted_text import PygmentsTokens
+from prompt_toolkit.history import InMemoryHistory, FileHistory
from concurrent.futures import ThreadPoolExecutor
from prompt_toolkit import __version__ as ptk_version
@@ -34,22 +32,20 @@ class TerminalPdb(Pdb):
def pt_init(self, pt_session_options=None):
"""Initialize the prompt session and the prompt loop
and store them in self.pt_app and self.pt_loop.
-
+
Additional keyword arguments for the PromptSession class
can be specified in pt_session_options.
"""
if pt_session_options is None:
pt_session_options = {}
-
+
def get_prompt_tokens():
return [(Token.Prompt, self.prompt)]
if self._ptcomp is None:
- compl = IPCompleter(shell=self.shell,
- namespace={},
- global_namespace={},
- parent=self.shell,
- )
+ compl = IPCompleter(
+ shell=self.shell, namespace={}, global_namespace={}, parent=self.shell
+ )
# add a completer for all the do_ methods
methods_names = [m[3:] for m in dir(self) if m.startswith("do_")]
@@ -62,11 +58,24 @@ class TerminalPdb(Pdb):
self._ptcomp = IPythonPTCompleter(compl)
+ # setup history only when we start pdb
+ if self.shell.debugger_history is None:
+ if self.shell.debugger_history_file is not None:
+
+ p = Path(self.shell.debugger_history_file).expanduser()
+ if not p.exists():
+ p.touch()
+ self.debugger_history = FileHistory(os.path.expanduser(str(p)))
+ else:
+ self.debugger_history = InMemoryHistory()
+ else:
+ self.debugger_history = self.shell.debugger_history
+
options = dict(
message=(lambda: PygmentsTokens(get_prompt_tokens())),
editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
key_bindings=create_ipython_shortcuts(self.shell),
- history=self.shell.debugger_history,
+ history=self.debugger_history,
completer=self._ptcomp,
enable_history_search=True,
mouse_support=self.shell.mouse_support,
@@ -124,6 +133,18 @@ class TerminalPdb(Pdb):
except Exception:
raise
+ def do_interact(self, arg):
+ ipshell = embed.InteractiveShellEmbed(
+ config=self.shell.config,
+ banner1="*interactive*",
+ exit_msg="*exiting interactive console...*",
+ )
+ global_ns = self.curframe.f_globals
+ ipshell(
+ module=sys.modules.get(global_ns["__name__"], None),
+ local_ns=self.curframe_locals,
+ )
+
def set_trace(frame=None):
"""
@@ -141,6 +162,6 @@ if __name__ == '__main__':
# happened after hitting "c", this is needed in order to
# be able to quit the debugging session (see #9950).
old_trace_dispatch = pdb.Pdb.trace_dispatch
- pdb.Pdb = TerminalPdb
- pdb.Pdb.trace_dispatch = old_trace_dispatch
+ pdb.Pdb = TerminalPdb # type: ignore
+ pdb.Pdb.trace_dispatch = old_trace_dispatch # type: ignore
pdb.main()
diff --git a/contrib/python/ipython/py3/IPython/terminal/embed.py b/contrib/python/ipython/py3/IPython/terminal/embed.py
index 188844fadd..85e76d5558 100644
--- a/contrib/python/ipython/py3/IPython/terminal/embed.py
+++ b/contrib/python/ipython/py3/IPython/terminal/embed.py
@@ -19,6 +19,8 @@ from IPython.terminal.ipapp import load_default_config
from traitlets import Bool, CBool, Unicode
from IPython.utils.io import ask_yes_no
+from typing import Set
+
class KillEmbedded(Exception):pass
# kept for backward compatibility as IPython 6 was released with
@@ -47,7 +49,6 @@ class EmbeddedMagics(Magics):
you may then kill it and the program will then continue to run without
the interactive shell interfering again.
-
Kill Instance Option:
If for some reasons you need to kill the location where the instance
@@ -106,6 +107,14 @@ class EmbeddedMagics(Magics):
self.shell.ask_exit()
+class _Sentinel:
+ def __init__(self, repr):
+ assert isinstance(repr, str)
+ self.repr = repr
+
+ def __repr__(self):
+ return repr
+
class InteractiveShellEmbed(TerminalInteractiveShell):
@@ -123,17 +132,17 @@ class InteractiveShellEmbed(TerminalInteractiveShell):
help="Automatically set the terminal title"
).tag(config=True)
- _inactive_locations = set()
+ _inactive_locations: Set[str] = set()
+
+ def _disable_init_location(self):
+ """Disable the current Instance creation location"""
+ InteractiveShellEmbed._inactive_locations.add(self._init_location_id)
@property
def embedded_active(self):
return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\
and (self._init_location_id not in InteractiveShellEmbed._inactive_locations)
- def _disable_init_location(self):
- """Disable the current Instance creation location"""
- InteractiveShellEmbed._inactive_locations.add(self._init_location_id)
-
@embedded_active.setter
def embedded_active(self, value):
if value:
@@ -146,9 +155,9 @@ class InteractiveShellEmbed(TerminalInteractiveShell):
self._call_location_id)
def __init__(self, **kw):
- if kw.get('user_global_ns', None) is not None:
- raise DeprecationWarning(
- "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.")
+ assert (
+ "user_global_ns" not in kw
+ ), "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0."
clid = kw.pop('_init_location_id', None)
if not clid:
@@ -174,8 +183,16 @@ class InteractiveShellEmbed(TerminalInteractiveShell):
super(InteractiveShellEmbed, self).init_magics()
self.register_magics(EmbeddedMagics)
- def __call__(self, header='', local_ns=None, module=None, dummy=None,
- stack_depth=1, global_ns=None, compile_flags=None, **kw):
+ def __call__(
+ self,
+ header="",
+ local_ns=None,
+ module=None,
+ dummy=None,
+ stack_depth=1,
+ compile_flags=None,
+ **kw
+ ):
"""Activate the interactive interpreter.
__call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
@@ -225,8 +242,9 @@ class InteractiveShellEmbed(TerminalInteractiveShell):
# Call the embedding code with a stack depth of 1 so it can skip over
# our call and get the original caller's namespaces.
- self.mainloop(local_ns, module, stack_depth=stack_depth,
- global_ns=global_ns, compile_flags=compile_flags)
+ self.mainloop(
+ local_ns, module, stack_depth=stack_depth, compile_flags=compile_flags
+ )
self.banner2 = self.old_banner2
@@ -236,40 +254,35 @@ class InteractiveShellEmbed(TerminalInteractiveShell):
if self.should_raise:
raise KillEmbedded('Embedded IPython raising error, as user requested.')
-
- def mainloop(self, local_ns=None, module=None, stack_depth=0,
- display_banner=None, global_ns=None, compile_flags=None):
+ def mainloop(
+ self,
+ local_ns=None,
+ module=None,
+ stack_depth=0,
+ compile_flags=None,
+ ):
"""Embeds IPython into a running python program.
Parameters
----------
-
local_ns, module
- Working local namespace (a dict) and module (a module or similar
- object). If given as None, they are automatically taken from the scope
- where the shell was called, so that program variables become visible.
-
+ Working local namespace (a dict) and module (a module or similar
+ object). If given as None, they are automatically taken from the scope
+ where the shell was called, so that program variables become visible.
stack_depth : int
- How many levels in the stack to go to looking for namespaces (when
- local_ns or module is None). This allows an intermediate caller to
- make sure that this function gets the namespace from the intended
- level in the stack. By default (0) it will get its locals and globals
- from the immediate caller.
-
+ How many levels in the stack to go to looking for namespaces (when
+ local_ns or module is None). This allows an intermediate caller to
+ make sure that this function gets the namespace from the intended
+ level in the stack. By default (0) it will get its locals and globals
+ from the immediate caller.
compile_flags
- A bit field identifying the __future__ features
- that are enabled, as passed to the builtin :func:`compile` function.
- If given as None, they are automatically taken from the scope where
- the shell was called.
+ A bit field identifying the __future__ features
+ that are enabled, as passed to the builtin :func:`compile` function.
+ If given as None, they are automatically taken from the scope where
+ the shell was called.
"""
- if (global_ns is not None) and (module is None):
- raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.")
-
- if (display_banner is not None):
- warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning)
-
# Get locals and globals from caller
if ((local_ns is None or module is None or compile_flags is None)
and self.default_user_namespaces):
@@ -334,7 +347,7 @@ class InteractiveShellEmbed(TerminalInteractiveShell):
self.compile.flags = orig_compile_flags
-def embed(**kwargs):
+def embed(*, header="", compile_flags=None, **kwargs):
"""Call this to embed IPython at the current point in your program.
The first invocation of this will create an :class:`InteractiveShellEmbed`
@@ -360,8 +373,6 @@ def embed(**kwargs):
config argument.
"""
config = kwargs.get('config')
- header = kwargs.pop('header', u'')
- compile_flags = kwargs.pop('compile_flags', None)
if config is None:
config = load_default_config()
config.InteractiveShellEmbed = config.TerminalInteractiveShell
diff --git a/contrib/python/ipython/py3/IPython/terminal/interactiveshell.py b/contrib/python/ipython/py3/IPython/terminal/interactiveshell.py
index 4e35aadd61..06724bea87 100644
--- a/contrib/python/ipython/py3/IPython/terminal/interactiveshell.py
+++ b/contrib/python/ipython/py3/IPython/terminal/interactiveshell.py
@@ -3,23 +3,34 @@
import asyncio
import os
import sys
-import warnings
from warnings import warn
+from IPython.core.async_helpers import get_asyncio_loop
from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
-from IPython.utils import io
from IPython.utils.py3compat import input
from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
from IPython.utils.process import abbrev_cwd
from traitlets import (
- Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union,
- Any, validate
+ Bool,
+ Unicode,
+ Dict,
+ Integer,
+ observe,
+ Instance,
+ Type,
+ default,
+ Enum,
+ Union,
+ Any,
+ validate,
+ Float,
)
+from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
from prompt_toolkit.formatted_text import PygmentsTokens
-from prompt_toolkit.history import InMemoryHistory
+from prompt_toolkit.history import History
from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
from prompt_toolkit.output import ColorDepth
from prompt_toolkit.patch_stdout import patch_stdout
@@ -39,7 +50,6 @@ from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
from .ptutils import IPythonPTCompleter, IPythonPTLexer
from .shortcuts import create_ipython_shortcuts
-DISPLAY_BANNER_DEPRECATED = object()
PTK3 = ptk_version.startswith('3.')
@@ -48,17 +58,17 @@ class _NoStyle(Style): pass
_style_overrides_light_bg = {
- Token.Prompt: '#0000ff',
- Token.PromptNum: '#0000ee bold',
- Token.OutPrompt: '#cc0000',
- Token.OutPromptNum: '#bb0000 bold',
+ Token.Prompt: '#ansibrightblue',
+ Token.PromptNum: '#ansiblue bold',
+ Token.OutPrompt: '#ansibrightred',
+ Token.OutPromptNum: '#ansired bold',
}
_style_overrides_linux = {
- Token.Prompt: '#00cc00',
- Token.PromptNum: '#00bb00 bold',
- Token.OutPrompt: '#cc0000',
- Token.OutPromptNum: '#bb0000 bold',
+ Token.Prompt: '#ansibrightgreen',
+ Token.PromptNum: '#ansigreen bold',
+ Token.OutPrompt: '#ansibrightred',
+ Token.OutPromptNum: '#ansired bold',
}
def get_default_editor():
@@ -91,13 +101,72 @@ else:
_use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
def black_reformat_handler(text_before_cursor):
+ """
+ We do not need to protect against error,
+ this is taken care at a higher level where any reformat error is ignored.
+ Indeed we may call reformatting on incomplete code.
+ """
import black
+
formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
- if not text_before_cursor.endswith('\n') and formatted_text.endswith('\n'):
- formatted_text = formatted_text[:-1]
+ if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
+ formatted_text = formatted_text[:-1]
return formatted_text
+def yapf_reformat_handler(text_before_cursor):
+ from yapf.yapflib import file_resources
+ from yapf.yapflib import yapf_api
+
+ style_config = file_resources.GetDefaultStyleForDir(os.getcwd())
+ formatted_text, was_formatted = yapf_api.FormatCode(
+ text_before_cursor, style_config=style_config
+ )
+ if was_formatted:
+ if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
+ formatted_text = formatted_text[:-1]
+ return formatted_text
+ else:
+ return text_before_cursor
+
+
+class PtkHistoryAdapter(History):
+ """
+ Prompt toolkit has it's own way of handling history, Where it assumes it can
+ Push/pull from history.
+
+ """
+
+ def __init__(self, shell):
+ super().__init__()
+ self.shell = shell
+ self._refresh()
+
+ def append_string(self, string):
+ # we rely on sql for that.
+ self._loaded = False
+ self._refresh()
+
+ def _refresh(self):
+ if not self._loaded:
+ self._loaded_strings = list(self.load_history_strings())
+
+ def load_history_strings(self):
+ last_cell = ""
+ res = []
+ for __, ___, cell in self.shell.history_manager.get_tail(
+ self.shell.history_load_length, include_latest=True
+ ):
+ # Ignore blank lines and consecutive duplicates
+ cell = cell.rstrip()
+ if cell and (cell != last_cell):
+ res.append(cell)
+ last_cell = cell
+ yield from res[::-1]
+
+ def store_string(self, string: str) -> None:
+ pass
+
class TerminalInteractiveShell(InteractiveShell):
mime_renderers = Dict().tag(config=True)
@@ -112,6 +181,10 @@ class TerminalInteractiveShell(InteractiveShell):
pt_app = None
debugger_history = None
+ debugger_history_file = Unicode(
+ "~/.pdbhistory", help="File in which to store and read history"
+ ).tag(config=True)
+
simple_prompt = Bool(_use_simple_prompt,
help="""Use `raw_input` for the REPL, without completion and prompt colors.
@@ -137,11 +210,45 @@ class TerminalInteractiveShell(InteractiveShell):
help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
).tag(config=True)
- autoformatter = Unicode(None,
- help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
+ emacs_bindings_in_vi_insert_mode = Bool(
+ True,
+ help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
+ ).tag(config=True)
+
+ modal_cursor = Bool(
+ True,
+ help="""
+ Cursor shape changes depending on vi mode: beam in vi insert mode,
+ block in nav mode, underscore in replace mode.""",
+ ).tag(config=True)
+
+ ttimeoutlen = Float(
+ 0.01,
+ help="""The time in milliseconds that is waited for a key code
+ to complete.""",
+ ).tag(config=True)
+
+ timeoutlen = Float(
+ 0.5,
+ help="""The time in milliseconds that is waited for a mapped key
+ sequence to complete.""",
+ ).tag(config=True)
+
+ autoformatter = Unicode(
+ None,
+ help="Autoformatter to reformat Terminal code. Can be `'black'`, `'yapf'` or `None`",
allow_none=True
).tag(config=True)
+ auto_match = Bool(
+ False,
+ help="""
+ Automatically add/delete closing bracket or quote when opening bracket or quote is entered/deleted.
+ Brackets: (), [], {}
+ Quotes: '', \"\"
+ """,
+ ).tag(config=True)
+
mouse_support = Bool(False,
help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
).tag(config=True)
@@ -171,16 +278,21 @@ class TerminalInteractiveShell(InteractiveShell):
if self.pt_app:
self.pt_app.editing_mode = getattr(EditingMode, change.new.upper())
- @observe('autoformatter')
- def _autoformatter_changed(self, change):
- formatter = change.new
+ def _set_formatter(self, formatter):
if formatter is None:
self.reformat_handler = lambda x:x
elif formatter == 'black':
self.reformat_handler = black_reformat_handler
+ elif formatter == "yapf":
+ self.reformat_handler = yapf_reformat_handler
else:
raise ValueError
+ @observe("autoformatter")
+ def _autoformatter_changed(self, change):
+ formatter = change.new
+ self._set_formatter(formatter)
+
@observe('highlighting_style')
@observe('colors')
def _highlighting_style_changed(self, change):
@@ -195,10 +307,12 @@ class TerminalInteractiveShell(InteractiveShell):
).tag(config=True)
true_color = Bool(False,
- help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
- "If your terminal supports true color, the following command "
- "should print 'TRUECOLOR' in orange: "
- "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
+ help="""Use 24bit colors instead of 256 colors in prompt highlighting.
+ If your terminal supports true color, the following command should
+ print ``TRUECOLOR`` in orange::
+
+ printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
+ """,
).tag(config=True)
editor = Unicode(get_default_editor(),
@@ -256,6 +370,29 @@ class TerminalInteractiveShell(InteractiveShell):
help="Allows to enable/disable the prompt toolkit history search"
).tag(config=True)
+ autosuggestions_provider = Unicode(
+ "AutoSuggestFromHistory",
+ help="Specifies from which source automatic suggestions are provided. "
+ "Can be set to `'AutoSuggestFromHistory`' or `None` to disable"
+ "automatic suggestions. Default is `'AutoSuggestFromHistory`'.",
+ allow_none=True,
+ ).tag(config=True)
+
+ def _set_autosuggestions(self, provider):
+ if provider is None:
+ self.auto_suggest = None
+ elif provider == "AutoSuggestFromHistory":
+ self.auto_suggest = AutoSuggestFromHistory()
+ else:
+ raise ValueError("No valid provider.")
+ if self.pt_app:
+ self.pt_app.auto_suggest = self.auto_suggest
+
+ @observe("autosuggestions_provider")
+ def _autosuggestions_provider_changed(self, change):
+ provider = change.new
+ self._set_autosuggestions(provider)
+
prompt_includes_vi_mode = Bool(True,
help="Display the current vi mode (when using vi editing mode)."
).tag(config=True)
@@ -276,9 +413,7 @@ class TerminalInteractiveShell(InteractiveShell):
def init_display_formatter(self):
super(TerminalInteractiveShell, self).init_display_formatter()
# terminal only supports plain text
- self.display_formatter.active_types = ['text/plain']
- # disable `_ipython_display_`
- self.display_formatter.ipython_display_formatter.enabled = False
+ self.display_formatter.active_types = ["text/plain"]
def init_prompt_toolkit_cli(self):
if self.simple_prompt:
@@ -297,16 +432,9 @@ class TerminalInteractiveShell(InteractiveShell):
# Set up keyboard shortcuts
key_bindings = create_ipython_shortcuts(self)
+
# Pre-populate history from IPython's history database
- history = InMemoryHistory()
- last_cell = u""
- for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
- include_latest=True):
- # Ignore blank lines and consecutive duplicates
- cell = cell.rstrip()
- if cell and (cell != last_cell):
- history.append_string(cell)
- last_cell = cell
+ history = PtkHistoryAdapter(self)
self._style = self._make_style_from_name_or_cls(self.highlighting_style)
self.style = DynamicStyle(lambda: self._style)
@@ -315,18 +443,20 @@ class TerminalInteractiveShell(InteractiveShell):
self.pt_loop = asyncio.new_event_loop()
self.pt_app = PromptSession(
- editing_mode=editing_mode,
- key_bindings=key_bindings,
- history=history,
- completer=IPythonPTCompleter(shell=self),
- enable_history_search = self.enable_history_search,
- style=self.style,
- include_default_pygments_style=False,
- mouse_support=self.mouse_support,
- enable_open_in_editor=self.extra_open_editor_shortcuts,
- color_depth=self.color_depth,
- tempfile_suffix=".py",
- **self._extra_prompt_options())
+ auto_suggest=self.auto_suggest,
+ editing_mode=editing_mode,
+ key_bindings=key_bindings,
+ history=history,
+ completer=IPythonPTCompleter(shell=self),
+ enable_history_search=self.enable_history_search,
+ style=self.style,
+ include_default_pygments_style=False,
+ mouse_support=self.mouse_support,
+ enable_open_in_editor=self.extra_open_editor_shortcuts,
+ color_depth=self.color_depth,
+ tempfile_suffix=".py",
+ **self._extra_prompt_options()
+ )
def _make_style_from_name_or_cls(self, name_or_cls):
"""
@@ -349,16 +479,16 @@ class TerminalInteractiveShell(InteractiveShell):
# looks like. These tweaks to the default theme help with that.
style_cls = get_style_by_name('default')
style_overrides.update({
- Token.Number: '#007700',
+ Token.Number: '#ansigreen',
Token.Operator: 'noinherit',
- Token.String: '#BB6622',
- Token.Name.Function: '#2080D0',
- Token.Name.Class: 'bold #2080D0',
- Token.Name.Namespace: 'bold #2080D0',
+ Token.String: '#ansiyellow',
+ Token.Name.Function: '#ansiblue',
+ Token.Name.Class: 'bold #ansiblue',
+ Token.Name.Namespace: 'bold #ansiblue',
Token.Name.Variable.Magic: '#ansiblue',
- Token.Prompt: '#009900',
+ Token.Prompt: '#ansigreen',
Token.PromptNum: '#ansibrightgreen bold',
- Token.OutPrompt: '#990000',
+ Token.OutPrompt: '#ansired',
Token.OutPromptNum: '#ansibrightred bold',
})
@@ -382,9 +512,9 @@ class TerminalInteractiveShell(InteractiveShell):
else:
style_cls = name_or_cls
style_overrides = {
- Token.Prompt: '#009900',
+ Token.Prompt: '#ansigreen',
Token.PromptNum: '#ansibrightgreen bold',
- Token.OutPrompt: '#990000',
+ Token.OutPrompt: '#ansired',
Token.OutPromptNum: '#ansibrightred bold',
}
style_overrides.update(self.highlighting_style_overrides)
@@ -461,14 +591,14 @@ class TerminalInteractiveShell(InteractiveShell):
# while/true inside which will freeze the prompt.
policy = asyncio.get_event_loop_policy()
- try:
- old_loop = policy.get_event_loop()
- except RuntimeError:
- # This happens when the the event loop is closed,
- # e.g. by calling `asyncio.run()`.
- old_loop = None
-
- policy.set_event_loop(self.pt_loop)
+ old_loop = get_asyncio_loop()
+
+ # FIXME: prompt_toolkit is using the deprecated `asyncio.get_event_loop`
+ # to get the current event loop.
+ # This will probably be replaced by an attribute or input argument,
+ # at which point we can stop calling the soon-to-be-deprecated `set_event_loop` here.
+ if old_loop is not self.pt_loop:
+ policy.set_event_loop(self.pt_loop)
try:
with patch_stdout(raw=True):
text = self.pt_app.prompt(
@@ -476,7 +606,7 @@ class TerminalInteractiveShell(InteractiveShell):
**self._extra_prompt_options())
finally:
# Restore the original event loop.
- if old_loop is not None:
+ if old_loop is not None and old_loop is not self.pt_loop:
policy.set_event_loop(old_loop)
return text
@@ -484,7 +614,6 @@ class TerminalInteractiveShell(InteractiveShell):
def enable_win_unicode_console(self):
# Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
# console by default, so WUC shouldn't be needed.
- from warnings import warn
warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
DeprecationWarning,
stacklevel=2)
@@ -496,16 +625,6 @@ class TerminalInteractiveShell(InteractiveShell):
import colorama
colorama.init()
- # For some reason we make these wrappers around stdout/stderr.
- # For now, we need to reset them so all output gets coloured.
- # https://github.com/ipython/ipython/issues/8669
- # io.std* are deprecated, but don't show our own deprecation warnings
- # during initialization of the deprecated API.
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- io.stdout = io.IOStream(sys.stdout)
- io.stderr = io.IOStream(sys.stderr)
-
def init_magics(self):
super(TerminalInteractiveShell, self).init_magics()
self.register_magics(TerminalMagics)
@@ -525,22 +644,19 @@ class TerminalInteractiveShell(InteractiveShell):
def __init__(self, *args, **kwargs):
super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
+ self._set_autosuggestions(self.autosuggestions_provider)
self.init_prompt_toolkit_cli()
self.init_term_title()
self.keep_running = True
+ self._set_formatter(self.autoformatter)
- self.debugger_history = InMemoryHistory()
def ask_exit(self):
self.keep_running = False
rl_next_input = None
- def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
-
- if display_banner is not DISPLAY_BANNER_DEPRECATED:
- warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
-
+ def interact(self):
self.keep_running = True
while self.keep_running:
print(self.separate_in, end='')
@@ -556,11 +672,9 @@ class TerminalInteractiveShell(InteractiveShell):
if code:
self.run_cell(code, store_history=True)
- def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
+ def mainloop(self):
# An extra layer of protection in case someone mashing Ctrl-C breaks
# out of our internal code.
- if display_banner is not DISPLAY_BANNER_DEPRECATED:
- warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
while True:
try:
self.interact()
@@ -577,6 +691,13 @@ class TerminalInteractiveShell(InteractiveShell):
self.restore_term_title()
+ # try to call some at-exit operation optimistically as some things can't
+ # be done during interpreter shutdown. this is technically inaccurate as
+ # this make mainlool not re-callable, but that should be a rare if not
+ # in existent use case.
+
+ self._atexit_once()
+
_inputhook = None
def inputhook(self, context):
@@ -601,7 +722,7 @@ class TerminalInteractiveShell(InteractiveShell):
# When we integrate the asyncio event loop, run the UI in the
# same event loop as the rest of the code. don't use an actual
# input hook. (Asyncio is not made for nesting event loops.)
- self.pt_loop = asyncio.get_event_loop()
+ self.pt_loop = get_asyncio_loop()
elif self._inputhook:
# If an inputhook was set, create a new asyncio event loop with
diff --git a/contrib/python/ipython/py3/IPython/terminal/ipapp.py b/contrib/python/ipython/py3/IPython/terminal/ipapp.py
index 1a3c6c791b..a87eb2f443 100644
--- a/contrib/python/ipython/py3/IPython/terminal/ipapp.py
+++ b/contrib/python/ipython/py3/IPython/terminal/ipapp.py
@@ -210,26 +210,6 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
StoreMagics,
]
- deprecated_subcommands = dict(
- qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp',
- """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console."""
- ),
- notebook=('notebook.notebookapp.NotebookApp',
- """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server."""
- ),
- console=('jupyter_console.app.ZMQTerminalIPythonApp',
- """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console."""
- ),
- nbconvert=('nbconvert.nbconvertapp.NbConvertApp',
- "DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats."
- ),
- trust=('nbformat.sign.TrustNotebookApp',
- "DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load."
- ),
- kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp',
- "DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications."
- ),
- )
subcommands = dict(
profile = ("IPython.core.profileapp.ProfileApp",
"Create and manage IPython profiles."
@@ -244,11 +224,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
"Manage the IPython history database."
),
)
- deprecated_subcommands['install-nbextension'] = (
- "notebook.nbextensions.InstallNBExtensionApp",
- "DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files"
- )
- subcommands.update(deprecated_subcommands)
+
# *do* autocreate requested profile, but don't create the config file.
auto_create=Bool(True)
@@ -288,22 +264,6 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
# internal, not-configurable
something_to_run=Bool(False)
- def parse_command_line(self, argv=None):
- """override to allow old '-pylab' flag with deprecation warning"""
-
- argv = sys.argv[1:] if argv is None else argv
-
- if '-pylab' in argv:
- # deprecated `-pylab` given,
- # warn and transform into current syntax
- argv = argv[:] # copy, don't clobber
- idx = argv.index('-pylab')
- warnings.warn("`-pylab` flag has been deprecated.\n"
- " Use `--matplotlib <backend>` and import pylab manually.")
- argv[idx] = '--pylab'
-
- return super(TerminalIPythonApp, self).parse_command_line(argv)
-
@catch_config_error
def initialize(self, argv=None):
"""Do actions after construct, but before starting the app."""
diff --git a/contrib/python/ipython/py3/IPython/terminal/magics.py b/contrib/python/ipython/py3/IPython/terminal/magics.py
index 42231c3f80..206ff20a0f 100644
--- a/contrib/python/ipython/py3/IPython/terminal/magics.py
+++ b/contrib/python/ipython/py3/IPython/terminal/magics.py
@@ -11,6 +11,7 @@ import sys
from IPython.core.error import TryNext, UsageError
from IPython.core.magic import Magics, magics_class, line_magic
from IPython.lib.clipboard import ClipboardEmpty
+from IPython.testing.skipdoctest import skip_doctest
from IPython.utils.text import SList, strip_email_quotes
from IPython.utils import py3compat
@@ -52,7 +53,7 @@ class TerminalMagics(Magics):
self.shell.user_ns['pasted_block'] = b
self.shell.using_paste_magics = True
try:
- self.shell.run_cell(b)
+ self.shell.run_cell(b, store_history=True)
finally:
self.shell.using_paste_magics = False
@@ -83,6 +84,7 @@ class TerminalMagics(Magics):
self.shell.set_autoindent()
print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
+ @skip_doctest
@line_magic
def cpaste(self, parameter_s=''):
"""Paste & execute a pre-formatted code block from clipboard.
@@ -111,9 +113,9 @@ class TerminalMagics(Magics):
Shell escapes are not supported (yet).
- See also
+ See Also
--------
- paste: automatically pull code from clipboard.
+ paste : automatically pull code from clipboard.
Examples
--------
@@ -174,9 +176,9 @@ class TerminalMagics(Magics):
IPython statements (magics, shell escapes) are not supported (yet).
- See also
+ See Also
--------
- cpaste: manually paste code into terminal until you mark its end.
+ cpaste : manually paste code into terminal until you mark its end.
"""
opts, name = self.parse_options(parameter_s, 'rq', mode='string')
if 'r' in opts:
@@ -191,16 +193,15 @@ class TerminalMagics(Magics):
else:
error('Could not get text from the clipboard.')
return
- except ClipboardEmpty:
- raise UsageError("The clipboard appears to be empty")
+ except ClipboardEmpty as e:
+ raise UsageError("The clipboard appears to be empty") from e
# By default, echo back to terminal unless quiet mode is requested
if 'q' not in opts:
- write = self.shell.write
- write(self.shell.pycolorize(block))
- if not block.endswith('\n'):
- write('\n')
- write("## -- End pasted text --\n")
+ sys.stdout.write(self.shell.pycolorize(block))
+ if not block.endswith("\n"):
+ sys.stdout.write("\n")
+ sys.stdout.write("## -- End pasted text --\n")
self.store_or_execute(block, name)
diff --git a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/asyncio.py b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/asyncio.py
index 95cf194f86..2d8c128208 100644
--- a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/asyncio.py
+++ b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/asyncio.py
@@ -27,15 +27,12 @@ prompt_toolkit`s `patch_stdout`)::
In [4]: asyncio.ensure_future(f())
"""
-import asyncio
from prompt_toolkit import __version__ as ptk_version
-PTK3 = ptk_version.startswith('3.')
+from IPython.core.async_helpers import get_asyncio_loop
+PTK3 = ptk_version.startswith('3.')
-# Keep reference to the original asyncio loop, because getting the event loop
-# within the input hook would return the other loop.
-loop = asyncio.get_event_loop()
def inputhook(context):
@@ -52,6 +49,9 @@ def inputhook(context):
# For prompt_toolkit 2.0, we can run the current asyncio event loop,
# because prompt_toolkit 2.0 uses a different event loop internally.
+ # get the persistent asyncio event loop
+ loop = get_asyncio_loop()
+
def stop():
loop.stop()
@@ -61,4 +61,3 @@ def inputhook(context):
loop.run_forever()
finally:
loop.remove_reader(fileno)
-
diff --git a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/glut.py b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/glut.py
index f6d54a55b4..835aadfc97 100644
--- a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/glut.py
+++ b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/glut.py
@@ -44,10 +44,10 @@ if sys.platform == 'darwin':
doc='glutCheckLoop( ) -> None',
argNames=(),
)
- except AttributeError:
+ except AttributeError as e:
raise RuntimeError(
- '''Your glut implementation does not allow interactive sessions'''
- '''Consider installing freeglut.''')
+ '''Your glut implementation does not allow interactive sessions. '''
+ '''Consider installing freeglut.''') from e
glutMainLoopEvent = glutCheckLoop
elif glut.HAVE_FREEGLUT:
glutMainLoopEvent = glut.glutMainLoopEvent
diff --git a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py
index 80440196fb..2754820efc 100644
--- a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py
+++ b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py
@@ -9,7 +9,7 @@ import ctypes
import ctypes.util
from threading import Event
-objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
+objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc")) # type: ignore
void_p = ctypes.c_void_p
@@ -37,7 +37,7 @@ def C(classname):
# end obj-c boilerplate from appnope
# CoreFoundation C-API calls we will use:
-CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
+CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library("CoreFoundation")) # type: ignore
CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate
CFFileDescriptorCreate.restype = void_p
diff --git a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/qt.py b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/qt.py
index b999f5aa17..f1e710aff5 100644
--- a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/qt.py
+++ b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/qt.py
@@ -74,6 +74,8 @@ def inputhook(context):
)
try:
# connect the callback we care about before we turn it on
+ # lambda is necessary as PyQT inspect the function signature to know
+ # what arguments to pass to. See https://github.com/ipython/ipython/pull/12355
notifier.activated.connect(lambda: event_loop.exit())
notifier.setEnabled(True)
# only start the event loop we are not already flipped
diff --git a/contrib/python/ipython/py3/IPython/terminal/ptshell.py b/contrib/python/ipython/py3/IPython/terminal/ptshell.py
deleted file mode 100644
index 666d3c5b51..0000000000
--- a/contrib/python/ipython/py3/IPython/terminal/ptshell.py
+++ /dev/null
@@ -1,8 +0,0 @@
-raise DeprecationWarning("""DEPRECATED:
-
-After Popular request and decision from the BDFL:
-`IPython.terminal.ptshell` has been moved back to `IPython.terminal.interactiveshell`
-during the beta cycle (after IPython 5.0.beta3) Sorry about that.
-
-This file will be removed in 5.0 rc or final.
-""")
diff --git a/contrib/python/ipython/py3/IPython/terminal/ptutils.py b/contrib/python/ipython/py3/IPython/terminal/ptutils.py
index 3e5d3c5c77..c390d4972a 100644
--- a/contrib/python/ipython/py3/IPython/terminal/ptutils.py
+++ b/contrib/python/ipython/py3/IPython/terminal/ptutils.py
@@ -9,8 +9,6 @@ not to be used outside IPython.
import unicodedata
from wcwidth import wcwidth
-import sys
-import traceback
from IPython.core.completer import (
provisionalcompleter, cursor_to_position,
@@ -22,6 +20,8 @@ from prompt_toolkit.patch_stdout import patch_stdout
import pygments.lexers as pygments_lexers
import os
+import sys
+import traceback
_completion_sentinel = object()
diff --git a/contrib/python/ipython/py3/IPython/terminal/shortcuts.py b/contrib/python/ipython/py3/IPython/terminal/shortcuts.py
index a23fa091a0..615397abc5 100644
--- a/contrib/python/ipython/py3/IPython/terminal/shortcuts.py
+++ b/contrib/python/ipython/py3/IPython/terminal/shortcuts.py
@@ -9,6 +9,8 @@ Module to define and register Terminal IPython shortcuts with
import warnings
import signal
import sys
+import re
+import os
from typing import Callable
@@ -18,6 +20,8 @@ from prompt_toolkit.filters import (has_focus, has_selection, Condition,
vi_insert_mode, emacs_insert_mode, has_completions, vi_mode)
from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.key_binding.bindings import named_commands as nc
+from prompt_toolkit.key_binding.vi_state import InputMode, ViState
from IPython.utils.decorators import undoc
@@ -53,7 +57,7 @@ def create_ipython_shortcuts(shell):
& insert_mode
))(reformat_and_execute)
- kb.add('c-\\')(force_exit)
+ kb.add("c-\\")(quit)
kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
)(previous_history_or_previous_completion)
@@ -82,15 +86,274 @@ def create_ipython_shortcuts(shell):
kb.add('f2', filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)
- if shell.display_completions == 'readlinelike':
- kb.add('c-i', filter=(has_focus(DEFAULT_BUFFER)
- & ~has_selection
- & insert_mode
- & ~cursor_in_leading_ws
- ))(display_completions_like_readline)
+ @Condition
+ def auto_match():
+ return shell.auto_match
- if sys.platform == 'win32':
- kb.add('c-v', filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
+ focused_insert = (vi_insert_mode | emacs_insert_mode) & has_focus(DEFAULT_BUFFER)
+ _preceding_text_cache = {}
+ _following_text_cache = {}
+
+ def preceding_text(pattern):
+ try:
+ return _preceding_text_cache[pattern]
+ except KeyError:
+ pass
+ m = re.compile(pattern)
+
+ def _preceding_text():
+ app = get_app()
+ return bool(m.match(app.current_buffer.document.current_line_before_cursor))
+
+ condition = Condition(_preceding_text)
+ _preceding_text_cache[pattern] = condition
+ return condition
+
+ def following_text(pattern):
+ try:
+ return _following_text_cache[pattern]
+ except KeyError:
+ pass
+ m = re.compile(pattern)
+
+ def _following_text():
+ app = get_app()
+ return bool(m.match(app.current_buffer.document.current_line_after_cursor))
+
+ condition = Condition(_following_text)
+ _following_text_cache[pattern] = condition
+ return condition
+
+ # auto match
+ @kb.add("(", filter=focused_insert & auto_match & following_text(r"[,)}\]]|$"))
+ def _(event):
+ event.current_buffer.insert_text("()")
+ event.current_buffer.cursor_left()
+
+ @kb.add("[", filter=focused_insert & auto_match & following_text(r"[,)}\]]|$"))
+ def _(event):
+ event.current_buffer.insert_text("[]")
+ event.current_buffer.cursor_left()
+
+ @kb.add("{", filter=focused_insert & auto_match & following_text(r"[,)}\]]|$"))
+ def _(event):
+ event.current_buffer.insert_text("{}")
+ event.current_buffer.cursor_left()
+
+ @kb.add(
+ '"',
+ filter=focused_insert
+ & auto_match
+ & preceding_text(r'^([^"]+|"[^"]*")*$')
+ & following_text(r"[,)}\]]|$"),
+ )
+ def _(event):
+ event.current_buffer.insert_text('""')
+ event.current_buffer.cursor_left()
+
+ @kb.add(
+ "'",
+ filter=focused_insert
+ & auto_match
+ & preceding_text(r"^([^']+|'[^']*')*$")
+ & following_text(r"[,)}\]]|$"),
+ )
+ def _(event):
+ event.current_buffer.insert_text("''")
+ event.current_buffer.cursor_left()
+
+ # raw string
+ @kb.add(
+ "(", filter=focused_insert & auto_match & preceding_text(r".*(r|R)[\"'](-*)$")
+ )
+ def _(event):
+ matches = re.match(
+ r".*(r|R)[\"'](-*)",
+ event.current_buffer.document.current_line_before_cursor,
+ )
+ dashes = matches.group(2) or ""
+ event.current_buffer.insert_text("()" + dashes)
+ event.current_buffer.cursor_left(len(dashes) + 1)
+
+ @kb.add(
+ "[", filter=focused_insert & auto_match & preceding_text(r".*(r|R)[\"'](-*)$")
+ )
+ def _(event):
+ matches = re.match(
+ r".*(r|R)[\"'](-*)",
+ event.current_buffer.document.current_line_before_cursor,
+ )
+ dashes = matches.group(2) or ""
+ event.current_buffer.insert_text("[]" + dashes)
+ event.current_buffer.cursor_left(len(dashes) + 1)
+
+ @kb.add(
+ "{", filter=focused_insert & auto_match & preceding_text(r".*(r|R)[\"'](-*)$")
+ )
+ def _(event):
+ matches = re.match(
+ r".*(r|R)[\"'](-*)",
+ event.current_buffer.document.current_line_before_cursor,
+ )
+ dashes = matches.group(2) or ""
+ event.current_buffer.insert_text("{}" + dashes)
+ event.current_buffer.cursor_left(len(dashes) + 1)
+
+ # just move cursor
+ @kb.add(")", filter=focused_insert & auto_match & following_text(r"^\)"))
+ @kb.add("]", filter=focused_insert & auto_match & following_text(r"^\]"))
+ @kb.add("}", filter=focused_insert & auto_match & following_text(r"^\}"))
+ @kb.add('"', filter=focused_insert & auto_match & following_text('^"'))
+ @kb.add("'", filter=focused_insert & auto_match & following_text("^'"))
+ def _(event):
+ event.current_buffer.cursor_right()
+
+ @kb.add(
+ "backspace",
+ filter=focused_insert
+ & preceding_text(r".*\($")
+ & auto_match
+ & following_text(r"^\)"),
+ )
+ @kb.add(
+ "backspace",
+ filter=focused_insert
+ & preceding_text(r".*\[$")
+ & auto_match
+ & following_text(r"^\]"),
+ )
+ @kb.add(
+ "backspace",
+ filter=focused_insert
+ & preceding_text(r".*\{$")
+ & auto_match
+ & following_text(r"^\}"),
+ )
+ @kb.add(
+ "backspace",
+ filter=focused_insert
+ & preceding_text('.*"$')
+ & auto_match
+ & following_text('^"'),
+ )
+ @kb.add(
+ "backspace",
+ filter=focused_insert
+ & preceding_text(r".*'$")
+ & auto_match
+ & following_text(r"^'"),
+ )
+ def _(event):
+ event.current_buffer.delete()
+ event.current_buffer.delete_before_cursor()
+
+ if shell.display_completions == "readlinelike":
+ kb.add(
+ "c-i",
+ filter=(
+ has_focus(DEFAULT_BUFFER)
+ & ~has_selection
+ & insert_mode
+ & ~cursor_in_leading_ws
+ ),
+ )(display_completions_like_readline)
+
+ if sys.platform == "win32":
+ kb.add("c-v", filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
+
+ @Condition
+ def ebivim():
+ return shell.emacs_bindings_in_vi_insert_mode
+
+ focused_insert_vi = has_focus(DEFAULT_BUFFER) & vi_insert_mode
+
+ # Needed for to accept autosuggestions in vi insert mode
+ def _apply_autosuggest(event):
+ b = event.current_buffer
+ suggestion = b.suggestion
+ if suggestion is not None and suggestion.text:
+ b.insert_text(suggestion.text)
+ else:
+ nc.end_of_line(event)
+
+ @kb.add("end", filter=has_focus(DEFAULT_BUFFER) & (ebivim | ~vi_insert_mode))
+ def _(event):
+ _apply_autosuggest(event)
+
+ @kb.add("c-e", filter=focused_insert_vi & ebivim)
+ def _(event):
+ _apply_autosuggest(event)
+
+ @kb.add("c-f", filter=focused_insert_vi)
+ def _(event):
+ b = event.current_buffer
+ suggestion = b.suggestion
+ if suggestion:
+ b.insert_text(suggestion.text)
+ else:
+ nc.forward_char(event)
+
+ @kb.add("escape", "f", filter=focused_insert_vi & ebivim)
+ def _(event):
+ b = event.current_buffer
+ suggestion = b.suggestion
+ if suggestion:
+ t = re.split(r"(\S+\s+)", suggestion.text)
+ b.insert_text(next((x for x in t if x), ""))
+ else:
+ nc.forward_word(event)
+
+ # Simple Control keybindings
+ key_cmd_dict = {
+ "c-a": nc.beginning_of_line,
+ "c-b": nc.backward_char,
+ "c-k": nc.kill_line,
+ "c-w": nc.backward_kill_word,
+ "c-y": nc.yank,
+ "c-_": nc.undo,
+ }
+
+ for key, cmd in key_cmd_dict.items():
+ kb.add(key, filter=focused_insert_vi & ebivim)(cmd)
+
+ # Alt and Combo Control keybindings
+ keys_cmd_dict = {
+ # Control Combos
+ ("c-x", "c-e"): nc.edit_and_execute,
+ ("c-x", "e"): nc.edit_and_execute,
+ # Alt
+ ("escape", "b"): nc.backward_word,
+ ("escape", "c"): nc.capitalize_word,
+ ("escape", "d"): nc.kill_word,
+ ("escape", "h"): nc.backward_kill_word,
+ ("escape", "l"): nc.downcase_word,
+ ("escape", "u"): nc.uppercase_word,
+ ("escape", "y"): nc.yank_pop,
+ ("escape", "."): nc.yank_last_arg,
+ }
+
+ for keys, cmd in keys_cmd_dict.items():
+ kb.add(*keys, filter=focused_insert_vi & ebivim)(cmd)
+
+ def get_input_mode(self):
+ app = get_app()
+ app.ttimeoutlen = shell.ttimeoutlen
+ app.timeoutlen = shell.timeoutlen
+
+ return self._input_mode
+
+ def set_input_mode(self, mode):
+ shape = {InputMode.NAVIGATION: 2, InputMode.REPLACE: 4}.get(mode, 6)
+ cursor = "\x1b[{} q".format(shape)
+
+ sys.stdout.write(cursor)
+ sys.stdout.flush()
+
+ self._input_mode = mode
+
+ if shell.editing_mode == "vi" and shell.modal_cursor:
+ ViState._input_mode = InputMode.INSERT
+ ViState.input_mode = property(get_input_mode, set_input_mode)
return kb
@@ -196,11 +459,16 @@ def reset_search_buffer(event):
def suspend_to_bg(event):
event.app.suspend_to_background()
-def force_exit(event):
+def quit(event):
"""
- Force exit (with a non-zero return value)
+ On platforms that support SIGQUIT, send SIGQUIT to the current process.
+ On other platforms, just exit the process with a message.
"""
- sys.exit("Quit")
+ sigquit = getattr(signal, "SIGQUIT", None)
+ if sigquit is not None:
+ os.kill(0, signal.SIGQUIT)
+ else:
+ sys.exit("Quit")
def indent_buffer(event):
event.current_buffer.insert_text(' ' * 4)
@@ -273,4 +541,4 @@ if sys.platform == 'win32':
return
except ClipboardEmpty:
return
- event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
+ event.current_buffer.insert_text(text.replace("\t", " " * 4))