mirror of
https://github.com/tmate-io/tmate.git
synced 2024-11-23 00:23:08 +01:00
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:
parent
6fab9a3e6f
commit
96dd3e8eb9
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
41
options.c
41
options.c
@ -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);
|
||||||
|
}
|
||||||
|
22
server.c
22
server.c
@ -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
8
tmux.1
@ -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
7
tmux.c
@ -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
14
tmux.h
@ -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 *);
|
||||||
|
Loading…
Reference in New Issue
Block a user