Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4e7b940

Browse files
authored
Fix autosuggestions in multi-line mode, vi command mode delay (#13991)
Fixes #13970. Relates to #13443. Documents #12603 with a new `emacs_like_insert_mode` filter alias.
2 parents ad452c1 + eccd2db commit 4e7b940

4 files changed

Lines changed: 84 additions & 16 deletions

File tree

IPython/terminal/shortcuts/__init__.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -181,30 +181,45 @@ def create_identifier(handler: Callable):
181181
]
182182

183183
AUTO_SUGGEST_BINDINGS = [
184+
# there are two reasons for re-defining bindings defined upstream:
185+
# 1) prompt-toolkit does not execute autosuggestion bindings in vi mode,
186+
# 2) prompt-toolkit checks if we are at the end of text, not end of line
187+
# hence it does not work in multi-line mode of navigable provider
184188
Binding(
185-
auto_suggest.accept_in_vi_insert_mode,
189+
auto_suggest.accept_or_jump_to_end,
186190
["end"],
187-
"default_buffer_focused & (ebivim | ~vi_insert_mode)",
191+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
188192
),
189193
Binding(
190-
auto_suggest.accept_in_vi_insert_mode,
194+
auto_suggest.accept_or_jump_to_end,
191195
["c-e"],
192-
"vi_insert_mode & default_buffer_focused & ebivim",
196+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
197+
),
198+
Binding(
199+
auto_suggest.accept,
200+
["c-f"],
201+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
202+
),
203+
Binding(
204+
auto_suggest.accept,
205+
["right"],
206+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
193207
),
194-
Binding(auto_suggest.accept, ["c-f"], "vi_insert_mode & default_buffer_focused"),
195208
Binding(
196209
auto_suggest.accept_word,
197210
["escape", "f"],
198-
"vi_insert_mode & default_buffer_focused & ebivim",
211+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
199212
),
200213
Binding(
201214
auto_suggest.accept_token,
202215
["c-right"],
203-
"has_suggestion & default_buffer_focused",
216+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
204217
),
205218
Binding(
206219
auto_suggest.discard,
207220
["escape"],
221+
# note this one is using `emacs_insert_mode`, not `emacs_like_insert_mode`
222+
# as in `vi_insert_mode` we do not want `escape` to be shadowed (ever).
208223
"has_suggestion & default_buffer_focused & emacs_insert_mode",
209224
),
210225
Binding(
@@ -241,22 +256,23 @@ def create_identifier(handler: Callable):
241256
Binding(
242257
auto_suggest.accept_character,
243258
["escape", "right"],
244-
"has_suggestion & default_buffer_focused",
259+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
245260
),
246261
Binding(
247262
auto_suggest.accept_and_move_cursor_left,
248263
["c-left"],
249-
"has_suggestion & default_buffer_focused",
264+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
250265
),
251266
Binding(
252267
auto_suggest.accept_and_keep_cursor,
253268
["c-down"],
254-
"has_suggestion & default_buffer_focused",
269+
"has_suggestion & default_buffer_focused & emacs_like_insert_mode",
255270
),
256271
Binding(
257272
auto_suggest.backspace_and_resume_hint,
258273
["backspace"],
259-
"has_suggestion & default_buffer_focused",
274+
# no `has_suggestion` here to allow resuming if no suggestion
275+
"default_buffer_focused & emacs_like_insert_mode",
260276
),
261277
]
262278

IPython/terminal/shortcuts/auto_suggest.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import tokenize
33
from io import StringIO
44
from typing import Callable, List, Optional, Union, Generator, Tuple
5+
import warnings
56

67
from prompt_toolkit.buffer import Buffer
78
from prompt_toolkit.key_binding import KeyPressEvent
@@ -178,9 +179,8 @@ def down(self, query: str, other_than: str, history: History) -> None:
178179
break
179180

180181

181-
# Needed for to accept autosuggestions in vi insert mode
182-
def accept_in_vi_insert_mode(event: KeyPressEvent):
183-
"""Apply autosuggestion if at end of line."""
182+
def accept_or_jump_to_end(event: KeyPressEvent):
183+
"""Apply autosuggestion or jump to end of line."""
184184
buffer = event.current_buffer
185185
d = buffer.document
186186
after_cursor = d.text[d.cursor_position :]
@@ -193,6 +193,15 @@ def accept_in_vi_insert_mode(event: KeyPressEvent):
193193
nc.end_of_line(event)
194194

195195

196+
def _deprected_accept_in_vi_insert_mode(event: KeyPressEvent):
197+
"""Accept autosuggestion or jump to end of line.
198+
199+
.. deprecated:: 8.12
200+
Use `accept_or_jump_to_end` instead.
201+
"""
202+
return accept_or_jump_to_end(event)
203+
204+
196205
def accept(event: KeyPressEvent):
197206
"""Accept autosuggestion"""
198207
buffer = event.current_buffer
@@ -373,3 +382,16 @@ def swap_autosuggestion_down(event: KeyPressEvent):
373382
provider=provider,
374383
direction_method=provider.down,
375384
)
385+
386+
387+
def __getattr__(key):
388+
if key == "accept_in_vi_insert_mode":
389+
warnings.warn(
390+
"`accept_in_vi_insert_mode` is deprecated since IPython 8.12 and "
391+
"renamed to `accept_or_jump_to_end`. Please update your configuration "
392+
"accordingly",
393+
DeprecationWarning,
394+
stacklevel=2,
395+
)
396+
return _deprected_accept_in_vi_insert_mode
397+
raise AttributeError

IPython/terminal/shortcuts/filters.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,33 @@ def is_windows_os():
181181
"vi_mode": vi_mode,
182182
"vi_insert_mode": vi_insert_mode,
183183
"emacs_insert_mode": emacs_insert_mode,
184+
# https://github.com/ipython/ipython/pull/12603 argued for inclusion of
185+
# emacs key bindings with a configurable `emacs_bindings_in_vi_insert_mode`
186+
# toggle; when the toggle is on user can access keybindigns like `ctrl + e`
187+
# in vi insert mode. Because some of the emacs bindings involve `escape`
188+
# followed by another key, e.g. `escape` followed by `f`, prompt-toolkit
189+
# needs to wait to see if there will be another character typed in before
190+
# executing pure `escape` keybinding; in vi insert mode `escape` switches to
191+
# command mode which is common and performance critical action for vi users.
192+
# To avoid the delay users employ a workaround:
193+
# https://github.com/ipython/ipython/issues/13443#issuecomment-1032753703
194+
# which involves switching `emacs_bindings_in_vi_insert_mode` off.
195+
#
196+
# For the workaround to work:
197+
# 1) end users need to toggle `emacs_bindings_in_vi_insert_mode` off
198+
# 2) all keybindings which would involve `escape` need to respect that
199+
# toggle by including either:
200+
# - `vi_insert_mode & ebivim` for actions which have emacs keybindings
201+
# predefined upstream in prompt-toolkit, or
202+
# - `emacs_like_insert_mode` for actions which do not have existing
203+
# emacs keybindings predefined upstream (or need overriding of the
204+
# upstream bindings to modify behaviour), defined below.
205+
"emacs_like_insert_mode": (vi_insert_mode & ebivim) | emacs_insert_mode,
184206
"has_completions": has_completions,
185207
"insert_mode": vi_insert_mode | emacs_insert_mode,
186208
"default_buffer_focused": default_buffer_focused,
187209
"search_buffer_focused": has_focus(SEARCH_BUFFER),
210+
# `ebivim` stands for emacs bindings in vi insert mode
188211
"ebivim": ebivim,
189212
"supports_suspend": supports_suspend,
190213
"is_windows_os": is_windows_os,

IPython/terminal/tests/test_shortcuts.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22
from IPython.terminal.shortcuts.auto_suggest import (
33
accept,
4-
accept_in_vi_insert_mode,
4+
accept_or_jump_to_end,
55
accept_token,
66
accept_character,
77
accept_word,
@@ -22,6 +22,13 @@
2222
from unittest.mock import patch, Mock
2323

2424

25+
def test_deprected():
26+
import IPython.terminal.shortcuts.auto_suggest as iptsa
27+
28+
with pytest.warns(DeprecationWarning, match=r"8\.12.+accept_or_jump_to_end"):
29+
iptsa.accept_in_vi_insert_mode
30+
31+
2532
def make_event(text, cursor, suggestion):
2633
event = Mock()
2734
event.current_buffer = Mock()
@@ -80,7 +87,7 @@ def test_autosuggest_at_EOL(text, cursor, suggestion, called):
8087

8188
event = make_event(text, cursor, suggestion)
8289
event.current_buffer.insert_text = Mock()
83-
accept_in_vi_insert_mode(event)
90+
accept_or_jump_to_end(event)
8491
if called:
8592
event.current_buffer.insert_text.assert_called()
8693
else:

0 commit comments

Comments
 (0)