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.
This commit is contained in:
Nicholas Marriott 2009-09-22 12:38:10 +00:00
parent 6fab9a3e6f
commit 96dd3e8eb9
9 changed files with 118 additions and 29 deletions

View File

@ -43,13 +43,13 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data; struct cmd_target_data *data = self->data;
struct session *s; struct session *s;
struct window_pane *wp; struct window_pane *wp;
int key; struct keylist *keylist;
if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL) if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
return (-1); return (-1);
key = options_get_number(&s->options, "prefix"); keylist = options_get_data(&s->options, "prefix");
window_pane_key(wp, ctx->curclient, key); window_pane_key(wp, ctx->curclient, ARRAY_FIRST(keylist));
return (0); return (0);
} }

View File

@ -65,7 +65,7 @@ const struct set_option_entry set_option_table[] = {
{ "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, { "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL },
{ "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, { "message-bg", SET_OPTION_COLOUR, 0, 0, NULL },
{ "message-fg", 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 }, { "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL }, { "set-remain-on-exit", SET_OPTION_FLAG, 0, 0, NULL },
{ "set-titles", 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: case SET_OPTION_NUMBER:
set_option_number(ctx, oo, entry, data->arg2); set_option_number(ctx, oo, entry, data->arg2);
break; break;
case SET_OPTION_KEY: case SET_OPTION_KEYS:
set_option_key(ctx, oo, entry, data->arg2); set_option_keys(ctx, oo, entry, data->arg2);
break; break;
case SET_OPTION_COLOUR: case SET_OPTION_COLOUR:
set_option_colour(ctx, oo, entry, data->arg2); set_option_colour(ctx, oo, entry, data->arg2);

View File

@ -140,8 +140,8 @@ cmd_set_window_option_exec(struct cmd *self, struct cmd_ctx *ctx)
case SET_OPTION_NUMBER: case SET_OPTION_NUMBER:
set_option_number(ctx, oo, entry, data->arg2); set_option_number(ctx, oo, entry, data->arg2);
break; break;
case SET_OPTION_KEY: case SET_OPTION_KEYS:
set_option_key(ctx, oo, entry, data->arg2); set_option_keys(ctx, oo, entry, data->arg2);
break; break;
case SET_OPTION_COLOUR: case SET_OPTION_COLOUR:
set_option_colour(ctx, oo, entry, data->arg2); set_option_colour(ctx, oo, entry, data->arg2);

View File

@ -28,6 +28,8 @@ set_option_print(const struct set_option_entry *entry, struct options_entry *o)
{ {
static char out[BUFSIZ]; static char out[BUFSIZ];
const char *s; const char *s;
struct keylist *keylist;
u_int i;
*out = '\0'; *out = '\0';
switch (entry->type) { switch (entry->type) {
@ -37,9 +39,14 @@ set_option_print(const struct set_option_entry *entry, struct options_entry *o)
case SET_OPTION_NUMBER: case SET_OPTION_NUMBER:
xsnprintf(out, sizeof out, "%lld", o->num); xsnprintf(out, sizeof out, "%lld", o->num);
break; break;
case SET_OPTION_KEY: case SET_OPTION_KEYS:
s = key_string_lookup_key(o->num); keylist = o->data;
xsnprintf(out, sizeof out, "%s", s); 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; break;
case SET_OPTION_COLOUR: case SET_OPTION_COLOUR:
s = colour_tostring(o->num); s = colour_tostring(o->num);
@ -114,23 +121,35 @@ set_option_number(struct cmd_ctx *ctx, struct options *oo,
} }
void 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) const struct set_option_entry *entry, char *value)
{ {
struct options_entry *o; struct options_entry *o;
int key; struct keylist *keylist;
char *copyvalue, *ptr, *str;
int key;
if (value == NULL) { if (value == NULL) {
ctx->error(ctx, "empty value"); ctx->error(ctx, "empty value");
return; return;
} }
if ((key = key_string_lookup_string(value)) == KEYC_NONE) { keylist = xmalloc(sizeof *keylist);
ctx->error(ctx, "unknown key: %s", value); ARRAY_INIT(keylist);
return;
}
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->info(
ctx, "set option: %s -> %s", o->name, set_option_print(entry, o)); ctx, "set option: %s -> %s", o->name, set_option_print(entry, o));
} }

View File

@ -54,6 +54,8 @@ options_free(struct options *oo)
xfree(o->name); xfree(o->name);
if (o->type == OPTIONS_STRING) if (o->type == OPTIONS_STRING)
xfree(o->str); xfree(o->str);
else if (o->type == OPTIONS_DATA)
o->freefn(o->data);
xfree(o); xfree(o);
} }
} }
@ -95,6 +97,8 @@ options_remove(struct options *oo, const char *name)
xfree(o->name); xfree(o->name);
if (o->type == OPTIONS_STRING) if (o->type == OPTIONS_STRING)
xfree(o->str); xfree(o->str);
else if (o->type == OPTIONS_DATA)
o->freefn(o->data);
xfree(o); 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); SPLAY_INSERT(options_tree, &oo->tree, o);
} else if (o->type == OPTIONS_STRING) } else if (o->type == OPTIONS_STRING)
xfree(o->str); xfree(o->str);
else if (o->type == OPTIONS_DATA)
o->freefn(o->data);
va_start(ap, fmt); va_start(ap, fmt);
o->type = OPTIONS_STRING; 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); SPLAY_INSERT(options_tree, &oo->tree, o);
} else if (o->type == OPTIONS_STRING) } else if (o->type == OPTIONS_STRING)
xfree(o->str); xfree(o->str);
else if (o->type == OPTIONS_DATA)
o->freefn(o->data);
o->type = OPTIONS_NUMBER; o->type = OPTIONS_NUMBER;
o->num = value; o->num = value;
@ -158,3 +166,36 @@ options_get_number(struct options *oo, const char *name)
fatalx("option not a number"); fatalx("option not a number");
return (o->num); 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);
}

View File

@ -798,8 +798,9 @@ server_handle_client(struct client *c)
struct screen *s; struct screen *s;
struct timeval tv; struct timeval tv;
struct key_binding *bd; struct key_binding *bd;
int key, prefix, status, xtimeout; struct keylist *keylist;
int mode; int key, status, xtimeout, mode, isprefix;
u_int i;
u_char mouse[3]; u_char mouse[3];
xtimeout = options_get_number(&c->session->options, "repeat-time"); xtimeout = options_get_number(&c->session->options, "repeat-time");
@ -811,7 +812,7 @@ server_handle_client(struct client *c)
} }
/* Process keys. */ /* 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) { while (tty_keys_next(&c->tty, &key, mouse) == 0) {
server_activity = time(NULL); server_activity = time(NULL);
@ -844,9 +845,18 @@ server_handle_client(struct client *c)
continue; 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. */ /* No previous prefix key. */
if (!(c->flags & CLIENT_PREFIX)) { if (!(c->flags & CLIENT_PREFIX)) {
if (key == prefix) if (isprefix)
c->flags |= CLIENT_PREFIX; c->flags |= CLIENT_PREFIX;
else { else {
/* Try as a non-prefix key binding. */ /* Try as a non-prefix key binding. */
@ -864,7 +874,7 @@ server_handle_client(struct client *c)
/* If repeating, treat this as a key, else ignore. */ /* If repeating, treat this as a key, else ignore. */
if (c->flags & CLIENT_REPEAT) { if (c->flags & CLIENT_REPEAT) {
c->flags &= ~CLIENT_REPEAT; c->flags &= ~CLIENT_REPEAT;
if (key == prefix) if (isprefix)
c->flags |= CLIENT_PREFIX; c->flags |= CLIENT_PREFIX;
else else
window_pane_key(wp, c, key); window_pane_key(wp, c, key);
@ -875,7 +885,7 @@ server_handle_client(struct client *c)
/* If already repeating, but this key can't repeat, skip it. */ /* If already repeating, but this key can't repeat, skip it. */
if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
c->flags &= ~CLIENT_REPEAT; c->flags &= ~CLIENT_REPEAT;
if (key == prefix) if (isprefix)
c->flags |= CLIENT_PREFIX; c->flags |= CLIENT_PREFIX;
else else
window_pane_key(wp, c, key); window_pane_key(wp, c, key);

8
tmux.1
View File

@ -1048,6 +1048,7 @@ characters.
All arguments are sent sequentially from first to last. All arguments are sent sequentially from first to last.
.It Ic send-prefix Op Fl t Ar target-pane .It Ic send-prefix Op Fl t Ar target-pane
Send the prefix key to a window as if it was pressed. 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 .It Xo Ic unbind-key
.Op Fl cn .Op Fl cn
.Op Fl t Ar key-table .Op Fl t Ar key-table
@ -1258,8 +1259,11 @@ from the 256-colour palette, or
.Ic default . .Ic default .
.It Ic message-fg Ar colour .It Ic message-fg Ar colour
Set status line message foreground colour. Set status line message foreground colour.
.It Ic prefix Ar key .It Ic prefix Ar keys
Set the current prefix key. 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 .It Ic repeat-time Ar time
Allow multiple commands to be entered without pressing the prefix-key again Allow multiple commands to be entered without pressing the prefix-key again
in the specified in the specified

7
tmux.c
View File

@ -309,6 +309,7 @@ main(int argc, char **argv)
enum msgtype msg; enum msgtype msg;
struct passwd *pw; struct passwd *pw;
struct options *so, *wo; struct options *so, *wo;
struct keylist *keylist;
char *s, *path, *label, *home, *cause, **var; char *s, *path, *label, *home, *cause, **var;
char cwd[MAXPATHLEN]; char cwd[MAXPATHLEN];
void *buf; void *buf;
@ -409,7 +410,6 @@ main(int argc, char **argv)
options_set_number(so, "message-attr", 0); options_set_number(so, "message-attr", 0);
options_set_number(so, "message-bg", 3); options_set_number(so, "message-bg", 3);
options_set_number(so, "message-fg", 0); options_set_number(so, "message-fg", 0);
options_set_number(so, "prefix", '\002');
options_set_number(so, "repeat-time", 500); options_set_number(so, "repeat-time", 500);
options_set_number(so, "set-remain-on-exit", 0); options_set_number(so, "set-remain-on-exit", 0);
options_set_number(so, "set-titles", 0); options_set_number(so, "set-titles", 0);
@ -439,6 +439,11 @@ main(int argc, char **argv)
options_set_number(so, "visual-bell", 0); options_set_number(so, "visual-bell", 0);
options_set_number(so, "visual-content", 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); options_init(&global_w_options, NULL);
wo = &global_w_options; wo = &global_w_options;
options_set_number(wo, "aggressive-resize", 0); options_set_number(wo, "aggressive-resize", 0);

14
tmux.h
View File

@ -544,10 +544,14 @@ struct options_entry {
enum { enum {
OPTIONS_STRING, OPTIONS_STRING,
OPTIONS_NUMBER, OPTIONS_NUMBER,
OPTIONS_DATA,
} type; } type;
char *str; char *str;
long long num; long long num;
void *data;
void (*freefn)(void *);
SPLAY_ENTRY(options_entry) entry; SPLAY_ENTRY(options_entry) entry;
}; };
@ -557,6 +561,9 @@ struct options {
struct options *parent; struct options *parent;
}; };
/* Key list for prefix option. */
ARRAY_DECL(keylist, int);
/* Screen selection. */ /* Screen selection. */
struct screen_sel { struct screen_sel {
int flag; int flag;
@ -1085,7 +1092,7 @@ struct set_option_entry {
enum { enum {
SET_OPTION_STRING, SET_OPTION_STRING,
SET_OPTION_NUMBER, SET_OPTION_NUMBER,
SET_OPTION_KEY, SET_OPTION_KEYS,
SET_OPTION_COLOUR, SET_OPTION_COLOUR,
SET_OPTION_ATTRIBUTES, SET_OPTION_ATTRIBUTES,
SET_OPTION_FLAG, SET_OPTION_FLAG,
@ -1165,6 +1172,9 @@ char *options_get_string(struct options *, const char *);
struct options_entry *options_set_number( struct options_entry *options_set_number(
struct options *, const char *, long long); struct options *, const char *, long long);
long long options_get_number(struct options *, const char *); 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 */ /* environ.c */
int environ_cmp(struct environ_entry *, struct environ_entry *); int environ_cmp(struct environ_entry *, struct environ_entry *);
@ -1245,7 +1255,7 @@ void set_option_string(struct cmd_ctx *,
struct options *, const struct set_option_entry *, char *, int); struct options *, const struct set_option_entry *, char *, int);
void set_option_number(struct cmd_ctx *, void set_option_number(struct cmd_ctx *,
struct options *, const struct set_option_entry *, char *); 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 *); struct options *, const struct set_option_entry *, char *);
void set_option_colour(struct cmd_ctx *, void set_option_colour(struct cmd_ctx *,
struct options *, const struct set_option_entry *, char *); struct options *, const struct set_option_entry *, char *);