From 5158c639a4d0774b0a91f78bc549ea38e2739693 Mon Sep 17 00:00:00 2001 From: Roland Walker Date: Thu, 5 Mar 2026 05:24:38 -0500 Subject: [PATCH] let completion-key bindings be configurable but set to the current behaviors by default. There are several behaviors, some of which are mutually exclusive. It would be complex to lay out in the options which are exclusive, so that is just documented in the commentary. --- changelog.md | 1 + mycli/key_bindings.py | 50 +++++++++++++++++++++++++++++++++++++------ mycli/myclirc | 13 +++++++++++ test/myclirc | 13 +++++++++++ 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 2c9f27a6..fb622df9 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ Upcoming (TBD) Features --------- * Allow shorter timeout lengths after pressing Esc, for vi-mode. +* Let tab and control-space behaviors be configurable. 1.60.0 (2026/03/05) diff --git a/mycli/key_bindings.py b/mycli/key_bindings.py index 86597483..d209f726 100644 --- a/mycli/key_bindings.py +++ b/mycli/key_bindings.py @@ -12,6 +12,7 @@ ) from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.key_binding.key_processor import KeyPressEvent +from prompt_toolkit.selection import SelectionType from mycli.constants import DOCS_URL from mycli.packages import shortcuts @@ -124,13 +125,31 @@ def _(event: KeyPressEvent) -> None: @kb.add("tab") def _(event: KeyPressEvent) -> None: - """Force autocompletion at cursor.""" + """Complete action at cursor.""" _logger.debug("Detected key.") b = event.app.current_buffer + + behaviors = mycli.config['keys'].as_list('tab') + + if 'toolkit_default' in behaviors: + if b.complete_state: + b.complete_next() + else: + b.start_completion(select_first=True) + if b.complete_state: - b.complete_next() - else: + if 'advance' in behaviors: + b.complete_next() + elif 'cancel' in behaviors: + b.cancel_completion() + return + + if 'advancing_summon' in behaviors: b.start_completion(select_first=True) + elif 'prefixing_summon' in behaviors: + b.start_completion(insert_common_part=True) + elif 'summon' in behaviors: + b.start_completion(select_first=False) @kb.add("escape", eager=True, filter=in_completion) def _(event: KeyPressEvent) -> None: @@ -145,9 +164,9 @@ def _(event: KeyPressEvent) -> None: @kb.add("c-space") def _(event: KeyPressEvent) -> None: """ - Initialize autocompletion at cursor. + Complete action at cursor. - If the autocompletion menu is not showing, display it with the + By default, if the autocompletion menu is not showing, display it with the appropriate completions for the context. If the menu is showing, select the next completion. @@ -155,9 +174,26 @@ def _(event: KeyPressEvent) -> None: _logger.debug("Detected key.") b = event.app.current_buffer + + behaviors = mycli.config['keys'].as_list('control_space') + + if 'toolkit_default' in behaviors: + if b.text: + b.start_selection(selection_type=SelectionType.CHARACTERS) + return + if b.complete_state: - b.complete_next() - else: + if 'advance' in behaviors: + b.complete_next() + elif 'cancel' in behaviors: + b.cancel_completion() + return + + if 'advancing_summon' in behaviors: + b.start_completion(select_first=True) + elif 'prefixing_summon' in behaviors: + b.start_completion(insert_common_part=True) + elif 'summon' in behaviors: b.start_completion(select_first=False) @kb.add("c-x", "p", filter=emacs_mode) diff --git a/mycli/myclirc b/mycli/myclirc index 5060386d..1d741811 100644 --- a/mycli/myclirc +++ b/mycli/myclirc @@ -235,6 +235,19 @@ control_d = exit # possible values: auto, fzf, reverse_isearch control_r = auto +# comma-separated list: toolkit_default, summon, advancing_summon, prefixing_summon, advance, cancel +# +# * toolkit_default - ignore other behaviors and use prompt_toolkit's default bindings +# * summon - when completions are not visible, summon them +# * advancing_summon - when completions are not visible, summon them _and_ advance in the list +# * prefixing_summon - when completions are not visible, summon them _and_ insert the common prefix +# * advance - when completions are visible, advance in the list +# * cancel - when completions are visible, toggle the list off +control_space = summon, advance + +# comma-separated list: toolkit_default, summon, advancing_summon, prefixing_summon, advance, cancel +tab = advancing_summon, advance + # How long to wait for an Escape key sequence in vi mode. # 0.5 seconds is the prompt_toolkit default, but vi users may find that too long. # Shorter values mean that "Escape" alone is recognized more quickly. diff --git a/test/myclirc b/test/myclirc index 64966274..734f07ef 100644 --- a/test/myclirc +++ b/test/myclirc @@ -233,6 +233,19 @@ control_d = exit # possible values: auto, fzf, reverse_isearch control_r = auto +# comma-separated list: toolkit_default, summon, advancing_summon, prefixing_summon, advance, cancel +# +# * toolkit_default - ignore other behaviors and use prompt_toolkit's default bindings +# * summon - when completions are not visible, summon them +# * advancing_summon - when completions are not visible, summon them _and_ advance in the list +# * prefixing_summon - when completions are not visible, summon them _and_ insert the common prefix +# * advance - when completions are visible, advance in the list +# * cancel - when completions are visible, toggle the list off +control_space = summon, advance + +# comma-separated list: toolkit_default, summon, advancing_summon, prefixing_summon, advance, cancel +tab = advancing_summon, advance + # How long to wait for an Escape key sequence in vi mode. # 0.5 seconds is the prompt_toolkit default, but vi users may find that too long. # Shorter values mean that "Escape" alone is recognized more quickly.