Add a prefix timeout option, from Conor Taylor in GitHub issue 4108.
authornicm <nicm@openbsd.org>
Mon, 16 Sep 2024 20:28:22 +0000 (20:28 +0000)
committernicm <nicm@openbsd.org>
Mon, 16 Sep 2024 20:28:22 +0000 (20:28 +0000)
usr.bin/tmux/options-table.c
usr.bin/tmux/server-client.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h

index 59cf346..9ef6ded 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: options-table.c,v 1.177 2024/08/21 04:37:42 nicm Exp $ */
+/* $OpenBSD: options-table.c,v 1.178 2024/09/16 20:28:22 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -386,6 +386,17 @@ const struct options_table_entry options_table[] = {
          .text = "Maximum number of server messages to keep."
        },
 
+       { .name = "prefix-timeout",
+         .type = OPTIONS_TABLE_NUMBER,
+         .scope = OPTIONS_TABLE_SERVER,
+         .minimum = 0,
+         .maximum = INT_MAX,
+         .default_num = 0,
+         .unit = "milliseconds",
+         .text = "The timeout for the prefix key if no subsequent key is "
+                 "pressed. Zero means disabled."
+       },
+
        { .name = "prompt-history-limit",
          .type = OPTIONS_TABLE_NUMBER,
          .scope = OPTIONS_TABLE_SERVER,
index a8c5012..b929c20 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.408 2024/09/11 19:12:33 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.409 2024/09/16 20:28:22 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -226,6 +226,17 @@ server_client_set_key_table(struct client *c, const char *name)
        key_bindings_unref_table(c->keytable);
        c->keytable = key_bindings_get_table(name, 1);
        c->keytable->references++;
+       if (gettimeofday(&c->keytable->activity_time, NULL) != 0)
+               fatal("gettimeofday failed");
+}
+
+static uint64_t
+server_client_key_table_activity_diff(struct client *c)
+{
+       struct timeval  diff;
+
+       timersub(&c->activity_time, &c->keytable->activity_time, &diff);
+       return ((diff.tv_sec * 1000ULL) + (diff.tv_usec / 1000ULL));
 }
 
 /* Get default key table. */
@@ -1870,7 +1881,7 @@ server_client_key_callback(struct cmdq_item *item, void *data)
        struct key_table                *table, *first;
        struct key_binding              *bd;
        int                              xtimeout;
-       uint64_t                         flags;
+       uint64_t                         flags, prefix_delay;
        struct cmd_find_state            fs;
        key_code                         key0, prefix, prefix2;
 
@@ -1965,8 +1976,34 @@ try_again:
        if (c->flags & CLIENT_REPEAT)
                log_debug("currently repeating");
 
-       /* Try to see if there is a key binding in the current table. */
        bd = key_bindings_get(table, key0);
+
+       /*
+        * If prefix-timeout is enabled and we're in the prefix table, see if
+        * the timeout has been exceeded. Revert to the root table if so.
+        */
+       prefix_delay = options_get_number(global_options, "prefix-timeout");
+       if (prefix_delay > 0 &&
+           strcmp(table->name, "prefix") == 0 &&
+           server_client_key_table_activity_diff(c) > prefix_delay) {
+               /*
+                * If repeating is active and this is a repeating binding,
+                * ignore the timeout.
+                */
+               if (bd != NULL &&
+                   (c->flags & CLIENT_REPEAT) &&
+                   (bd->flags & KEY_BINDING_REPEAT)) {
+                       log_debug("prefix timeout ignored, repeat is active");
+               } else {
+                       log_debug("prefix timeout exceeded");
+                       server_client_set_key_table(c, NULL);
+                       first = table = c->keytable;
+                       server_status_client(c);
+                       goto table_changed;
+               }
+       }
+
+       /* Try to see if there is a key binding in the current table. */
        if (bd != NULL) {
                /*
                 * Key was matched in this table. If currently repeating but a
index 9165234..c8a7d8b 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.954 2024/08/27 07:49:07 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.955 2024/09/16 20:28:22 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -14,7 +14,7 @@
 .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: August 27 2024 $
+.Dd $Mdocdate: September 16 2024 $
 .Dt TMUX 1
 .Os
 .Sh NAME
@@ -4228,6 +4228,13 @@ Like
 .Ic prefix2
 can be set to
 .Ql None .
+.It Ic prefix-timeout Ar time
+Set the time in milliseconds for which
+.Nm
+waits after
+.Ic prefix
+is input before dismissing it.
+Can be set to zero to disable any timeout.
 .It Xo Ic renumber-windows
 .Op Ic on | off
 .Xc
index 99f5343..f6bfb91 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1226 2024/08/27 07:49:07 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1227 2024/09/16 20:28:22 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1982,6 +1982,7 @@ RB_HEAD(key_bindings, key_binding);
 
 struct key_table {
        const char              *name;
+       struct timeval           activity_time;
        struct key_bindings      key_bindings;
        struct key_bindings      default_key_bindings;