From bdd35d87ba3466a5a002e6f245f590fae5254d91 Mon Sep 17 00:00:00 2001 From: Roland Walker Date: Fri, 6 Mar 2026 05:06:55 -0500 Subject: [PATCH] settable ttimeoutlen for Escape key sequences Since olden times, most terminals have sent Alt+key combinations, function keys, and so on as sequences of characters starting with Escape. This creates an ambiguity. What if the user simply typed "Escape"? Terminal applications solve this by waiting some period of time before registering a plain "Escape". prompt_toolkit waits a default of 0.5 seconds. This pause can be a nuisance for users who use the Escape key, especially users of vi keybindings. Here we provide access to prompt_toolkit's ttimeoutlen property, making the value independent between Emacs and vi modes. At smaller values, an Escape key alone is recognized much more quickly. The toolbar UI for vi modes may lag on the display of a change in state, but the keystroke is recognized for the typist. The setting is named after the Vim setting for familiarity to the group most likely to need it. --- changelog.md | 8 ++++++++ mycli/key_bindings.py | 4 ++++ mycli/main.py | 7 +++++++ mycli/myclirc | 8 ++++++++ test/myclirc | 8 ++++++++ 5 files changed, 35 insertions(+) diff --git a/changelog.md b/changelog.md index 972a730d..2c9f27a6 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,11 @@ +Upcoming (TBD) +============== + +Features +--------- +* Allow shorter timeout lengths after pressing Esc, for vi-mode. + + 1.60.0 (2026/03/05) ============== diff --git a/mycli/key_bindings.py b/mycli/key_bindings.py index 9da02dac..86597483 100644 --- a/mycli/key_bindings.py +++ b/mycli/key_bindings.py @@ -103,9 +103,11 @@ def _(event: KeyPressEvent) -> None: if mycli.key_bindings == "vi": event.app.editing_mode = EditingMode.EMACS mycli.key_bindings = "emacs" + event.app.ttimeoutlen = mycli.emacs_ttimeoutlen else: event.app.editing_mode = EditingMode.VI mycli.key_bindings = "vi" + event.app.ttimeoutlen = mycli.vi_ttimeoutlen @kb.add('escape', '[', 'S') def _(event: KeyPressEvent) -> None: @@ -114,9 +116,11 @@ def _(event: KeyPressEvent) -> None: if mycli.key_bindings == 'vi': event.app.editing_mode = EditingMode.EMACS mycli.key_bindings = 'emacs' + event.app.ttimeoutlen = mycli.emacs_ttimeoutlen else: event.app.editing_mode = EditingMode.VI mycli.key_bindings = 'vi' + event.app.ttimeoutlen = mycli.vi_ttimeoutlen @kb.add("tab") def _(event: KeyPressEvent) -> None: diff --git a/mycli/main.py b/mycli/main.py index a6ccdc3e..873b62ef 100755 --- a/mycli/main.py +++ b/mycli/main.py @@ -198,6 +198,8 @@ def __init__( self.config_without_user_options = read_config_files(config_files, ignore_user_options=True) self.multi_line = c["main"].as_bool("multi_line") self.key_bindings = c["main"]["key_bindings"] + self.emacs_ttimeoutlen = c['keys'].as_float('emacs_ttimeoutlen') + self.vi_ttimeoutlen = c['keys'].as_float('vi_ttimeoutlen') special.set_timing_enabled(c["main"].as_bool("timing")) special.set_show_favorite_query(c["main"].as_bool("show_favorite_query")) self.beep_after_seconds = float(c["main"]["beep_after_seconds"] or 0) @@ -1311,6 +1313,11 @@ def one_iteration(text: str | None = None) -> None: search_ignore_case=True, ) + if self.key_bindings == 'vi': + self.prompt_app.app.ttimeoutlen = self.vi_ttimeoutlen + else: + self.prompt_app.app.ttimeoutlen = self.emacs_ttimeoutlen + try: while True: one_iteration() diff --git a/mycli/myclirc b/mycli/myclirc index 057f6c30..5060386d 100644 --- a/mycli/myclirc +++ b/mycli/myclirc @@ -235,6 +235,14 @@ control_d = exit # possible values: auto, fzf, reverse_isearch control_r = auto +# 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. +vi_ttimeoutlen = 0.1 + +# How long to wait for an Escape key sequence in Emacs mode. +emacs_ttimeoutlen = 0.5 + # Custom colors for the completion menu, toolbar, etc, with actual support # depending on the terminal, and the property being set. # Colors: #ffffff, bg:#ffffff, border:#ffffff. diff --git a/test/myclirc b/test/myclirc index 4b37d012..64966274 100644 --- a/test/myclirc +++ b/test/myclirc @@ -233,6 +233,14 @@ control_d = exit # possible values: auto, fzf, reverse_isearch control_r = auto +# 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. +vi_ttimeoutlen = 0.1 + +# How long to wait for an Escape key sequence in Emacs mode. +emacs_ttimeoutlen = 0.5 + # Custom colors for the completion menu, toolbar, etc, with actual support # depending on the terminal, and the property being set. # Colors: #ffffff, bg:#ffffff, border:#ffffff.