From df7b68480cf37f4039a5fd1809fd7c8dbf127277 Mon Sep 17 00:00:00 2001 From: Tiago Cunha Date: Tue, 22 Sep 2009 14:22:21 +0000 Subject: [PATCH] Sync OpenBSD patchset 343: Permit multiple prefix keys to be defined, separated by commas, for example: set -g prefix ^a,^b Any key in the list acts as the prefix. The send-prefix command always sends the first key in the list. --- cmd-send-prefix.c | 8 ++++---- cmd-set-option.c | 8 ++++---- cmd-set-window-option.c | 6 +++--- options-cmd.c | 41 ++++++++++++++++++++++++++++----------- options.c | 43 ++++++++++++++++++++++++++++++++++++++++- server.c | 24 ++++++++++++++++------- tmux.1 | 12 ++++++++---- tmux.c | 9 +++++++-- tmux.h | 16 ++++++++++++--- 9 files changed, 128 insertions(+), 39 deletions(-) diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c index 4620e123..34f4b7c9 100644 --- a/cmd-send-prefix.c +++ b/cmd-send-prefix.c @@ -1,4 +1,4 @@ -/* $Id: cmd-send-prefix.c,v 1.26 2009-08-20 11:37:46 tcunha Exp $ */ +/* $Id: cmd-send-prefix.c,v 1.27 2009-09-22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -43,13 +43,13 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx) struct cmd_target_data *data = self->data; struct session *s; struct window_pane *wp; - int key; + struct keylist *keylist; if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) return (-1); - key = options_get_number(&s->options, "prefix"); - window_pane_key(wp, ctx->curclient, key); + keylist = options_get_data(&s->options, "prefix"); + window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist)); return (0); } diff --git a/cmd-set-option.c b/cmd-set-option.c index 283f3692..32a913aa 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -1,4 +1,4 @@ -/* $Id: cmd-set-option.c,v 1.79 2009-09-19 18:53:01 tcunha Exp $ */ +/* $Id: cmd-set-option.c,v 1.80 2009-09-22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -65,7 +65,7 @@ const struct set_option_entry set_option_table[] = { { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, - { "prefix", SET_OPTION_KEY, 0, 0, NULL }, + { "prefix", SET_OPTION_KEYS, 0, 0, NULL }, { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "set-titles", SET_OPTION_FLAG, 0, 0, NULL }, @@ -162,8 +162,8 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->arg2); break; - case SET_OPTION_KEY: - set_option_key(ctx, oo, entry, data->arg2); + case SET_OPTION_KEYS: + set_option_keys(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: set_option_colour(ctx, oo, entry, data->arg2); diff --git a/cmd-set-window-option.c b/cmd-set-window-option.c index 8e9c88fe..c683aa9f 100644 --- a/cmd-set-window-option.c +++ b/cmd-set-window-option.c @@ -1,4 +1,4 @@ -/* $Id: cmd-set-window-option.c,v 1.38 2009-08-11 14:42:59 nicm Exp $ */ +/* $Id: cmd-set-window-option.c,v 1.39 2009-09-22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -140,8 +140,8 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx) case SET_OPTION_NUMBER: set_option_number(ctx, oo, entry, data->arg2); break; - case SET_OPTION_KEY: - set_option_key(ctx, oo, entry, data->arg2); + case SET_OPTION_KEYS: + set_option_keys(ctx, oo, entry, data->arg2); break; case SET_OPTION_COLOUR: set_option_colour(ctx, oo, entry, data->arg2); diff --git a/options-cmd.c b/options-cmd.c index bc978611..815c2e63 100644 --- a/options-cmd.c +++ b/options-cmd.c @@ -1,4 +1,4 @@ -/* $Id: options-cmd.c,v 1.7 2009-09-22 13:59:46 tcunha Exp $ */ +/* $Id: options-cmd.c,v 1.8 2009-09-22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -28,6 +28,8 @@ set_option_print(const struct set_option_entry *entry, struct options_entry *o) { static char out[BUFSIZ]; const char *s; + struct keylist *keylist; + u_int i; *out = '\0'; switch (entry->type) { @@ -37,9 +39,14 @@ set_option_print(const struct set_option_entry *entry, struct options_entry *o) case SET_OPTION_NUMBER: xsnprintf(out, sizeof out, "%lld", o->num); break; - case SET_OPTION_KEY: - s = key_string_lookup_key(o->num); - xsnprintf(out, sizeof out, "%s", s); + case SET_OPTION_KEYS: + keylist = o->data; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + strlcat(out, key_string_lookup_key( + ARRAY_ITEM(keylist, i)), sizeof out); + if (i != ARRAY_LENGTH(keylist) - 1) + strlcat(out, ",", sizeof out); + } break; case SET_OPTION_COLOUR: s = colour_tostring(o->num); @@ -114,23 +121,35 @@ set_option_number(struct cmd_ctx *ctx, struct options *oo, } void -set_option_key(struct cmd_ctx *ctx, struct options *oo, +set_option_keys(struct cmd_ctx *ctx, struct options *oo, const struct set_option_entry *entry, char *value) { struct options_entry *o; - int key; + struct keylist *keylist; + char *copyvalue, *ptr, *str; + int key; if (value == NULL) { ctx->error(ctx, "empty value"); return; } - if ((key = key_string_lookup_string(value)) == KEYC_NONE) { - ctx->error(ctx, "unknown key: %s", value); - return; - } + keylist = xmalloc(sizeof *keylist); + ARRAY_INIT(keylist); - o = options_set_number(oo, entry->name, key); + ptr = copyvalue = xstrdup(value); + while ((str = strsep(&ptr, ",")) != NULL) { + if ((key = key_string_lookup_string(str)) == KEYC_NONE) { + xfree(keylist); + ctx->error(ctx, "unknown key: %s", str); + xfree(copyvalue); + return; + } + ARRAY_ADD(keylist, key); + } + xfree(copyvalue); + + o = options_set_data(oo, entry->name, keylist, xfree); ctx->info( ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); } diff --git a/options.c b/options.c index 78a11ae8..9e870370 100644 --- a/options.c +++ b/options.c @@ -1,4 +1,4 @@ -/* $Id: options.c,v 1.8 2009-09-22 13:59:46 tcunha Exp $ */ +/* $Id: options.c,v 1.9 2009-09-22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -54,6 +54,8 @@ options_free(struct options *oo) xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); xfree(o); } } @@ -95,6 +97,8 @@ options_remove(struct options *oo, const char *name) xfree(o->name); if (o->type == OPTIONS_STRING) xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); xfree(o); } @@ -110,6 +114,8 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...) SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); va_start(ap, fmt); o->type = OPTIONS_STRING; @@ -141,6 +147,8 @@ options_set_number(struct options *oo, const char *name, long long value) SPLAY_INSERT(options_tree, &oo->tree, o); } else if (o->type == OPTIONS_STRING) xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); o->type = OPTIONS_NUMBER; o->num = value; @@ -158,3 +166,36 @@ options_get_number(struct options *oo, const char *name) fatalx("option not a number"); return (o->num); } + +struct options_entry * +options_set_data( + struct options *oo, const char *name, void *value, void (*freefn)(void *)) +{ + struct options_entry *o; + + if ((o = options_find1(oo, name)) == NULL) { + o = xmalloc(sizeof *o); + o->name = xstrdup(name); + SPLAY_INSERT(options_tree, &oo->tree, o); + } else if (o->type == OPTIONS_STRING) + xfree(o->str); + else if (o->type == OPTIONS_DATA) + o->freefn(o->data); + + o->type = OPTIONS_DATA; + o->data = value; + o->freefn = freefn; + return (o); +} + +void * +options_get_data(struct options *oo, const char *name) +{ + struct options_entry *o; + + if ((o = options_find(oo, name)) == NULL) + fatalx("missing option"); + if (o->type != OPTIONS_DATA) + fatalx("option not data"); + return (o->data); +} diff --git a/server.c b/server.c index bdb8adde..7de0b0e1 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.190 2009-09-20 22:11:27 tcunha Exp $ */ +/* $Id: server.c,v 1.191 2009-09-22 14:22:20 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -801,8 +801,9 @@ server_handle_client(struct client *c) struct screen *s; struct timeval tv; struct key_binding *bd; - int key, prefix, status, xtimeout; - int mode; + struct keylist *keylist; + int key, status, xtimeout, mode, isprefix; + u_int i; u_char mouse[3]; xtimeout = options_get_number(&c->session->options, "repeat-time"); @@ -814,7 +815,7 @@ server_handle_client(struct client *c) } /* Process keys. */ - prefix = options_get_number(&c->session->options, "prefix"); + keylist = options_get_data(&c->session->options, "prefix"); while (tty_keys_next(&c->tty, &key, mouse) == 0) { server_activity = time(NULL); @@ -847,9 +848,18 @@ server_handle_client(struct client *c) continue; } + /* Is this a prefix key? */ + isprefix = 0; + for (i = 0; i < ARRAY_LENGTH(keylist); i++) { + if (key == ARRAY_ITEM(keylist, i)) { + isprefix = 1; + break; + } + } + /* No previous prefix key. */ if (!(c->flags & CLIENT_PREFIX)) { - if (key == prefix) + if (isprefix) c->flags |= CLIENT_PREFIX; else { /* Try as a non-prefix key binding. */ @@ -867,7 +877,7 @@ server_handle_client(struct client *c) /* If repeating, treat this as a key, else ignore. */ if (c->flags & CLIENT_REPEAT) { c->flags &= ~CLIENT_REPEAT; - if (key == prefix) + if (isprefix) c->flags |= CLIENT_PREFIX; else window_pane_key(wp, c, key); @@ -878,7 +888,7 @@ server_handle_client(struct client *c) /* If already repeating, but this key can't repeat, skip it. */ if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { c->flags &= ~CLIENT_REPEAT; - if (key == prefix) + if (isprefix) c->flags |= CLIENT_PREFIX; else window_pane_key(wp, c, key); diff --git a/tmux.1 b/tmux.1 index a5abcba1..a7acdbe9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.170 2009-09-22 13:51:24 tcunha Exp $ +.\" $Id: tmux.1,v 1.171 2009-09-22 14:22:20 tcunha Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -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: September 21 2009 $ +.Dd $Mdocdate: September 22 2009 $ .Dt TMUX 1 .Os .Sh NAME @@ -1048,6 +1048,7 @@ characters. All arguments are sent sequentially from first to last. .It Ic send-prefix Op Fl t Ar target-pane Send the prefix key to a window as if it was pressed. +If multiple prefix keys are configured, only the first is sent. .It Xo Ic unbind-key .Op Fl cn .Op Fl t Ar key-table @@ -1258,8 +1259,11 @@ from the 256-colour palette, or .Ic default . .It Ic message-fg Ar colour Set status line message foreground colour. -.It Ic prefix Ar key -Set the current prefix key. +.It Ic prefix Ar keys +Set the keys accepted as a prefix key. +.Ar keys +is a comma-separated list of key names, each of which individually behave as +the prefix key. .It Ic repeat-time Ar time Allow multiple commands to be entered without pressing the prefix-key again in the specified diff --git a/tmux.c b/tmux.c index 3e9affc1..1a4a01c9 100644 --- a/tmux.c +++ b/tmux.c @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.172 2009-09-19 18:53:01 tcunha Exp $ */ +/* $Id: tmux.c,v 1.173 2009-09-22 14:22:21 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -318,6 +318,7 @@ main(int argc, char **argv) enum msgtype msg; struct passwd *pw; struct options *so, *wo; + struct keylist *keylist; char *s, *path, *label, *home, *cause, **var; char cwd[MAXPATHLEN]; void *buf; @@ -418,7 +419,6 @@ main(int argc, char **argv) options_set_number(so, "message-attr", 0); options_set_number(so, "message-bg", 3); options_set_number(so, "message-fg", 0); - options_set_number(so, "prefix", '\002'); options_set_number(so, "repeat-time", 500); options_set_number(so, "set-remain-on-exit", 0); options_set_number(so, "set-titles", 0); @@ -448,6 +448,11 @@ main(int argc, char **argv) options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-content", 0); + keylist = xmalloc(sizeof *keylist); + ARRAY_INIT(keylist); + ARRAY_ADD(keylist, '\002'); + options_set_data(so, "prefix", keylist, xfree); + options_init(&global_w_options, NULL); wo = &global_w_options; options_set_number(wo, "aggressive-resize", 0); diff --git a/tmux.h b/tmux.h index 9dc346c8..e709a30b 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.449 2009-09-22 13:59:46 tcunha Exp $ */ +/* $Id: tmux.h,v 1.450 2009-09-22 14:22:21 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -542,10 +542,14 @@ struct options_entry { enum { OPTIONS_STRING, OPTIONS_NUMBER, + OPTIONS_DATA, } type; char *str; long long num; + void *data; + + void (*freefn)(void *); SPLAY_ENTRY(options_entry) entry; }; @@ -555,6 +559,9 @@ struct options { struct options *parent; }; +/* Key list for prefix option. */ +ARRAY_DECL(keylist, int); + /* Screen selection. */ struct screen_sel { int flag; @@ -1083,7 +1090,7 @@ struct set_option_entry { enum { SET_OPTION_STRING, SET_OPTION_NUMBER, - SET_OPTION_KEY, + SET_OPTION_KEYS, SET_OPTION_COLOUR, SET_OPTION_ATTRIBUTES, SET_OPTION_FLAG, @@ -1163,6 +1170,9 @@ char *options_get_string(struct options *, const char *); struct options_entry *options_set_number( struct options *, const char *, long long); long long options_get_number(struct options *, const char *); +struct options_entry *options_set_data( + struct options *, const char *, void *, void (*)(void *)); +void *options_get_data(struct options *, const char *); /* environ.c */ int environ_cmp(struct environ_entry *, struct environ_entry *); @@ -1243,7 +1253,7 @@ void set_option_string(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *, int); void set_option_number(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); -void set_option_key(struct cmd_ctx *, +void set_option_keys(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *); void set_option_colour(struct cmd_ctx *, struct options *, const struct set_option_entry *, char *);