##// END OF EJS Templates
Fix autosuggestions in multi-line mode, vi command mode delay (#13991)...
Matthias Bussonnier -
r28198:4e7b9408 merge
parent child Browse files
Show More
@@ -181,30 +181,45 b' AUTO_MATCH_BINDINGS = ['
181 181 ]
182 182
183 183 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
184 188 Binding(
185 auto_suggest.accept_in_vi_insert_mode,
189 auto_suggest.accept_or_jump_to_end,
186 190 ["end"],
187 "default_buffer_focused & (ebivim | ~vi_insert_mode)",
191 "has_suggestion & default_buffer_focused & emacs_like_insert_mode",
188 192 ),
189 193 Binding(
190 auto_suggest.accept_in_vi_insert_mode,
194 auto_suggest.accept_or_jump_to_end,
191 195 ["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",
193 207 ),
194 Binding(auto_suggest.accept, ["c-f"], "vi_insert_mode & default_buffer_focused"),
195 208 Binding(
196 209 auto_suggest.accept_word,
197 210 ["escape", "f"],
198 "vi_insert_mode & default_buffer_focused & ebivim",
211 "has_suggestion & default_buffer_focused & emacs_like_insert_mode",
199 212 ),
200 213 Binding(
201 214 auto_suggest.accept_token,
202 215 ["c-right"],
203 "has_suggestion & default_buffer_focused",
216 "has_suggestion & default_buffer_focused & emacs_like_insert_mode",
204 217 ),
205 218 Binding(
206 219 auto_suggest.discard,
207 220 ["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).
208 223 "has_suggestion & default_buffer_focused & emacs_insert_mode",
209 224 ),
210 225 Binding(
@@ -241,22 +256,23 b' AUTO_SUGGEST_BINDINGS = ['
241 256 Binding(
242 257 auto_suggest.accept_character,
243 258 ["escape", "right"],
244 "has_suggestion & default_buffer_focused",
259 "has_suggestion & default_buffer_focused & emacs_like_insert_mode",
245 260 ),
246 261 Binding(
247 262 auto_suggest.accept_and_move_cursor_left,
248 263 ["c-left"],
249 "has_suggestion & default_buffer_focused",
264 "has_suggestion & default_buffer_focused & emacs_like_insert_mode",
250 265 ),
251 266 Binding(
252 267 auto_suggest.accept_and_keep_cursor,
253 268 ["c-down"],
254 "has_suggestion & default_buffer_focused",
269 "has_suggestion & default_buffer_focused & emacs_like_insert_mode",
255 270 ),
256 271 Binding(
257 272 auto_suggest.backspace_and_resume_hint,
258 273 ["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",
260 276 ),
261 277 ]
262 278
@@ -2,6 +2,7 b' import re'
2 2 import tokenize
3 3 from io import StringIO
4 4 from typing import Callable, List, Optional, Union, Generator, Tuple
5 import warnings
5 6
6 7 from prompt_toolkit.buffer import Buffer
7 8 from prompt_toolkit.key_binding import KeyPressEvent
@@ -178,9 +179,8 b' class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):'
178 179 break
179 180
180 181
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."""
184 184 buffer = event.current_buffer
185 185 d = buffer.document
186 186 after_cursor = d.text[d.cursor_position :]
@@ -193,6 +193,15 b' def accept_in_vi_insert_mode(event: KeyPressEvent):'
193 193 nc.end_of_line(event)
194 194
195 195
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
196 205 def accept(event: KeyPressEvent):
197 206 """Accept autosuggestion"""
198 207 buffer = event.current_buffer
@@ -373,3 +382,16 b' def swap_autosuggestion_down(event: KeyPressEvent):'
373 382 provider=provider,
374 383 direction_method=provider.down,
375 384 )
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
@@ -181,10 +181,33 b' KEYBINDING_FILTERS = {'
181 181 "vi_mode": vi_mode,
182 182 "vi_insert_mode": vi_insert_mode,
183 183 "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,
184 206 "has_completions": has_completions,
185 207 "insert_mode": vi_insert_mode | emacs_insert_mode,
186 208 "default_buffer_focused": default_buffer_focused,
187 209 "search_buffer_focused": has_focus(SEARCH_BUFFER),
210 # `ebivim` stands for emacs bindings in vi insert mode
188 211 "ebivim": ebivim,
189 212 "supports_suspend": supports_suspend,
190 213 "is_windows_os": is_windows_os,
@@ -1,7 +1,7 b''
1 1 import pytest
2 2 from IPython.terminal.shortcuts.auto_suggest import (
3 3 accept,
4 accept_in_vi_insert_mode,
4 accept_or_jump_to_end,
5 5 accept_token,
6 6 accept_character,
7 7 accept_word,
@@ -22,6 +22,13 b' from prompt_toolkit.auto_suggest import AutoSuggestFromHistory'
22 22 from unittest.mock import patch, Mock
23 23
24 24
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
25 32 def make_event(text, cursor, suggestion):
26 33 event = Mock()
27 34 event.current_buffer = Mock()
@@ -80,7 +87,7 b' def test_autosuggest_at_EOL(text, cursor, suggestion, called):'
80 87
81 88 event = make_event(text, cursor, suggestion)
82 89 event.current_buffer.insert_text = Mock()
83 accept_in_vi_insert_mode(event)
90 accept_or_jump_to_end(event)
84 91 if called:
85 92 event.current_buffer.insert_text.assert_called()
86 93 else:
General Comments 0
You need to be logged in to leave comments. Login now