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.