diff --git a/IPython/terminal/shortcuts/__init__.py b/IPython/terminal/shortcuts/__init__.py index 41533c8..b787b09 100644 --- a/IPython/terminal/shortcuts/__init__.py +++ b/IPython/terminal/shortcuts/__init__.py @@ -181,30 +181,45 @@ AUTO_MATCH_BINDINGS = [ ] AUTO_SUGGEST_BINDINGS = [ + # there are two reasons for re-defining bindings defined upstream: + # 1) prompt-toolkit does not execute autosuggestion bindings in vi mode, + # 2) prompt-toolkit checks if we are at the end of text, not end of line + # hence it does not work in multi-line mode of navigable provider Binding( auto_suggest.accept_in_vi_insert_mode, ["end"], - "default_buffer_focused & (ebivim | ~vi_insert_mode)", + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", ), Binding( auto_suggest.accept_in_vi_insert_mode, ["c-e"], - "vi_insert_mode & default_buffer_focused & ebivim", + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", + ), + Binding( + auto_suggest.accept, + ["c-f"], + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", + ), + Binding( + auto_suggest.accept, + ["right"], + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", ), - Binding(auto_suggest.accept, ["c-f"], "vi_insert_mode & default_buffer_focused"), Binding( auto_suggest.accept_word, ["escape", "f"], - "vi_insert_mode & default_buffer_focused & ebivim", + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", ), Binding( auto_suggest.accept_token, ["c-right"], - "has_suggestion & default_buffer_focused", + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", ), Binding( auto_suggest.discard, ["escape"], + # note this one is using `emacs_insert_mode`, not `emacs_like_insert_mode` + # as in `vi_insert_mode` we do not want `escape` to be shadowed (ever). "has_suggestion & default_buffer_focused & emacs_insert_mode", ), Binding( @@ -236,22 +251,22 @@ AUTO_SUGGEST_BINDINGS = [ Binding( auto_suggest.accept_character, ["escape", "right"], - "has_suggestion & default_buffer_focused", + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", ), Binding( auto_suggest.accept_and_move_cursor_left, ["c-left"], - "has_suggestion & default_buffer_focused", + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", ), Binding( auto_suggest.accept_and_keep_cursor, ["c-down"], - "has_suggestion & default_buffer_focused", + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", ), Binding( auto_suggest.backspace_and_resume_hint, ["backspace"], - "has_suggestion & default_buffer_focused", + "has_suggestion & default_buffer_focused & emacs_like_insert_mode", ), ] diff --git a/IPython/terminal/shortcuts/auto_suggest.py b/IPython/terminal/shortcuts/auto_suggest.py index 0c193d9..6c2b4ff 100644 --- a/IPython/terminal/shortcuts/auto_suggest.py +++ b/IPython/terminal/shortcuts/auto_suggest.py @@ -178,9 +178,8 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory): break -# Needed for to accept autosuggestions in vi insert mode -def accept_in_vi_insert_mode(event: KeyPressEvent): - """Apply autosuggestion if at end of line.""" +def accept_or_jump_to_end(event: KeyPressEvent): + """Apply autosuggestion or jump to end of line.""" buffer = event.current_buffer d = buffer.document after_cursor = d.text[d.cursor_position :] @@ -193,6 +192,15 @@ def accept_in_vi_insert_mode(event: KeyPressEvent): nc.end_of_line(event) +def accept_in_vi_insert_mode(event: KeyPressEvent): + """Accept autosuggestion or jump to end of line. + + .. deprecated:: 8.12 + Use `accept_or_jump_to_end` instead. + """ + return accept_or_jump_to_end(event) + + def accept(event: KeyPressEvent): """Accept autosuggestion""" buffer = event.current_buffer diff --git a/IPython/terminal/shortcuts/filters.py b/IPython/terminal/shortcuts/filters.py index a4a6213..4627769 100644 --- a/IPython/terminal/shortcuts/filters.py +++ b/IPython/terminal/shortcuts/filters.py @@ -181,10 +181,33 @@ KEYBINDING_FILTERS = { "vi_mode": vi_mode, "vi_insert_mode": vi_insert_mode, "emacs_insert_mode": emacs_insert_mode, + # https://github.com/ipython/ipython/pull/12603 argued for inclusion of + # emacs key bindings with a configurable `emacs_bindings_in_vi_insert_mode` + # toggle; when the toggle is on user can access keybindigns like `ctrl + e` + # in vi insert mode. Because some of the emacs bindings involve `escape` + # followed by another key, e.g. `escape` followed by `f`, prompt-toolkit + # needs to wait to see if there will be another character typed in before + # executing pure `escape` keybinding; in vi insert mode `escape` switches to + # command mode which is common and performance critical action for vi users. + # To avoid the delay users employ a workaround: + # https://github.com/ipython/ipython/issues/13443#issuecomment-1032753703 + # which involves switching `emacs_bindings_in_vi_insert_mode` off. + # + # For the workaround to work: + # 1) end users need to toggle `emacs_bindings_in_vi_insert_mode` off + # 2) all keybindings which would involve `escape` need to respect that + # toggle by including either: + # - `vi_insert_mode & ebivim` for actions which have emacs keybindings + # predefined upstream in prompt-toolkit, or + # - `emacs_like_insert_mode` for actions which do not have existing + # emacs keybindings predefined upstream (or need overriding of the + # upstream bindings to modify behaviour), defined below. + "emacs_like_insert_mode": (vi_insert_mode & ebivim) | emacs_insert_mode, "has_completions": has_completions, "insert_mode": vi_insert_mode | emacs_insert_mode, "default_buffer_focused": default_buffer_focused, "search_buffer_focused": has_focus(SEARCH_BUFFER), + # `ebivim` stands for emacs bindings in vi insert mode "ebivim": ebivim, "supports_suspend": supports_suspend, "is_windows_os": is_windows_os,