Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2015-04-22 10:05:54 +01:00
commit 0a88377086
21 changed files with 477 additions and 245 deletions

View File

@ -261,8 +261,13 @@ client_main(int argc, char **argv, int flags)
/* Initialize the client socket and start the server. */
fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
if (fd == -1) {
fprintf(stderr, "failed to connect to server: %s\n",
strerror(errno));
if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n",
socket_path);
} else {
fprintf(stderr, "error connecting to %s (%s)\n",
socket_path, strerror(errno));
}
return (1);
}

View File

@ -33,8 +33,8 @@ enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *, int);
const struct cmd_entry cmd_bind_key_entry = {
"bind-key", "bind",
"cnrt:", 1, -1,
"[-cnr] [-t mode-table] key command [arguments]",
"cnrt:T:", 1, -1,
"[-cnr] [-t mode-table] [-T key-table] key command [arguments]",
0,
cmd_bind_key_exec
};
@ -46,6 +46,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
char *cause;
struct cmd_list *cmdlist;
int key;
const char *tablename;
if (args_has(args, 't')) {
if (args->argc != 2 && args->argc != 3) {
@ -68,6 +69,13 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 't'))
return (cmd_bind_key_mode_table(self, cmdq, key));
if (args_has(args, 'T'))
tablename = args_get(args, 'T');
else if (args_has(args, 'n'))
tablename = "root";
else
tablename = "prefix";
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
&cause);
if (cmdlist == NULL) {
@ -76,9 +84,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
}
if (!args_has(args, 'n'))
key |= KEYC_PREFIX;
key_bindings_add(key, args_has(args, 'r'), cmdlist);
key_bindings_add(tablename, key, args_has(args, 'r'), cmdlist);
return (CMD_RETURN_NORMAL);
}

View File

@ -68,8 +68,11 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
window_copy_init_from_pane(wp);
}
if (args_has(args, 'M'))
if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &cmdq->item->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp);

View File

@ -44,11 +44,14 @@ const struct cmd_entry cmd_if_shell_entry = {
};
struct cmd_if_shell_data {
char *cmd_if;
char *cmd_else;
struct cmd_q *cmdq;
int bflag;
int started;
char *cmd_if;
char *cmd_else;
struct cmd_q *cmdq;
struct mouse_event mouse;
int bflag;
int references;
};
enum cmd_retval
@ -95,23 +98,26 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
}
return (CMD_RETURN_ERROR);
}
cmdq_run(cmdq, cmdlist, NULL);
cmdq_run(cmdq, cmdlist, &cmdq->item->mouse);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}
cdata = xmalloc(sizeof *cdata);
cdata->cmd_if = xstrdup(args->argv[1]);
if (args->argc == 3)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
cdata->bflag = args_has(args, 'b');
cdata->started = 0;
cdata->cmdq = cmdq;
memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
cmdq->references++;
cdata->references = 1;
job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata);
free(shellcmd);
@ -146,13 +152,12 @@ cmd_if_shell_callback(struct job *job)
return;
}
cdata->started = 1;
cmdq1 = cmdq_new(cmdq->client);
cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata;
cmdq_run(cmdq1, cmdlist, NULL);
cdata->references++;
cmdq_run(cmdq1, cmdlist, &cdata->mouse);
cmd_list_free(cmdlist);
}
@ -164,12 +169,14 @@ cmd_if_shell_done(struct cmd_q *cmdq1)
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
cmdq_free(cmdq1);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata);
@ -181,7 +188,7 @@ cmd_if_shell_free(void *data)
struct cmd_if_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq;
if (cdata->started)
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag)

View File

@ -33,8 +33,8 @@ enum cmd_retval cmd_list_keys_commands(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_keys_entry = {
"list-keys", "lsk",
"t:", 0, 0,
"[-t key-table]",
"t:T:", 0, 0,
"[-t mode-table] [-T key-table]",
0,
cmd_list_keys_exec
};
@ -51,11 +51,12 @@ enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct key_table *table;
struct key_binding *bd;
const char *key;
char tmp[BUFSIZ], flags[8];
const char *key, *tablename, *r;
char tmp[BUFSIZ];
size_t used;
int width, keywidth;
int repeat, width, tablewidth, keywidth;
if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, cmdq));
@ -63,46 +64,57 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 't'))
return (cmd_list_keys_table(self, cmdq));
width = 0;
RB_FOREACH(bd, key_bindings, &key_bindings) {
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
if (key == NULL)
continue;
keywidth = strlen(key);
if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat)
keywidth += 4;
else
keywidth += 3;
} else if (bd->can_repeat)
keywidth += 3;
if (keywidth > width)
width = keywidth;
tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
RB_FOREACH(bd, key_bindings, &key_bindings) {
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
if (key == NULL)
repeat = 0;
tablewidth = keywidth = 0;
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
if (key == NULL)
continue;
*flags = '\0';
if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat)
xsnprintf(flags, sizeof flags, "-rn ");
else
xsnprintf(flags, sizeof flags, "-n ");
} else if (bd->can_repeat)
xsnprintf(flags, sizeof flags, "-r ");
repeat = 1;
used = xsnprintf(tmp, sizeof tmp, "%s%*s ",
flags, (int) (width - strlen(flags)), key);
if (used >= sizeof tmp)
width = strlen(table->name);
if (width > tablewidth)
tablewidth =width;
width = strlen(key);
if (width > keywidth)
keywidth = width;
}
}
RB_FOREACH(table, key_tables, &key_tables) {
if (tablename != NULL && strcmp(table->name, tablename) != 0)
continue;
RB_FOREACH(bd, key_bindings, &table->key_bindings) {
key = key_string_lookup_key(bd->key);
if (key == NULL)
continue;
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
cmdq_print(cmdq, "bind-key %s", tmp);
if (!repeat)
r = "";
else if (bd->can_repeat)
r = "-r ";
else
r = " ";
used = xsnprintf(tmp, sizeof tmp, "%s-T %-*s %-*s ", r,
(int)tablewidth, table->name, (int)keywidth, key);
if (used < sizeof tmp) {
cmd_list_print(bd->cmdlist, tmp + used,
(sizeof tmp) - used);
}
cmdq_print(cmdq, "bind-key %s", tmp);
}
}
return (CMD_RETURN_NORMAL);

View File

@ -51,7 +51,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct session *src, *dst, *s;
struct winlink *wl;
char *cause;
int idx, kflag, dflag;
int idx, kflag, dflag, sflag;
if (args_has(args, 'r')) {
s = cmd_find_session(cmdq, args_get(args, 't'), 0);
@ -71,6 +71,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
sflag = args_has(self->args, 's');
if (server_link_window(src, wl, dst, idx, kflag, !dflag,
&cause) != 0) {
cmdq_error(cmdq, "can't link window: %s", cause);
@ -79,6 +80,15 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
}
if (self->entry == &cmd_move_window_entry)
server_unlink_window(src, wl);
/*
* Renumber the winlinks in the src session only, the destination
* session already has the correct winlink id to us, either
* automatically or specified by -s.
*/
if (!sflag && options_get_number(&src->options, "renumber-windows"))
session_renumber_windows(src);
recalculate_sizes();
return (CMD_RETURN_NORMAL);

View File

@ -31,8 +31,8 @@ enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc",
"lc:npt:r", 0, 0,
"[-lnpr] [-c target-client] [-t target-session]",
"lc:npt:rT:", 0, 0,
"[-lnpr] [-c target-client] [-t target-session] [-T key-table]",
CMD_READONLY,
cmd_switch_client_exec
};
@ -46,7 +46,8 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
struct winlink *wl = NULL;
struct window *w = NULL;
struct window_pane *wp = NULL;
const char *tflag;
const char *tflag, *tablename;
struct key_table *table;
if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
@ -58,6 +59,18 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
c->flags |= CLIENT_READONLY;
}
tablename = args_get(args, 'T');
if (tablename != NULL) {
table = key_bindings_get_table(tablename, 0);
if (table == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
table->references++;
key_bindings_unref_table(c->keytable);
c->keytable = table;
}
tflag = args_get(args, 't');
if (args_has(args, 'n')) {
if ((s = session_next_session(c->session)) == NULL) {

View File

@ -31,8 +31,8 @@ enum cmd_retval cmd_unbind_key_mode_table(struct cmd *, struct cmd_q *, int);
const struct cmd_entry cmd_unbind_key_entry = {
"unbind-key", "unbind",
"acnt:", 0, 1,
"[-acn] [-t mode-table] key",
"acnt:T:", 0, 1,
"[-acn] [-t mode-table] [-T key-table] key",
0,
cmd_unbind_key_exec
};
@ -40,9 +40,9 @@ const struct cmd_entry cmd_unbind_key_entry = {
enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct key_binding *bd;
int key;
struct args *args = self->args;
int key;
const char *tablename;
if (!args_has(args, 'a')) {
if (args->argc != 1) {
@ -66,16 +66,31 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
return (cmd_unbind_key_mode_table(self, cmdq, key));
if (key == KEYC_NONE) {
while (!RB_EMPTY(&key_bindings)) {
bd = RB_ROOT(&key_bindings);
key_bindings_remove(bd->key);
tablename = args_get(args, 'T');
if (tablename == NULL) {
key_bindings_remove_table("root");
key_bindings_remove_table("prefix");
return (CMD_RETURN_NORMAL);
}
if (key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
key_bindings_remove_table(tablename);
return (CMD_RETURN_NORMAL);
}
if (!args_has(args, 'n'))
key |= KEYC_PREFIX;
key_bindings_remove(key);
if (args_has(args, 'T')) {
tablename = args_get(args, 'T');
if (key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(cmdq, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'n'))
tablename = "root";
else
tablename = "prefix";
key_bindings_remove(tablename, key);
return (CMD_RETURN_NORMAL);
}

8
cmd.c
View File

@ -780,15 +780,15 @@ cmd_lookup_index(struct session *s, const char *name, int *ambiguous)
const char *errstr;
u_int idx;
idx = strtonum(name, 0, INT_MAX, &errstr);
if (errstr == NULL)
return (idx);
if ((wl = cmd_lookup_window(s, name, ambiguous)) != NULL)
return (wl->idx);
if (*ambiguous)
return (-1);
idx = strtonum(name, 0, INT_MAX, &errstr);
if (errstr == NULL)
return (idx);
return (-1);
}

View File

@ -546,7 +546,11 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_activity", "%lld", (long long) t);
format_add(ft, "client_activity_string", "%s", format_time_string(t));
format_add(ft, "client_prefix", "%d", !!(c->flags & CLIENT_PREFIX));
if (strcmp(c->keytable->name, "root") == 0)
format_add(ft, "client_prefix", "%d", 0);
else
format_add(ft, "client_prefix", "%d", 1);
format_add(ft, "client_key_table", "%s", c->keytable->name);
if (c->tty.flags & TTY_UTF8)
format_add(ft, "client_utf8", "%d", 1);
@ -574,7 +578,10 @@ format_defaults_window(struct format_tree *ft, struct window *w)
ft->w = w;
layout = layout_dump(w);
if (w->saved_layout_root != NULL)
layout = layout_dump(w->saved_layout_root);
else
layout = layout_dump(w->layout_root);
format_add(ft, "window_id", "@%u", w->id);
format_add(ft, "window_name", "%s", w->name);
@ -728,6 +735,8 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "wrap_flag", "%d",
!!(wp->base.mode & MODE_WRAP));
format_add(ft, "mouse_any_flag", "%d",
!!(wp->base.mode & (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON)));
format_add(ft, "mouse_standard_flag", "%d",
!!(wp->base.mode & MODE_MOUSE_STANDARD));
format_add(ft, "mouse_button_flag", "%d",

View File

@ -250,5 +250,6 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
buf[len++] = x + 33;
buf[len++] = y + 33;
}
log_debug("writing mouse %.*s", (int)len, buf);
bufferevent_write(wp->event, buf, len);
}

View File

@ -25,60 +25,120 @@
#include "tmux.h"
RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
RB_GENERATE(key_tables, key_table, entry, key_table_cmp);
struct key_tables key_tables = RB_INITIALIZER(&key_tables);
struct key_bindings key_bindings;
int
key_table_cmp(struct key_table *e1, struct key_table *e2)
{
return (strcmp(e1->name, e2->name));
}
int
key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
{
int key1, key2;
key1 = bd1->key & ~KEYC_PREFIX;
key2 = bd2->key & ~KEYC_PREFIX;
if (key1 != key2)
return (key1 - key2);
if (bd1->key & KEYC_PREFIX && !(bd2->key & KEYC_PREFIX))
return (-1);
if (bd2->key & KEYC_PREFIX && !(bd1->key & KEYC_PREFIX))
return (1);
return (0);
return (bd1->key - bd2->key);
}
struct key_binding *
key_bindings_lookup(int key)
struct key_table *
key_bindings_get_table(const char *name, int create)
{
struct key_binding bd;
struct key_table table_find, *table;
bd.key = key;
return (RB_FIND(key_bindings, &key_bindings, &bd));
table_find.name = name;
table = RB_FIND(key_tables, &key_tables, &table_find);
if (table != NULL || !create)
return (table);
table = xmalloc(sizeof *table);
table->name = xstrdup(name);
RB_INIT(&table->key_bindings);
table->references = 1; /* one reference in key_tables */
RB_INSERT(key_tables, &key_tables, table);
return (table);
}
void
key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist)
key_bindings_unref_table(struct key_table *table)
{
struct key_binding *bd;
key_bindings_remove(key);
if (--table->references != 0)
return;
while (!RB_EMPTY(&table->key_bindings)) {
bd = RB_ROOT(&table->key_bindings);
RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist);
free(bd);
}
free((void *)table->name);
free(table);
}
void
key_bindings_add(const char *name, int key, int can_repeat,
struct cmd_list *cmdlist)
{
struct key_table *table;
struct key_binding bd_find, *bd;
table = key_bindings_get_table(name, 1);
bd_find.key = key;
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) {
RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist);
free(bd);
}
bd = xmalloc(sizeof *bd);
bd->key = key;
RB_INSERT(key_bindings, &key_bindings, bd);
RB_INSERT(key_bindings, &table->key_bindings, bd);
bd->can_repeat = can_repeat;
bd->cmdlist = cmdlist;
}
void
key_bindings_remove(int key)
key_bindings_remove(const char *name, int key)
{
struct key_binding *bd;
struct key_table *table;
struct key_binding bd_find, *bd;
if ((bd = key_bindings_lookup(key)) == NULL)
table = key_bindings_get_table(name, 0);
if (table == NULL)
return;
RB_REMOVE(key_bindings, &key_bindings, bd);
bd_find.key = key;
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd == NULL)
return;
RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist);
free(bd);
if (RB_EMPTY(&table->key_bindings)) {
RB_REMOVE(key_tables, &key_tables, table);
key_bindings_unref_table(table);
}
}
void
key_bindings_remove_table(const char *name)
{
struct key_table *table;
table = key_bindings_get_table(name, 0);
if (table != NULL) {
RB_REMOVE(key_tables, &key_tables, table);
key_bindings_unref_table(table);
}
}
void
@ -161,7 +221,7 @@ key_bindings_init(void)
"bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
"bind -n MouseDrag1Border resize-pane -M",
"bind -n MouseDown1Status select-window -t=",
"bind -n MouseDrag1Pane copy-mode -M",
"bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'",
};
u_int i;
struct cmd_list *cmdlist;
@ -169,8 +229,6 @@ key_bindings_init(void)
int error;
struct cmd_q *cmdq;
RB_INIT(&key_bindings);
cmdq = cmdq_new(NULL);
for (i = 0; i < nitems(defaults); i++) {
error = cmd_string_parse(defaults[i], &cmdlist,

View File

@ -55,12 +55,12 @@ layout_checksum(const char *layout)
/* Dump layout as a string. */
char *
layout_dump(struct window *w)
layout_dump(struct layout_cell *root)
{
char layout[BUFSIZ], *out;
*layout = '\0';
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
if (layout_append(root, layout, sizeof layout) != 0)
return (NULL);
xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);

View File

@ -29,6 +29,7 @@
#include "tmux.h"
void server_client_key_table(struct client *, const char *);
void server_client_check_focus(struct window_pane *);
void server_client_check_resize(struct window_pane *);
int server_client_check_mouse(struct client *);
@ -44,6 +45,15 @@ void server_client_msg_command(struct client *, struct imsg *);
void server_client_msg_identify(struct client *, struct imsg *);
void server_client_msg_shell(struct client *);
/* Set client key table. */
void
server_client_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++;
}
/* Create a new client. */
void
server_client_create(int fd)
@ -92,6 +102,9 @@ server_client_create(int fd)
c->flags |= CLIENT_FOCUSED;
c->keytable = key_bindings_get_table("root", 1);
c->keytable->references++;
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@ -163,6 +176,8 @@ server_client_lost(struct client *c)
evtimer_del(&c->repeat_timer);
key_bindings_unref_table(c->keytable);
if (event_initialized(&c->identify_timer))
evtimer_del(&c->identify_timer);
@ -375,7 +390,7 @@ server_client_check_mouse(struct client *c)
c->tty.mouse_drag_release = NULL;
c->tty.mouse_drag_flag = 0;
return (KEYC_NONE);
return (KEYC_MOUSE); /* not a key, but still may want to pass */
}
/* Convert to a key binding. */
@ -526,16 +541,19 @@ void
server_client_handle_key(struct client *c, int key)
{
struct mouse_event *m = &c->tty.mouse;
struct session *s;
struct session *s = c->session;
struct window *w;
struct window_pane *wp;
struct timeval tv;
struct key_binding *bd;
int xtimeout, isprefix, ispaste;
struct key_table *table = c->keytable;
struct key_binding bd_find, *bd;
int xtimeout;
/* Check the client is good to accept input. */
if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
return;
w = s->curw->window;
wp = w->active;
/* No session, do nothing. */
if (c->session == NULL)
@ -551,7 +569,7 @@ server_client_handle_key(struct client *c, int key)
sizeof s->last_activity_time);
memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
/* Special case: number keys jump to pane in identify mode. */
/* Number keys jump to pane in identify mode. */
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
if (c->flags & CLIENT_READONLY)
return;
@ -592,74 +610,88 @@ server_client_handle_key(struct client *c, int key)
} else
m->valid = 0;
/* Is this a prefix key? */
if (key == options_get_number(&s->options, "prefix"))
isprefix = 1;
else if (key == options_get_number(&s->options, "prefix2"))
isprefix = 1;
else
isprefix = 0;
/* Treat prefix as a regular key when pasting is detected. */
ispaste = server_client_assume_paste(s);
if (ispaste)
isprefix = 0;
/* No previous prefix key. */
if (!(c->flags & CLIENT_PREFIX)) {
if (isprefix) {
c->flags |= CLIENT_PREFIX;
server_status_client(c);
return;
}
/* Try as a non-prefix key binding. */
if (ispaste || (bd = key_bindings_lookup(key)) == NULL) {
if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c, s, key, m);
} else
key_bindings_dispatch(bd, c, m);
return;
}
/* Prefix key already pressed. Reset prefix and lookup key. */
c->flags &= ~CLIENT_PREFIX;
server_status_client(c);
if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
/* If repeating, treat this as a key, else ignore. */
if (c->flags & CLIENT_REPEAT) {
c->flags &= ~CLIENT_REPEAT;
if (isprefix)
c->flags |= CLIENT_PREFIX;
else if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c, s, key, m);
}
return;
}
/* If already repeating, but this key can't repeat, skip it. */
if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
c->flags &= ~CLIENT_REPEAT;
if (isprefix)
c->flags |= CLIENT_PREFIX;
else if (!(c->flags & CLIENT_READONLY))
/* Treat everything as a regular key when pasting is detected. */
if (server_client_assume_paste(s)) {
if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c, s, key, m);
return;
}
/* If this key can repeat, reset the repeat flags and timer. */
xtimeout = options_get_number(&s->options, "repeat-time");
if (xtimeout != 0 && bd->can_repeat) {
c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
retry:
/* Try to see if there is a key binding in the current table. */
bd_find.key = key;
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) {
/*
* Key was matched in this table. If currently repeating but a
* non-repeating binding was found, stop repeating and try
* again in the root table.
*/
if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) {
server_client_key_table(c, "root");
c->flags &= ~CLIENT_REPEAT;
server_status_client(c);
goto retry;
}
tv.tv_sec = xtimeout / 1000;
tv.tv_usec = (xtimeout % 1000) * 1000L;
evtimer_del(&c->repeat_timer);
evtimer_add(&c->repeat_timer, &tv);
/*
* Take a reference to this table to make sure the key binding
* doesn't disappear.
*/
table->references++;
/*
* If this is a repeating key, start the timer. Otherwise reset
* the client back to the root table.
*/
xtimeout = options_get_number(&s->options, "repeat-time");
if (xtimeout != 0 && bd->can_repeat) {
c->flags |= CLIENT_REPEAT;
tv.tv_sec = xtimeout / 1000;
tv.tv_usec = (xtimeout % 1000) * 1000L;
evtimer_del(&c->repeat_timer);
evtimer_add(&c->repeat_timer, &tv);
} else {
c->flags &= ~CLIENT_REPEAT;
server_client_key_table(c, "root");
}
server_status_client(c);
/* Dispatch the key binding. */
key_bindings_dispatch(bd, c, m);
key_bindings_unref_table(table);
return;
}
/* Dispatch the command. */
key_bindings_dispatch(bd, c, m);
/*
* No match in this table. If repeating, switch the client back to the
* root table and try again.
*/
if (c->flags & CLIENT_REPEAT) {
server_client_key_table(c, "root");
c->flags &= ~CLIENT_REPEAT;
server_status_client(c);
goto retry;
}
/* If no match and we're not in the root table, that's it. */
if (strcmp(c->keytable->name, "root") != 0) {
server_client_key_table(c, "root");
server_status_client(c);
return;
}
/*
* No match, but in the root table. Prefix switches to the prefix table
* and everything else is passed through.
*/
if (key == options_get_number(&s->options, "prefix") ||
key == options_get_number(&s->options, "prefix2")) {
server_client_key_table(c, "prefix");
server_status_client(c);
} else if (!(c->flags & CLIENT_READONLY))
window_pane_key(wp, c, s, key, m);
}
/* Client functions that need to happen every loop. */
@ -857,9 +889,9 @@ server_client_repeat_timer(unused int fd, unused short events, void *data)
struct client *c = data;
if (c->flags & CLIENT_REPEAT) {
if (c->flags & CLIENT_PREFIX)
server_status_client(c);
c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
server_client_key_table(c, "root");
c->flags &= ~CLIENT_REPEAT;
server_status_client(c);
}
}

View File

@ -351,7 +351,6 @@ server_unlink_window(struct session *s, struct winlink *wl)
server_destroy_session_group(s);
else
server_redraw_session_group(s);
session_renumber_windows(s);
}
void

View File

@ -78,24 +78,22 @@ server_create_socket(void)
size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
if (size >= sizeof sa.sun_path) {
errno = ENAMETOOLONG;
fatal("socket failed");
return (-1);
}
unlink(sa.sun_path);
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed");
return (-1);
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
fatal("bind failed");
return (-1);
umask(mask);
if (listen(fd, 16) == -1)
fatal("listen failed");
return (-1);
setblocking(fd, 0);
server_update_socket();
return (fd);
}
@ -156,6 +154,9 @@ server_start(int lockfd, char *lockfile)
#endif
server_fd = server_create_socket();
if (server_fd == -1)
fatal("couldn't create socket");
server_update_socket();
server_client_create(pair[1]);
unlink(lockfile);
@ -388,6 +389,7 @@ server_add_accept(int timeout)
void
server_signal_callback(int sig, unused short events, unused void *data)
{
int fd;
switch (sig) {
case SIGTERM:
server_shutdown = 1;
@ -398,8 +400,12 @@ server_signal_callback(int sig, unused short events, unused void *data)
break;
case SIGUSR1:
event_del(&server_ev_accept);
close(server_fd);
server_fd = server_create_socket();
fd = server_create_socket();
if (fd != -1) {
close(server_fd);
server_fd = fd;
server_update_socket();
}
server_add_accept(0);
break;
}

108
tmux.1
View File

@ -163,7 +163,8 @@ If the socket is accidentally removed, the
.Dv SIGUSR1
signal may be sent to the
.Nm
server process to recreate it.
server process to recreate it (note that this will fail if any parent
directories are missing).
.It Fl l
Behave as a login shell.
This flag currently has no effect and is for compatibility with other shells
@ -842,6 +843,7 @@ Suspend a client by sending
.Op Fl lnpr
.Op Fl c Ar target-client
.Op Fl t Ar target-session
.Op Fl T Ar key-table
.Xc
.D1 (alias: Ic switchc )
Switch the current session for client
@ -859,6 +861,22 @@ respectively.
toggles whether a client is read-only (see the
.Ic attach-session
command).
.Pp
.Fl T
sets the client's key table; the next key from the client will be interpreted from
.Ar key-table .
This may be used to configure multiple prefix keys, or to bind commands to
sequences of keys.
For example, to make typing
.Ql abc
run the
.Ic list-keys
command:
.Bd -literal -offset indent
bind-key -Ttable2 c list-keys
bind-key -Ttable1 b switch-client -Ttable2
bind-key -Troot a switch-client -Ttable1
.Ed
.El
.Sh WINDOWS AND PANES
A
@ -1935,6 +1953,7 @@ Commands related to key bindings are as follows:
.It Xo Ic bind-key
.Op Fl cnr
.Op Fl t Ar mode-table
.Op Fl T Ar key-table
.Ar key Ar command Op Ar arguments
.Xc
.D1 (alias: Ic bind )
@ -1942,16 +1961,40 @@ Bind key
.Ar key
to
.Ar command .
By default (without
.Fl t )
the primary key bindings are modified (those normally activated with the prefix
key); in this case, if
.Fl n
is specified, it is not necessary to use the prefix key,
.Ar command
Keys are bound in a key table.
By default (without -T), the key is bound in
the
.Em prefix
key table.
This table is used for keys pressed after the prefix key (for example,
by default
.Ql c
is bound to
.Ar key
alone.
.Ic new-window
in the
.Em prefix
table, so
.Ql C-b c
creates a new window).
The
.Em root
table is used for keys pressed without the prefix key: binding
.Ql c
to
.Ic new-window
in the
.Em root
table (not recommended) means a plain
.Ql c
will create a new window.
.Fl n
is an alias
for
.Fl T Ar root .
Keys may also be bound in custom key tables and the
.Ic switch-client
.Fl T
command used to switch to them from a key binding.
The
.Fl r
flag indicates this key may repeat, see the
@ -1967,21 +2010,33 @@ is bound in
the binding for command mode with
.Fl c
or for normal mode without.
See the
.Sx WINDOWS AND PANES
section and the
.Ic list-keys
command for information on mode key bindings.
.Pp
To view the default bindings and possible commands, see the
.Ic list-keys
command.
.It Ic list-keys Op Fl t Ar key-table
.It Xo Ic list-keys
.Op Fl t Ar mode-table
.Op Fl T Ar key-table
.Xc
.D1 (alias: Ic lsk )
List all key bindings.
Without
.Fl t
the primary key bindings - those executed when preceded by the prefix key -
are printed.
.Fl T
all key tables are printed.
With
.Fl T
only
.Ar key-table .
.Pp
With
.Fl t ,
the key bindings in
.Ar key-table
.Ar mode-table
are listed; this may be one of:
.Em vi-edit ,
.Em emacs-edit ,
@ -2026,31 +2081,22 @@ the secondary prefix key, to a window as if it was pressed.
.It Xo Ic unbind-key
.Op Fl acn
.Op Fl t Ar mode-table
.Op Fl T Ar key-table
.Ar key
.Xc
.D1 (alias: Ic unbind )
Unbind the command bound to
.Ar key .
Without
.Fl c ,
.Fl n ,
.Fl T
and
.Fl t
the primary key bindings are modified; in this case, if
.Fl n
is specified, the command bound to
.Ar key
without a prefix (if any) is removed.
are the same as for
.Ic bind-key .
If
.Fl a
is present, all key bindings are removed.
.Pp
If
.Fl t
is present,
.Ar key
in
.Ar mode-table
is unbound: the binding for command mode with
.Fl c
or for normal mode without.
.El
.Sh OPTIONS
The appearance and behaviour of

41
tmux.h
View File

@ -87,10 +87,9 @@ extern char **environ;
#define KEYC_ESCAPE 0x2000
#define KEYC_CTRL 0x4000
#define KEYC_SHIFT 0x8000
#define KEYC_PREFIX 0x10000
/* Mask to obtain key w/o modifiers. */
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX)
#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT)
#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
/* Is this a mouse key? */
@ -1299,7 +1298,7 @@ struct client {
struct screen status;
#define CLIENT_TERMINAL 0x1
#define CLIENT_PREFIX 0x2
/* 0x2 unused */
#define CLIENT_EXIT 0x4
#define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10
@ -1318,6 +1317,7 @@ struct client {
#define CLIENT_256COLOURS 0x20000
#define CLIENT_IDENTIFIED 0x40000
int flags;
struct key_table *keytable;
struct event identify_timer;
@ -1438,15 +1438,24 @@ struct cmd_entry {
enum cmd_retval (*exec)(struct cmd *, struct cmd_q *);
};
/* Key binding. */
/* Key binding and key table. */
struct key_binding {
int key;
struct cmd_list *cmdlist;
int can_repeat;
int key;
struct cmd_list *cmdlist;
int can_repeat;
RB_ENTRY(key_binding) entry;
RB_ENTRY(key_binding) entry;
};
RB_HEAD(key_bindings, key_binding);
struct key_table {
const char *name;
struct key_bindings key_bindings;
u_int references;
RB_ENTRY(key_table) entry;
};
RB_HEAD(key_tables, key_table);
/*
* Option table entries. The option table is the user-visible part of the
@ -1874,12 +1883,16 @@ void cmd_wait_for_flush(void);
int client_main(int, char **, int);
/* key-bindings.c */
extern struct key_bindings key_bindings;
int key_bindings_cmp(struct key_binding *, struct key_binding *);
RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
struct key_binding *key_bindings_lookup(int);
void key_bindings_add(int, int, struct cmd_list *);
void key_bindings_remove(int);
RB_PROTOTYPE(key_tables, key_table, entry, key_table_cmp);
extern struct key_tables key_tables;
int key_table_cmp(struct key_table *, struct key_table *);
int key_bindings_cmp(struct key_binding *, struct key_binding *);
struct key_table *key_bindings_get_table(const char *, int);
void key_bindings_unref_table(struct key_table *);
void key_bindings_add(const char *, int, int, struct cmd_list *);
void key_bindings_remove(const char *, int);
void key_bindings_remove_table(const char *);
void key_bindings_init(void);
void key_bindings_dispatch(struct key_binding *, struct client *,
struct mouse_event *);
@ -2210,7 +2223,7 @@ struct layout_cell *layout_split_pane(
void layout_close_pane(struct window_pane *);
/* layout-custom.c */
char *layout_dump(struct window *);
char *layout_dump(struct layout_cell *);
int layout_parse(struct window *, const char *);
/* layout-set.c */

4
utf8.c
View File

@ -291,9 +291,9 @@ utf8_build(void)
while (*ptr != NULL) {
node = *ptr;
if (item->last < node->first)
ptr = &(node->left);
ptr = &node->left;
else if (item->first > node->last)
ptr = &(node->right);
ptr = &node->right;
}
*ptr = item;
}

View File

@ -2216,14 +2216,12 @@ window_copy_rectangle_toggle(struct window_pane *wp)
void
window_copy_start_drag(struct client *c, unused struct mouse_event *m)
{
struct window_pane *wp;
struct window_copy_mode_data *data;
u_int x, y;
struct window_pane *wp;
u_int x, y;
wp = cmd_mouse_pane(m, NULL, NULL);
if (wp->mode != &window_copy_mode)
if (wp == NULL || wp->mode != &window_copy_mode)
return;
data = wp->modedata;
if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
return;
@ -2244,7 +2242,7 @@ window_copy_drag_update(unused struct client *c, struct mouse_event *m)
u_int x, y, old_cy;
wp = cmd_mouse_pane(m, NULL, NULL);
if (wp->mode != &window_copy_mode)
if (wp == NULL || wp->mode != &window_copy_mode)
return;
data = wp->modedata;
@ -2260,13 +2258,11 @@ window_copy_drag_update(unused struct client *c, struct mouse_event *m)
void
window_copy_drag_release(unused struct client *c, struct mouse_event *m)
{
struct window_pane *wp;
struct window_copy_mode_data *data;
struct window_pane *wp;
wp = cmd_mouse_pane(m, NULL, NULL);
if (wp->mode != &window_copy_mode)
if (wp == NULL || wp->mode != &window_copy_mode)
return;
data = wp->modedata;
window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp);

View File

@ -518,6 +518,7 @@ window_unzoom(struct window *w)
w->flags &= ~WINDOW_ZOOMED;
layout_free(w);
w->layout_root = w->saved_layout_root;
w->saved_layout_root = NULL;
TAILQ_FOREACH(wp, &w->panes, entry) {
wp->layout_cell = wp->saved_layout_cell;