From 180faf73afe07d35e6002993a70d5fe63549ffce Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:09:59 +0000 Subject: [PATCH 01/91] Allow choose commands to be used outside tmux, so long as at least one client is attached. --- cmd-choose-buffer.c | 40 ++------- cmd-choose-client.c | 45 ++++------- cmd-choose-list.c | 35 ++------ cmd-choose-tree.c | 42 ++-------- cmd-find-window.c | 29 ++----- tmux.1 | 21 ++--- tmux.h | 35 ++++---- window-choose.c | 192 ++++++++++++++++++++++++++------------------ 8 files changed, 181 insertions(+), 258 deletions(-) diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index b811a042..a58e38b7 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -29,9 +29,6 @@ enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *); -void cmd_choose_buffer_callback(struct window_choose_data *); -void cmd_choose_buffer_free(struct window_choose_data *); - const struct cmd_entry cmd_choose_buffer_entry = { "choose-buffer", NULL, "F:t:", 0, 1, @@ -46,6 +43,7 @@ enum cmd_retval cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; + struct client *c; struct window_choose_data *cdata; struct winlink *wl; struct paste_buffer *pb; @@ -53,8 +51,8 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) const char *template; u_int idx; - if (ctx->curclient == NULL) { - ctx->error(ctx, "must be run interactively"); + if ((c = cmd_current_client(ctx)) == NULL) { + ctx->error(ctx, "no client available"); return (CMD_RETURN_ERROR); } @@ -77,9 +75,8 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) idx = 0; while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { - cdata = window_choose_data_create(ctx); + cdata = window_choose_data_create(TREE_OTHER, c, c->session); cdata->idx = idx - 1; - cdata->client->references++; cdata->ft_template = xstrdup(template); format_add(cdata->ft, "line", "%u", idx - 1); @@ -93,34 +90,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) } free(action); - window_choose_ready(wl->window->active, - 0, cmd_choose_buffer_callback, cmd_choose_buffer_free); + window_choose_ready(wl->window->active, 0, NULL); return (CMD_RETURN_NORMAL); } - -void -cmd_choose_buffer_callback(struct window_choose_data *cdata) -{ - if (cdata == NULL) - return; - if (cdata->client->flags & CLIENT_DEAD) - return; - - window_choose_ctx(cdata); -} - -void -cmd_choose_buffer_free(struct window_choose_data *data) -{ - struct window_choose_data *cdata = data; - - if (cdata == NULL) - return; - - cdata->client->references--; - - free(cdata->command); - free(cdata->ft_template); - free(cdata); -} diff --git a/cmd-choose-client.c b/cmd-choose-client.c index 1f9741fe..962aefca 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -30,7 +30,6 @@ enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_ctx *); void cmd_choose_client_callback(struct window_choose_data *); -void cmd_choose_client_free(struct window_choose_data *); const struct cmd_entry cmd_choose_client_entry = { "choose-client", NULL, @@ -50,15 +49,16 @@ enum cmd_retval cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; + struct client *c; + struct client *c1; struct window_choose_data *cdata; struct winlink *wl; - struct client *c; const char *template; char *action; u_int i, idx, cur; - if (ctx->curclient == NULL) { - ctx->error(ctx, "must be run interactively"); + if ((c = cmd_current_client(ctx)) == NULL) { + ctx->error(ctx, "no client available"); return (CMD_RETURN_ERROR); } @@ -78,30 +78,29 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) cur = idx = 0; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) + c1 = ARRAY_ITEM(&clients, i); + if (c1 == NULL || c1->session == NULL) continue; - if (c == ctx->curclient) + if (c1 == ctx->curclient) cur = idx; idx++; - cdata = window_choose_data_create(ctx); + cdata = window_choose_data_create(TREE_OTHER, c, c->session); cdata->idx = i; - cdata->client->references++; cdata->ft_template = xstrdup(template); format_add(cdata->ft, "line", "%u", i); - format_session(cdata->ft, c->session); - format_client(cdata->ft, c); + format_session(cdata->ft, c1->session); + format_client(cdata->ft, c1); - cdata->command = cmd_template_replace(action, c->tty.path, 1); + cdata->command = cmd_template_replace(action, c1->tty.path, 1); window_choose_add(wl->window->active, cdata); } free(action); - window_choose_ready(wl->window->active, - cur, cmd_choose_client_callback, cmd_choose_client_free); + window_choose_ready(wl->window->active, cur, + cmd_choose_client_callback); return (CMD_RETURN_NORMAL); } @@ -113,7 +112,7 @@ cmd_choose_client_callback(struct window_choose_data *cdata) if (cdata == NULL) return; - if (cdata->client->flags & CLIENT_DEAD) + if (cdata->start_client->flags & CLIENT_DEAD) return; if (cdata->idx > ARRAY_LENGTH(&clients) - 1) @@ -122,19 +121,5 @@ cmd_choose_client_callback(struct window_choose_data *cdata) if (c == NULL || c->session == NULL) return; - window_choose_ctx(cdata); -} - -void -cmd_choose_client_free(struct window_choose_data *cdata) -{ - if (cdata == NULL) - return; - - cdata->client->references--; - - free(cdata->ft_template); - free(cdata->command); - format_free(cdata->ft); - free(cdata); + window_choose_data_run(cdata); } diff --git a/cmd-choose-list.c b/cmd-choose-list.c index 4c32e694..9634fef4 100644 --- a/cmd-choose-list.c +++ b/cmd-choose-list.c @@ -33,9 +33,6 @@ enum cmd_retval cmd_choose_list_exec(struct cmd *, struct cmd_ctx *); -void cmd_choose_list_callback(struct window_choose_data *); -void cmd_choose_list_free(struct window_choose_data *); - const struct cmd_entry cmd_choose_list_entry = { "choose-list", NULL, "l:t:", 0, 1, @@ -50,13 +47,14 @@ enum cmd_retval cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; + struct client *c; struct winlink *wl; const char *list1; char *template, *item, *copy, *list; u_int idx; - if (ctx->curclient == NULL) { - ctx->error(ctx, "must be run interactively"); + if ((c = cmd_current_client(ctx)) == NULL) { + ctx->error(ctx, "no client available"); return (CMD_RETURN_ERROR); } @@ -80,7 +78,7 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) { if (*item == '\0') /* no empty entries */ continue; - window_choose_add_item(wl->window->active, ctx, wl, item, + window_choose_add_item(wl->window->active, c, wl, item, template, idx); idx++; } @@ -92,32 +90,9 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_ERROR); } - window_choose_ready(wl->window->active, 0, cmd_choose_list_callback, - cmd_choose_list_free); + window_choose_ready(wl->window->active, 0, NULL); free(template); return (CMD_RETURN_NORMAL); } - -void -cmd_choose_list_callback(struct window_choose_data *cdata) -{ - if (cdata == NULL || (cdata->client->flags & CLIENT_DEAD)) - return; - - window_choose_ctx(cdata); -} - -void -cmd_choose_list_free(struct window_choose_data *cdata) -{ - cdata->session->references--; - cdata->client->references--; - - free(cdata->ft_template); - free(cdata->command); - format_free(cdata->ft); - free(cdata); - -} diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index b274d561..a111bc07 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -34,9 +34,6 @@ enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_ctx *); -void cmd_choose_tree_callback(struct window_choose_data *); -void cmd_choose_tree_free(struct window_choose_data *); - const struct cmd_entry cmd_choose_tree_entry = { "choose-tree", NULL, "S:W:swub:c:t:", 0, 1, @@ -74,6 +71,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct winlink *wl, *wm; struct session *s, *s2; + struct client *c; struct window_choose_data *wcd = NULL; const char *ses_template, *win_template; char *final_win_action, *cur_win_template; @@ -86,12 +84,13 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) ses_template = win_template = NULL; ses_action = win_action = NULL; - if (ctx->curclient == NULL) { - ctx->error(ctx, "must be run interactively"); + if ((c = cmd_current_client(ctx)) == NULL) { + ctx->error(ctx, "no client available"); return (CMD_RETURN_ERROR); } - s = ctx->curclient->session; + if ((s = c->session) == NULL) + return (CMD_RETURN_ERROR); if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); @@ -175,7 +174,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) } wcd = window_choose_add_session(wl->window->active, - ctx, s2, ses_template, (char *)ses_action, idx_ses); + c, s2, ses_template, (char *)ses_action, idx_ses); /* If we're just choosing sessions, skip choosing windows. */ if (sflag && !wflag) { @@ -213,7 +212,7 @@ windows_only: cur_win_template = final_win_template_last; window_choose_add_window(wl->window->active, - ctx, s2, wm, cur_win_template, + c, s2, wm, cur_win_template, final_win_action, (wflag && !sflag) ? win_ses : idx_ses); @@ -230,35 +229,10 @@ windows_only: free(final_win_template_middle); free(final_win_template_last); - window_choose_ready(wl->window->active, cur_win, - cmd_choose_tree_callback, cmd_choose_tree_free); + window_choose_ready(wl->window->active, cur_win, NULL); if (args_has(args, 'u')) window_choose_expand_all(wl->window->active); return (CMD_RETURN_NORMAL); } - -void -cmd_choose_tree_callback(struct window_choose_data *cdata) -{ - if (cdata == NULL) - return; - - if (cdata->client->flags & CLIENT_DEAD) - return; - - window_choose_ctx(cdata); -} - -void -cmd_choose_tree_free(struct window_choose_data *cdata) -{ - cdata->session->references--; - cdata->client->references--; - - free(cdata->ft_template); - free(cdata->command); - format_free(cdata->ft); - free(cdata); -} diff --git a/cmd-find-window.c b/cmd-find-window.c index f2b20ae7..acd63c84 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -31,7 +31,6 @@ enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_ctx *); void cmd_find_window_callback(struct window_choose_data *); -void cmd_find_window_free(struct window_choose_data *); /* Flags for determining matching behavior. */ #define CMD_FIND_WINDOW_BY_TITLE 0x1 @@ -131,6 +130,7 @@ enum cmd_retval cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; + struct client *c; struct window_choose_data *cdata; struct session *s; struct winlink *wl, *wm; @@ -139,11 +139,11 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) const char *template; u_int i, match_flags; - if (ctx->curclient == NULL) { - ctx->error(ctx, "must be run interactively"); + if ((c = cmd_current_client(ctx)) == NULL) { + ctx->error(ctx, "no client available"); return (CMD_RETURN_ERROR); } - s = ctx->curclient->session; + s = c->session; if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); @@ -180,9 +180,8 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) for (i = 0; i < ARRAY_LENGTH(&find_list); i++) { wm = ARRAY_ITEM(&find_list, i).wl; - cdata = window_choose_data_create(ctx); + cdata = window_choose_data_create(TREE_OTHER, c, c->session); cdata->idx = wm->idx; - cdata->client->references++; cdata->wl = wm; cdata->ft_template = xstrdup(template); @@ -198,8 +197,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) window_choose_add(wl->window->active, cdata); } - window_choose_ready(wl->window->active, - 0, cmd_find_window_callback, cmd_find_window_free); + window_choose_ready(wl->window->active, 0, cmd_find_window_callback); out: ARRAY_FREE(&find_list); @@ -215,7 +213,7 @@ cmd_find_window_callback(struct window_choose_data *cdata) if (cdata == NULL) return; - s = cdata->session; + s = cdata->start_session; if (!session_alive(s)) return; @@ -228,16 +226,3 @@ cmd_find_window_callback(struct window_choose_data *cdata) recalculate_sizes(); } } - -void -cmd_find_window_free(struct window_choose_data *cdata) -{ - if (cdata == NULL) - return; - - cdata->session->references--; - - free(cdata->ft_template); - format_free(cdata->ft); - free(cdata); -} diff --git a/tmux.1 b/tmux.1 index ceebfcef..0e788130 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1074,8 +1074,7 @@ For the meaning of the flag, see the .Sx FORMATS section. -This command works only from inside -.Nm . +This command works only if at least one client is attached. .It Xo .Ic choose-list .Op Fl l Ar items @@ -1101,8 +1100,7 @@ also accepts format specifiers. For the meaning of this see the .Sx FORMATS section. -This command works only from inside -.Nm . +This command works only if at least one client is attached. .It Xo .Ic choose-session .Op Fl F Ar format @@ -1124,8 +1122,7 @@ For the meaning of the flag, see the .Sx FORMATS section. -This command works only from inside -.Nm . +This command works only if at least one client is attached. .It Xo .Ic choose-tree .Op Fl s @@ -1189,8 +1186,7 @@ and options, see the .Sx FORMATS section. -This command only works from inside -.Nm . +This command works only if at least one client is attached. .It Xo .Ic choose-window .Op Fl F Ar format @@ -1212,8 +1208,7 @@ For the meaning of the flag, see the .Sx FORMATS section. -This command works only from inside -.Nm . +This command works only if at least one client is attached. .It Ic display-panes Op Fl t Ar target-client .D1 (alias: Ic displayp) Display a visible indicator of each pane shown by @@ -1257,8 +1252,7 @@ For the meaning of the flag, see the .Sx FORMATS section. -This command only works from inside -.Nm . +This command works only if at least one client is attached. .It Xo Ic join-pane .Op Fl bdhv .Oo Fl l @@ -3306,8 +3300,7 @@ For the meaning of the flag, see the .Sx FORMATS section. -This command works only from inside -.Nm . +This command works only if at least one client is attached. .It Ic clear-history Op Fl t Ar target-pane .D1 (alias: Ic clearhist ) Remove and free the history for the specified pane. diff --git a/tmux.h b/tmux.h index f6382a70..d12cc3a5 100644 --- a/tmux.h +++ b/tmux.h @@ -883,18 +883,24 @@ struct window_mode { /* Structures for choose mode. */ struct window_choose_data { - struct client *client; - struct session *session; /* Session of current client. */ - struct session *tree_session; /* Session of items in tree. */ - struct format_tree *ft; - struct winlink *wl; - char *ft_template; - char *command; + struct client *start_client; + struct session *start_session; + u_int idx; int type; +#define TREE_OTHER 0x0 #define TREE_WINDOW 0x1 #define TREE_SESSION 0x2 + + struct session *tree_session; /* session of items in tree */ + + struct winlink *wl; int pane_id; + + char *ft_template; + struct format_tree *ft; + + char *command; }; struct window_choose_mode_item { @@ -2196,18 +2202,19 @@ extern const struct window_mode window_choose_mode; void window_choose_add(struct window_pane *, struct window_choose_data *); void window_choose_ready(struct window_pane *, - u_int, void (*)(struct window_choose_data *), - void (*)(struct window_choose_data *)); -struct window_choose_data *window_choose_data_create(struct cmd_ctx *); -void window_choose_ctx(struct window_choose_data *); + u_int, void (*)(struct window_choose_data *)); +struct window_choose_data *window_choose_data_create (int, + struct client *, struct session *); +void window_choose_data_free(struct window_choose_data *); +void window_choose_data_run(struct window_choose_data *); struct window_choose_data *window_choose_add_window(struct window_pane *, - struct cmd_ctx *, struct session *, struct winlink *, + struct client *, struct session *, struct winlink *, const char *, char *, u_int); struct window_choose_data *window_choose_add_session(struct window_pane *, - struct cmd_ctx *, struct session *, const char *, + struct client *, struct session *, const char *, char *, u_int); struct window_choose_data *window_choose_add_item(struct window_pane *, - struct cmd_ctx *, struct winlink *, const char *, + struct client *, struct winlink *, const char *, char *, u_int); void window_choose_expand_all(struct window_pane *); diff --git a/window-choose.c b/window-choose.c index dce026ec..041e1ecb 100644 --- a/window-choose.c +++ b/window-choose.c @@ -31,6 +31,8 @@ void window_choose_key(struct window_pane *, struct session *, int); void window_choose_mouse( struct window_pane *, struct session *, struct mouse_event *); +void window_choose_default_callback(struct window_choose_data *); + void window_choose_fire_callback( struct window_pane *, struct window_choose_data *); void window_choose_redraw_screen(struct window_pane *); @@ -101,8 +103,7 @@ window_choose_add(struct window_pane *wp, struct window_choose_data *wcd) void window_choose_ready(struct window_pane *wp, u_int cur, - void (*callbackfn)(struct window_choose_data *), - void (*freefn)(struct window_choose_data *)) + void (*callbackfn)(struct window_choose_data *)) { struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -112,7 +113,8 @@ window_choose_ready(struct window_pane *wp, u_int cur, data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s); data->callbackfn = callbackfn; - data->freefn = freefn; + if (data->callbackfn == NULL) + data->callbackfn = window_choose_default_callback; ARRAY_CONCAT(&data->old_list, &data->list); @@ -154,24 +156,95 @@ window_choose_init(struct window_pane *wp) } struct window_choose_data * -window_choose_data_create(struct cmd_ctx *ctx) +window_choose_data_create(int type, struct client *c, struct session *s) { struct window_choose_data *wcd; wcd = xmalloc(sizeof *wcd); + wcd->type = type; + wcd->ft = format_create(); wcd->ft_template = NULL; + wcd->command = NULL; + wcd->wl = NULL; - wcd->tree_session = NULL; - wcd->client = ctx->curclient; - wcd->session = ctx->curclient->session; + wcd->pane_id = -1; wcd->idx = -1; - wcd->type = 0; + + wcd->tree_session = NULL; + + wcd->start_client = c; + wcd->start_client->references++; + wcd->start_session = s; + wcd->start_session->references++; return (wcd); } +void +window_choose_data_free(struct window_choose_data *wcd) +{ + wcd->start_client->references--; + wcd->start_session->references--; + + if (wcd->tree_session != NULL) + wcd->tree_session->references--; + + free(wcd->ft_template); + format_free(wcd->ft); + + free(wcd->command); + free(wcd); +} + +void +window_choose_data_run(struct window_choose_data *cdata) +{ + struct cmd_ctx ctx; + struct cmd_list *cmdlist; + char *cause; + + /* + * The command template will have already been replaced. But if it's + * NULL, bail here. + */ + if (cdata->command == NULL) + return; + + if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) { + if (cause != NULL) { + *cause = toupper((u_char) *cause); + status_message_set(cdata->start_client, "%s", cause); + free(cause); + } + return; + } + + ctx.msgdata = NULL; + ctx.curclient = cdata->start_client; + + ctx.error = key_bindings_error; + ctx.print = key_bindings_print; + ctx.info = key_bindings_info; + + ctx.cmdclient = NULL; + + cmd_list_exec(cmdlist, &ctx); + cmd_list_free(cmdlist); +} + +void +window_choose_default_callback(struct window_choose_data *wcd) +{ + if (wcd == NULL) + return; + if (wcd->start_client->flags & CLIENT_DEAD) + return; + + window_choose_data_run(wcd); +} + void window_choose_free(struct window_pane *wp) { @@ -181,8 +254,7 @@ window_choose_free(struct window_pane *wp) for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) { item = &ARRAY_ITEM(&data->old_list, i); - if (data->freefn != NULL && item->wcd != NULL) - data->freefn(item->wcd); + window_choose_data_free(item->wcd); free(item->name); } ARRAY_FREE(&data->list); @@ -209,7 +281,7 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) void window_choose_fire_callback( - struct window_pane *wp, struct window_choose_data *wcd) + struct window_pane *wp, struct window_choose_data *wcd) { struct window_choose_mode_data *data = wp->modedata; const struct window_mode *oldmode; @@ -299,7 +371,7 @@ window_choose_collapse_all(struct window_pane *wp) struct session *s, *chosen; u_int i; - chosen = ARRAY_ITEM(&data->list, data->selected).wcd->session; + chosen = ARRAY_ITEM(&data->list, data->selected).wcd->start_session; RB_FOREACH(s, sessions, &sessions) window_choose_collapse(wp, s); @@ -790,58 +862,23 @@ window_choose_scroll_down(struct window_pane *wp) screen_write_stop(&ctx); } -void -window_choose_ctx(struct window_choose_data *cdata) -{ - struct cmd_ctx ctx; - struct cmd_list *cmdlist; - char *cause; - - /* The command template will have already been replaced. But if it's - * NULL, bail here. - */ - if (cdata->command == NULL) - return; - - if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) { - if (cause != NULL) { - *cause = toupper((u_char) *cause); - status_message_set(cdata->client, "%s", cause); - free(cause); - } - return; - } - - ctx.msgdata = NULL; - ctx.curclient = cdata->client; - - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; - - cmd_list_exec(cmdlist, &ctx); - cmd_list_free(cmdlist); -} - struct window_choose_data * -window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx, +window_choose_add_session(struct window_pane *wp, struct client *c, struct session *s, const char *template, char *action, u_int idx) { struct window_choose_data *wcd; - wcd = window_choose_data_create(ctx); + wcd = window_choose_data_create(TREE_SESSION, c, c->session); wcd->idx = s->idx; + wcd->tree_session = s; - wcd->type = TREE_SESSION; - wcd->command = cmd_template_replace(action, s->name, 1); + wcd->tree_session->references++; + wcd->ft_template = xstrdup(template); format_add(wcd->ft, "line", "%u", idx); format_session(wcd->ft, s); - wcd->client->references++; - wcd->session->references++; + wcd->command = cmd_template_replace(action, s->name, 1); window_choose_add(wp, wcd); @@ -849,63 +886,60 @@ window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx, } struct window_choose_data * -window_choose_add_item(struct window_pane *wp, struct cmd_ctx *ctx, +window_choose_add_item(struct window_pane *wp, struct client *c, struct winlink *wl, const char *template, char *action, u_int idx) { struct window_choose_data *wcd; - char *action_data; + char *expanded; - wcd = window_choose_data_create(ctx); + wcd = window_choose_data_create(TREE_OTHER, c, c->session); wcd->idx = wl->idx; + wcd->ft_template = xstrdup(template); format_add(wcd->ft, "line", "%u", idx); - format_session(wcd->ft, wcd->session); - format_winlink(wcd->ft, wcd->session, wl); + format_session(wcd->ft, wcd->start_session); + format_winlink(wcd->ft, wcd->start_session, wl); format_window_pane(wcd->ft, wl->window->active); - wcd->client->references++; - wcd->session->references++; + /* + * Interpolate action here, since the data we pass back is the expanded + * template itself. + */ + xasprintf(&expanded, "%s", format_expand(wcd->ft, wcd->ft_template)); + wcd->command = cmd_template_replace(action, expanded, 1); + free(expanded); window_choose_add(wp, wcd); - /* - * Interpolate action_data here, since the data we pass back is the - * expanded template itself. - */ - xasprintf(&action_data, "%s", format_expand(wcd->ft, wcd->ft_template)); - wcd->command = cmd_template_replace(action, action_data, 1); - free(action_data); - return (wcd); } struct window_choose_data * -window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx, +window_choose_add_window(struct window_pane *wp, struct client *c, struct session *s, struct winlink *wl, const char *template, char *action, u_int idx) { struct window_choose_data *wcd; - char *action_data; - - wcd = window_choose_data_create(ctx); - - xasprintf(&action_data, "%s:%d", s->name, wl->idx); - wcd->command = cmd_template_replace(action, action_data, 1); - free(action_data); + char *expanded; + wcd = window_choose_data_create(TREE_WINDOW, c, c->session); wcd->idx = wl->idx; + wcd->wl = wl; + wcd->tree_session = s; - wcd->type = TREE_WINDOW; + wcd->tree_session->references++; + wcd->ft_template = xstrdup(template); format_add(wcd->ft, "line", "%u", idx); format_session(wcd->ft, s); format_winlink(wcd->ft, s, wl); format_window_pane(wcd->ft, wl->window->active); - wcd->client->references++; - wcd->session->references++; + xasprintf(&expanded, "%s:%d", s->name, wl->idx); + wcd->command = cmd_template_replace(action, expanded, 1); + free(expanded); window_choose_add(wp, wcd); From 9b7e18f166b1f771a2ad3096831bf145731deb1b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:12:10 +0000 Subject: [PATCH 02/91] Rework reflow code so it does not do so much allocation which should be faster with large histories. --- grid.c | 153 +++++++++++++++++++++++++++++++++++++++++++++---------- screen.c | 13 ++--- 2 files changed, 129 insertions(+), 37 deletions(-) diff --git a/grid.c b/grid.c index a8d6d930..93160a06 100644 --- a/grid.c +++ b/grid.c @@ -70,6 +70,11 @@ grid_check_y(struct grid *gd, u_int py) } #endif +void grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int); +void grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int, + u_int); +void grid_reflow_move(struct grid *, u_int *, struct grid_line *); + /* Create a new grid. */ struct grid * grid_create(u_int sx, u_int sy, u_int hlimit) @@ -461,43 +466,135 @@ grid_duplicate_lines( } } +/* Join line data. */ +void +grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl, + u_int new_x) +{ + struct grid_line *dst_gl = &dst->linedata[(*py) - 1]; + u_int left, to_copy, ox, nx; + + /* How much is left on the old line? */ + left = new_x - dst_gl->cellsize; + + /* Work out how much to append. */ + to_copy = src_gl->cellsize; + if (to_copy > left) + to_copy = left; + ox = dst_gl->cellsize; + nx = ox + to_copy; + + /* Resize the destination line. */ + dst_gl->celldata = xrealloc(dst_gl->celldata, nx, + sizeof *dst_gl->celldata); + dst_gl->cellsize = nx; + + /* Append as much as possible. */ + memcpy(&dst_gl->celldata[ox], &src_gl->celldata[0], + to_copy * sizeof src_gl->celldata[0]); + + /* If there is any left in the source, split it. */ + if (src_gl->cellsize > to_copy) { + dst_gl->flags |= GRID_LINE_WRAPPED; + + src_gl->cellsize -= to_copy; + grid_reflow_split(dst, py, src_gl, new_x, to_copy); + } +} + +/* Split line data. */ +void +grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl, + u_int new_x, u_int offset) +{ + struct grid_line *dst_gl = NULL; + u_int to_copy; + + /* Loop and copy sections of the source line. */ + while (src_gl->cellsize > 0) { + /* Create new line. */ + if (*py >= dst->hsize + dst->sy) + grid_scroll_history(dst); + dst_gl = &dst->linedata[*py]; + (*py)++; + + /* How much should we copy? */ + to_copy = new_x; + if (to_copy > src_gl->cellsize) + to_copy = src_gl->cellsize; + + /* Expand destination line. */ + dst_gl->celldata = xmalloc(to_copy * sizeof *dst_gl->celldata); + dst_gl->cellsize = to_copy; + dst_gl->flags |= GRID_LINE_WRAPPED; + + /* Copy the data. */ + memcpy (&dst_gl->celldata[0], &src_gl->celldata[offset], + to_copy * sizeof dst_gl->celldata[0]); + + /* Move offset and reduce old line size. */ + offset += to_copy; + src_gl->cellsize -= to_copy; + } + + /* Last line is not wrapped. */ + if (dst_gl != NULL) + dst_gl->flags &= ~GRID_LINE_WRAPPED; +} + +/* Move line data. */ +void +grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl) +{ + struct grid_line *dst_gl; + + /* Create new line. */ + if (*py >= dst->hsize + dst->sy) + grid_scroll_history(dst); + dst_gl = &dst->linedata[*py]; + (*py)++; + + /* Copy the old line. */ + memcpy(dst_gl, src_gl, sizeof *dst_gl); + dst_gl->flags &= ~GRID_LINE_WRAPPED; + + /* Clear old line. */ + src_gl->celldata = NULL; +} + /* - * Reflow lines from src grid into dst grid based on width sx. Returns number - * of lines fewer in the visible area, or zero. + * Reflow lines from src grid into dst grid of width new_x. Returns number of + * lines fewer in the visible area. The source grid is destroyed. */ u_int -grid_reflow(struct grid *dst, const struct grid *src, u_int sx) +grid_reflow(struct grid *dst, struct grid *src, u_int new_x) { - u_int px, py, line, cell; + u_int py, sy, line; int previous_wrapped; - struct grid_line *gl; + struct grid_line *src_gl; - px = py = 0; - previous_wrapped = 1; - for (line = 0; line < src->sy + src->hsize; line++) { - gl = src->linedata + line; + py = 0; + sy = src->sy; + + previous_wrapped = 0; + for (line = 0; line < sy + src->hsize; line++) { + src_gl = src->linedata + line; if (!previous_wrapped) { - px = 0; - py++; - if (py >= dst->hsize + dst->sy) - grid_scroll_history(dst); + /* Wasn't wrapped. If smaller, move to destination. */ + if (src_gl->cellsize <= new_x) + grid_reflow_move(dst, &py, src_gl); + else + grid_reflow_split(dst, &py, src_gl, new_x, 0); + } else { + /* Previous was wrapped. Try to join. */ + grid_reflow_join(dst, &py, src_gl, new_x); } - for (cell = 0; cell < gl->cellsize; cell++) { - if (px == sx) { - dst->linedata[py].flags |= GRID_LINE_WRAPPED; - px = 0; - py++; - if (py >= dst->hsize + dst->sy) - grid_scroll_history(dst); - } - grid_set_cell(dst, px, py, gl->celldata + cell); - px++; - } - previous_wrapped = gl->flags & GRID_LINE_WRAPPED; + previous_wrapped = src_gl->flags & GRID_LINE_WRAPPED; } - py++; /* account for final line, which never wraps */ - if (py > src->sy) + grid_destroy(src); + + if (py > sy) return (0); - return (src->sy - py); + return (sy - py); } diff --git a/screen.c b/screen.c index 1c0c0d36..754effc2 100644 --- a/screen.c +++ b/screen.c @@ -362,15 +362,10 @@ screen_check_selection(struct screen *s, u_int px, u_int py) /* Reflow wrapped lines. */ void -screen_reflow(struct screen *s, u_int sx) +screen_reflow(struct screen *s, u_int new_x) { - struct grid *old, *new; + struct grid *old = s->grid; - old = s->grid; - new = grid_create(old->sx, old->sy, old->hlimit); - - s->cy -= grid_reflow(new, old, sx); - s->grid = new; - - grid_destroy(old); + s->grid = grid_create(old->sx, old->sy, old->hlimit); + s->cy -= grid_reflow(s->grid, old, new_x); } From dd76497ab01620bf5c7b63205f3e1405f3c34d8c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:12:50 +0000 Subject: [PATCH 03/91] Show alias in lscm output. --- cmd-list-commands.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 2ebc206e..261acefb 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -42,8 +42,15 @@ cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx) { const struct cmd_entry **entryp; - for (entryp = cmd_table; *entryp != NULL; entryp++) - ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage); + for (entryp = cmd_table; *entryp != NULL; entryp++) { + if ((*entryp)->alias != NULL) { + ctx->print(ctx, "%s (%s) %s", (*entryp)->name, + (*entryp)->alias, (*entryp)->usage); + } else { + ctx->print(ctx, "%s %s", (*entryp)->name, + (*entryp)->usage); + } + } return (CMD_RETURN_NORMAL); } From 63b4fd5cacc1a53b93e92ef007d5a7249f5cac38 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:14:09 +0000 Subject: [PATCH 04/91] Add a format client_prefix which is 1 if prefix key has been pressed, used for example #{?client_prefix,X,Y}. Also a few extra server_client_status needed. --- format.c | 5 ++++- server-client.c | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/format.c b/format.c index e950df53..f005c1c4 100644 --- a/format.c +++ b/format.c @@ -251,10 +251,11 @@ format_expand(struct format_tree *ft, const char *fmt) continue; } } - while (len - off < 2) { + while (len - off < 3) { buf = xrealloc(buf, 2, len); len *= 2; } + buf[off++] = '#'; buf[off++] = ch; continue; } @@ -321,6 +322,8 @@ format_client(struct format_tree *ft, struct client *c) *strchr(tim, '\n') = '\0'; format_add(ft, "client_activity_string", "%s", tim); + format_add(ft, "client_prefix", "%d", !!(c->flags & CLIENT_PREFIX)); + if (c->tty.flags & TTY_UTF8) format_add(ft, "client_utf8", "%d", 1); else diff --git a/server-client.c b/server-client.c index 82189a5c..1cae4733 100644 --- a/server-client.c +++ b/server-client.c @@ -418,6 +418,7 @@ server_client_handle_key(struct client *c, int key) if (!(c->flags & CLIENT_PREFIX)) { if (isprefix) { c->flags |= CLIENT_PREFIX; + server_status_client(c); return; } @@ -432,6 +433,7 @@ server_client_handle_key(struct client *c, int key) /* 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) { @@ -587,8 +589,11 @@ 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_REPEAT) { + if (c->flags & CLIENT_PREFIX) + server_status_client(c); c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); + } } /* Check if client should be exited. */ From 69fe5ca5670bc32b585e3ebf2066861212d7d014 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:15:52 +0000 Subject: [PATCH 05/91] Add -v to set and setw to show only option value. --- options-table.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/options-table.c b/options-table.c index 529b3c26..23828bf8 100644 --- a/options-table.c +++ b/options-table.c @@ -746,8 +746,8 @@ options_table_populate_tree( /* Print an option using its type from the table. */ const char * -options_table_print_entry( - const struct options_table_entry *oe, struct options_entry *o) +options_table_print_entry(const struct options_table_entry *oe, + struct options_entry *o, int no_quotes) { static char out[BUFSIZ]; const char *s; @@ -755,13 +755,17 @@ options_table_print_entry( *out = '\0'; switch (oe->type) { case OPTIONS_TABLE_STRING: - xsnprintf(out, sizeof out, "\"%s\"", o->str); + if (no_quotes) + xsnprintf(out, sizeof out, "%s", o->str); + else + xsnprintf(out, sizeof out, "\"%s\"", o->str); break; case OPTIONS_TABLE_NUMBER: xsnprintf(out, sizeof out, "%lld", o->num); break; case OPTIONS_TABLE_KEY: - xsnprintf(out, sizeof out, "%s", key_string_lookup_key(o->num)); + xsnprintf(out, sizeof out, "%s", + key_string_lookup_key(o->num)); break; case OPTIONS_TABLE_COLOUR: s = colour_tostring(o->num); From 0c0953f3bda2ecf9c351624c730445405d87e495 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:17:01 +0000 Subject: [PATCH 06/91] Add user options, prefixed with @. May be set to any arbitrary string. --- cmd-set-option.c | 68 +++++++++++++++++++++++++++++- cmd-show-options.c | 100 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 143 insertions(+), 25 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index d8d9edad..55b2c929 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -27,7 +27,10 @@ * Set an option. */ -enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_ctx *); + +enum cmd_retval cmd_set_option_user(struct cmd *, struct cmd_ctx *, + const char *, const char *); int cmd_set_option_unset(struct cmd *, struct cmd_ctx *, const struct options_table_entry *, struct options *, @@ -102,6 +105,10 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) else valstr = args->argv[1]; + /* Is this a user option? */ + if (*optstr == '@') + return (cmd_set_option_user(self, ctx, optstr, valstr)); + /* Find the option entry, try each table. */ table = oe = NULL; if (options_table_find(optstr, &table, &oe) != 0) { @@ -171,6 +178,63 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_NORMAL); } +/* Set user option. */ +enum cmd_retval +cmd_set_option_user(struct cmd *self, struct cmd_ctx *ctx, const char* optstr, + const char *valstr) +{ + struct args *args = self->args; + struct session *s; + struct winlink *wl; + struct options *oo; + + if (args_has(args, 's')) + oo = &global_options; + else if (args_has(self->args, 'w') || + self->entry == &cmd_set_window_option_entry) { + if (args_has(self->args, 'g')) + oo = &global_w_options; + else { + wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + if (wl == NULL) + return (CMD_RETURN_ERROR); + oo = &wl->window->options; + } + } else { + if (args_has(self->args, 'g')) + oo = &global_s_options; + else { + s = cmd_find_session(ctx, args_get(args, 't'), 0); + if (s == NULL) + return (CMD_RETURN_ERROR); + oo = &s->options; + } + } + + if (args_has(args, 'u')) { + if (options_find1(oo, optstr) == NULL) { + ctx->error(ctx, "unknown option: %s", optstr); + return (CMD_RETURN_ERROR); + } + if (valstr != NULL) { + ctx->error(ctx, "value passed to unset option: %s", + optstr); + return (CMD_RETURN_ERROR); + } + options_remove(oo, optstr); + } else { + if (valstr == NULL) { + ctx->error(ctx, "empty value"); + return (CMD_RETURN_ERROR); + } + options_set_string(oo, optstr, "%s", valstr); + if (!args_has(args, 'q')) + ctx->info(ctx, "set option: %s -> %s", optstr, valstr); + } + return (CMD_RETURN_NORMAL); +} + + /* Unset an option. */ int cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx, @@ -234,7 +298,7 @@ cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, if (o == NULL) return (-1); - s = options_table_print_entry(oe, o); + s = options_table_print_entry(oe, o, 0); if (!args_has(args, 'q')) ctx->info(ctx, "set option: %s -> %s", oe->name, s); return (0); diff --git a/cmd-show-options.c b/cmd-show-options.c index 85b481a1..b42c65cb 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -29,10 +29,15 @@ enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_ctx *, + struct options *); +enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_ctx *, + const struct options_table_entry *, struct options *); + const struct cmd_entry cmd_show_options_entry = { "show-options", "show", - "gst:w", 0, 1, - "[-gsw] [-t target-session|target-window] [option]", + "gst:vw", 0, 1, + "[-gsvw] [-t target-session|target-window] [option]", 0, NULL, NULL, @@ -41,8 +46,8 @@ const struct cmd_entry cmd_show_options_entry = { const struct cmd_entry cmd_show_window_options_entry = { "show-window-options", "showw", - "gt:", 0, 1, - "[-g] " CMD_TARGET_WINDOW_USAGE " [option]", + "gvt:", 0, 1, + "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]", 0, NULL, NULL, @@ -53,12 +58,10 @@ enum cmd_retval cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - const struct options_table_entry *table, *oe; struct session *s; struct winlink *wl; + const struct options_table_entry *table; struct options *oo; - struct options_entry *o; - const char *optval; if (args_has(self->args, 's')) { oo = &global_options; @@ -86,28 +89,79 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) } } - if (args->argc != 0) { - table = oe = NULL; - if (options_table_find(args->argv[0], &table, &oe) != 0) { - ctx->error(ctx, "ambiguous option: %s", args->argv[0]); - return (CMD_RETURN_ERROR); - } - if (oe == NULL) { + if (args->argc != 0) + return (cmd_show_options_one(self, ctx, oo)); + else + return (cmd_show_options_all(self, ctx, table, oo)); +} + +enum cmd_retval +cmd_show_options_one(struct cmd *self, struct cmd_ctx *ctx, + struct options *oo) +{ + struct args *args = self->args; + const struct options_table_entry *table, *oe; + struct options_entry *o; + const char *optval; + + if (*args->argv[0] == '@') { + if ((o = options_find1(oo, args->argv[0])) == NULL) { ctx->error(ctx, "unknown option: %s", args->argv[0]); return (CMD_RETURN_ERROR); } - if ((o = options_find1(oo, oe->name)) == NULL) - return (CMD_RETURN_NORMAL); - optval = options_table_print_entry(oe, o); + if (args_has(self->args, 'v')) + ctx->print(ctx, "%s", o->str); + else + ctx->print(ctx, "%s \"%s\"", o->name, o->str); + return (CMD_RETURN_NORMAL); + } + + table = oe = NULL; + if (options_table_find(args->argv[0], &table, &oe) != 0) { + ctx->error(ctx, "ambiguous option: %s", args->argv[0]); + return (CMD_RETURN_ERROR); + } + if (oe == NULL) { + ctx->error(ctx, "unknown option: %s", args->argv[0]); + return (CMD_RETURN_ERROR); + } + if ((o = options_find1(oo, oe->name)) == NULL) + return (CMD_RETURN_NORMAL); + optval = options_table_print_entry(oe, o, args_has(self->args, 'v')); + if (args_has(self->args, 'v')) + ctx->print(ctx, "%s", optval); + else ctx->print(ctx, "%s %s", oe->name, optval); - } else { - for (oe = table; oe->name != NULL; oe++) { - if ((o = options_find1(oo, oe->name)) == NULL) - continue; - optval = options_table_print_entry(oe, o); - ctx->print(ctx, "%s %s", oe->name, optval); + return (CMD_RETURN_NORMAL); +} + +enum cmd_retval +cmd_show_options_all(struct cmd *self, struct cmd_ctx *ctx, + const struct options_table_entry *table, struct options *oo) +{ + const struct options_table_entry *oe; + struct options_entry *o; + const char *optval; + + RB_FOREACH(o, options_tree, &oo->tree) { + if (*o->name == '@') { + if (args_has(self->args, 'v')) + ctx->print(ctx, "%s", o->str); + else + ctx->print(ctx, "%s \"%s\"", o->name, o->str); } } + for (oe = table; oe->name != NULL; oe++) { + if ((o = options_find1(oo, oe->name)) == NULL) + continue; + optval = options_table_print_entry(oe, o, + args_has(self->args, 'v')); + if (args_has(self->args, 'v')) + ctx->print(ctx, "%s", optval); + else + ctx->print(ctx, "%s %s", oe->name, optval); + } + return (CMD_RETURN_NORMAL); } From c982279950de9c9ffa797aab48caa1bff89ee8d4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:19:25 +0000 Subject: [PATCH 07/91] Fix constness of cmd_template_replace, window_choose_add_item and window_choose_add_window. --- tmux.h | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tmux.h b/tmux.h index d12cc3a5..b0e63069 100644 --- a/tmux.h +++ b/tmux.h @@ -1572,12 +1572,11 @@ long long options_get_number(struct options *, const char *); extern const struct options_table_entry server_options_table[]; extern const struct options_table_entry session_options_table[]; extern const struct options_table_entry window_options_table[]; -void options_table_populate_tree( - const struct options_table_entry *, struct options *); -const char *options_table_print_entry( - const struct options_table_entry *, struct options_entry *); -int options_table_find( - const char *, const struct options_table_entry **, +void options_table_populate_tree(const struct options_table_entry *, + struct options *); +const char *options_table_print_entry(const struct options_table_entry *, + struct options_entry *, int); +int options_table_find(const char *, const struct options_table_entry **, const struct options_table_entry **); /* job.c */ @@ -1725,7 +1724,7 @@ int cmd_find_index( struct cmd_ctx *, const char *, struct session **); struct winlink *cmd_find_pane(struct cmd_ctx *, const char *, struct session **, struct window_pane **); -char *cmd_template_replace(char *, const char *, int); +char *cmd_template_replace(const char *, const char *, int); const char *cmd_get_default_path(struct cmd_ctx *, const char *); extern const struct cmd_entry *cmd_table[]; extern const struct cmd_entry cmd_attach_session_entry; @@ -1970,7 +1969,7 @@ void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); char *grid_string_cells(struct grid *, u_int, u_int, u_int); void grid_duplicate_lines( struct grid *, u_int, struct grid *, u_int, u_int); -u_int grid_reflow(struct grid *, const struct grid *, u_int); +u_int grid_reflow(struct grid *, struct grid *, u_int); /* grid-cell.c */ u_int grid_cell_width(const struct grid_cell *); @@ -2209,13 +2208,13 @@ void window_choose_data_free(struct window_choose_data *); void window_choose_data_run(struct window_choose_data *); struct window_choose_data *window_choose_add_window(struct window_pane *, struct client *, struct session *, struct winlink *, - const char *, char *, u_int); + const char *, const char *, u_int); struct window_choose_data *window_choose_add_session(struct window_pane *, struct client *, struct session *, const char *, - char *, u_int); + const char *, u_int); struct window_choose_data *window_choose_add_item(struct window_pane *, struct client *, struct winlink *, const char *, - char *, u_int); + const char *, u_int); void window_choose_expand_all(struct window_pane *); /* names.c */ From 51d989f5dfaa63a844ae291772f20c486a5982fb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:22:48 +0000 Subject: [PATCH 08/91] Do not crash when calling choose-tree with a command that changes the mode. --- cmd.c | 12 ++++++------ window-choose.c | 32 +++++++++++++++++--------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/cmd.c b/cmd.c index b1b86eac..023a540d 100644 --- a/cmd.c +++ b/cmd.c @@ -1222,14 +1222,14 @@ cmd_find_pane_offset(const char *paneptr, struct winlink *wl) /* Replace the first %% or %idx in template by s. */ char * -cmd_template_replace(char *template, const char *s, int idx) +cmd_template_replace(const char *template, const char *s, int idx) { - char ch; - char *buf, *ptr; - int replaced; - size_t len; + char ch, *buf; + const char *ptr; + int replaced; + size_t len; - if (strstr(template, "%") == NULL) + if (strchr(template, '%') == NULL) return (xstrdup(template)); buf = xmalloc(1); diff --git a/window-choose.c b/window-choose.c index 041e1ecb..d89386b0 100644 --- a/window-choose.c +++ b/window-choose.c @@ -75,9 +75,9 @@ struct window_choose_mode_data { char *input_str; void (*callbackfn)(struct window_choose_data *); - void (*freefn)(struct window_choose_data *); }; +void window_choose_free1(struct window_choose_mode_data *); int window_choose_key_index(struct window_choose_mode_data *, u_int); int window_choose_index_key(struct window_choose_mode_data *, int); void window_choose_prompt_input(enum window_choose_input_type, @@ -131,7 +131,6 @@ window_choose_init(struct window_pane *wp) wp->modedata = data = xmalloc(sizeof *data); data->callbackfn = NULL; - data->freefn = NULL; data->input_type = WINDOW_CHOOSE_NORMAL; data->input_str = xstrdup(""); data->input_prompt = NULL; @@ -248,10 +247,19 @@ window_choose_default_callback(struct window_choose_data *wcd) void window_choose_free(struct window_pane *wp) { - struct window_choose_mode_data *data = wp->modedata; + if (wp->modedata != NULL) + window_choose_free1(wp->modedata); +} + +void +window_choose_free1(struct window_choose_mode_data *data) +{ struct window_choose_mode_item *item; u_int i; + if (data == NULL) + return; + for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) { item = &ARRAY_ITEM(&data->old_list, i); window_choose_data_free(item->wcd); @@ -284,14 +292,13 @@ window_choose_fire_callback( struct window_pane *wp, struct window_choose_data *wcd) { struct window_choose_mode_data *data = wp->modedata; - const struct window_mode *oldmode; - oldmode = wp->mode; - wp->mode = NULL; + wp->modedata = NULL; + window_pane_reset_mode(wp); data->callbackfn(wcd); - wp->mode = oldmode; + window_choose_free1(data); } void @@ -502,7 +509,6 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) } item = &ARRAY_ITEM(&data->list, n); window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); break; case MODEKEYCHOICE_BACKSPACE: input_len = strlen(data->input_str); @@ -523,12 +529,10 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCHOICE_CANCEL: window_choose_fire_callback(wp, NULL); - window_pane_reset_mode(wp); break; case MODEKEYCHOICE_CHOOSE: item = &ARRAY_ITEM(&data->list, data->selected); window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); break; case MODEKEYCHOICE_TREE_TOGGLE: item = &ARRAY_ITEM(&data->list, data->selected); @@ -678,7 +682,6 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) item = &ARRAY_ITEM(&data->list, data->selected); window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); break; } } @@ -707,7 +710,6 @@ window_choose_mouse( item = &ARRAY_ITEM(&data->list, data->selected); window_choose_fire_callback(wp, item->wcd); - window_pane_reset_mode(wp); } void @@ -864,7 +866,7 @@ window_choose_scroll_down(struct window_pane *wp) struct window_choose_data * window_choose_add_session(struct window_pane *wp, struct client *c, - struct session *s, const char *template, char *action, u_int idx) + struct session *s, const char *template, const char *action, u_int idx) { struct window_choose_data *wcd; @@ -887,7 +889,7 @@ window_choose_add_session(struct window_pane *wp, struct client *c, struct window_choose_data * window_choose_add_item(struct window_pane *wp, struct client *c, - struct winlink *wl, const char *template, char *action, u_int idx) + struct winlink *wl, const char *template, const char *action, u_int idx) { struct window_choose_data *wcd; char *expanded; @@ -918,7 +920,7 @@ window_choose_add_item(struct window_pane *wp, struct client *c, struct window_choose_data * window_choose_add_window(struct window_pane *wp, struct client *c, struct session *s, struct winlink *wl, const char *template, - char *action, u_int idx) + const char *action, u_int idx) { struct window_choose_data *wcd; char *expanded; From 66414029a12af55f4e6b4a421d5e193c2561e30c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:23:07 +0000 Subject: [PATCH 09/91] Run session command before window in choose-tree. --- cmd-choose-tree.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index a111bc07..1e6bba71 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -37,7 +37,7 @@ enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_choose_tree_entry = { "choose-tree", NULL, "S:W:swub:c:t:", 0, 1, - "[-swu] [-b session-template] [-c window template] [-S format] " \ + "[-suw] [-b session-template] [-c window template] [-S format] " \ "[-W format] " CMD_TARGET_WINDOW_USAGE, 0, NULL, @@ -174,7 +174,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) } wcd = window_choose_add_session(wl->window->active, - c, s2, ses_template, (char *)ses_action, idx_ses); + c, s2, ses_template, ses_action, idx_ses); /* If we're just choosing sessions, skip choosing windows. */ if (sflag && !wflag) { @@ -203,8 +203,8 @@ windows_only: cur_win = idx_ses; } - xasprintf(&final_win_action, "%s ; %s", win_action, - wcd ? wcd->command : ""); + xasprintf(&final_win_action, "%s ; %s", + wcd ? wcd->command : "", win_action); if (win_ses != win_max) cur_win_template = final_win_template_middle; From 4920306486122f3e6c1afd69518dbbdb40fbff5b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:23:46 +0000 Subject: [PATCH 10/91] Clarify choose-tree entry in man page. --- tmux.1 | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/tmux.1 b/tmux.1 index 0e788130..9ccf9054 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1125,9 +1125,7 @@ section. This command works only if at least one client is attached. .It Xo .Ic choose-tree -.Op Fl s -.Op Fl w -.Op Fl u +.Op Fl suw .Op Fl b Ar session-template .Op Fl c Ar window-template .Op Fl S Ar format @@ -1152,25 +1150,30 @@ is given, will show sessions. If .Fl w is given, will show windows. -If +.Pp +By default, the tree is collapsed and sessions must be expanded to windows +with the right arrow key. +The .Fl u -is given, the tree is uncollapsed by default. +will start with all all sessions expanded instead. +.Pp If .Fl b is given, will override the default session command. Note that .Ql %% -can be used, and will be replaced with the session name. +can be used and will be replaced with the session name. The default option if not specified is "switch-client -t '%%'". If .Fl c is given, will override the default window command. -Note that +Like +.Fl b , .Ql %% -can be used, and will be replaced with the session name and window index. -This command will run -.Ar session-template -before it. +can be used and will be replaced with the session name and window index. +When a window is chosen from the list, the session command is run before the +window command. +.Pp If .Fl S is given will display the specified format instead of the default session @@ -1186,6 +1189,7 @@ and options, see the .Sx FORMATS section. +.Pp This command works only if at least one client is attached. .It Xo .Ic choose-window @@ -1939,6 +1943,19 @@ All window options are documented with the .Ic set-window-option command. .Pp +.Nm +also supports user options which are prefixed with a +.Ql \&@ . +User options may have any name, so long as it is prefixed with +.Ql \&@, +and be set to any string. +For example +.Bd -literal -offset indent +$ tmux setw -q @foo "abc123" +$ tmux showw -v @foo +abc123 +.Ed +.Pp Commands which set options are as follows: .Bl -tag -width Ds .It Xo Ic set-option @@ -2865,7 +2882,7 @@ If this option is set, searches will wrap around the end of the pane contents. The default is on. .El .It Xo Ic show-options -.Op Fl gsw +.Op Fl gsvw .Op Fl t Ar target-session | Ar target-window .Op Ar option .Xc @@ -2881,8 +2898,10 @@ otherwise the session options for Global session or window options are listed if .Fl g is used. +.Fl v +shows only the option value, not the name. .It Xo Ic show-window-options -.Op Fl g +.Op Fl gv .Op Fl t Ar target-window .Op Ar option .Xc @@ -2892,6 +2911,8 @@ List the window options or a single option for or the global window options if .Fl g is used. +.Fl v +shows only the option value, not the name. .El .Sh FORMATS Certain commands accept the @@ -2935,6 +2956,7 @@ The following variables are available, where appropriate: .It Li "client_created_string" Ta "String time client created" .It Li "client_cwd" Ta "Working directory of client" .It Li "client_height" Ta "Height of client" +.It Li "client_prefix" Ta "1 if prefix key has been pressed" .It Li "client_readonly" Ta "1 if client is readonly" .It Li "client_termname" Ta "Terminal name of client" .It Li "client_tty" Ta "Pseudo terminal of client" From dd46c95e23e546dfe5ad66e8200d87b739c15db2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:25:08 +0000 Subject: [PATCH 11/91] Aargh. Spaces -> tabs. --- status.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/status.c b/status.c index dd4c737c..d9545218 100644 --- a/status.c +++ b/status.c @@ -393,13 +393,6 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl, long limit; u_int idx; - if (s == NULL) - s = c->session; - if (wl == NULL) - wl = s->curw; - if (wp == NULL) - wp = wl->window->active; - errno = 0; limit = strtol(*iptr, &endptr, 10); if ((limit == 0 && errno != EINVAL) || @@ -444,8 +437,7 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl, case 'P': if (window_pane_index(wp, &idx) != 0) fatalx("index not found"); - xsnprintf( - tmp, sizeof tmp, "%u", idx); + xsnprintf(tmp, sizeof tmp, "%u", idx); ptr = tmp; goto do_replace; case 'S': @@ -468,6 +460,9 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl, */ ch = ']'; goto skip_to; + case '{': + ptr = (char *) "#{"; + goto do_replace; case '#': *(*optr)++ = '#'; break; @@ -507,13 +502,21 @@ char * status_replace(struct client *c, struct session *s, struct winlink *wl, struct window_pane *wp, const char *fmt, time_t t, int jobsflag) { - static char out[BUFSIZ]; - char in[BUFSIZ], ch, *iptr, *optr; - size_t len; + static char out[BUFSIZ]; + char in[BUFSIZ], ch, *iptr, *optr, *expanded; + size_t len; + struct format_tree *ft; if (fmt == NULL) return (xstrdup("")); + if (s == NULL) + s = c->session; + if (wl == NULL) + wl = s->curw; + if (wp == NULL) + wp = wl->window->active; + len = strftime(in, sizeof in, fmt, localtime(&t)); in[len] = '\0'; @@ -534,7 +537,14 @@ status_replace(struct client *c, struct session *s, struct winlink *wl, } *optr = '\0'; - return (xstrdup(out)); + ft = format_create(); + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, wl); + format_window_pane(ft, wp); + expanded = format_expand(ft, out); + format_free(ft); + return (expanded); } /* Figure out job name and get its result, starting it off if necessary. */ From 801d64a16e320f0f24dcc65d2da9eabb16b17dee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:49:37 +0000 Subject: [PATCH 12/91] Add -c to refresh-client to set client size in control mode, based on code from George Nachman. --- cmd-refresh-client.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 0ce7be9d..885e8165 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -28,8 +28,8 @@ enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", - "St:", 0, 0, - "[-S] " CMD_TARGET_CLIENT_USAGE, + "C:St:", 0, 0, + "[-S] [-C size]" CMD_TARGET_CLIENT_USAGE, 0, NULL, NULL, @@ -41,11 +41,33 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; + const char *size; + u_int w, h; if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) return (CMD_RETURN_ERROR); - if (args_has(args, 'S')) { + if (args_has(args, 'C')) { + if ((size = args_get(args, 'C')) == NULL) { + ctx->error(ctx, "missing size"); + return (CMD_RETURN_ERROR); + } + if (sscanf(size, "%u,%u", &w, &h) != 2) { + ctx->error(ctx, "bad size argument"); + return (CMD_RETURN_ERROR); + } + if (w < PANE_MINIMUM || w > 5000 || + h < PANE_MINIMUM || h > 5000) { + ctx->error(ctx, "size too small or too big"); + return (CMD_RETURN_ERROR); + } + if (!(c->flags & CLIENT_CONTROL)) { + ctx->error(ctx, "not a control client"); + return (CMD_RETURN_ERROR); + } + if (tty_set_size(&c->tty, w, h)) + recalculate_sizes(); + } else if (args_has(args, 'S')) { status_update_jobs(c); server_status_client(c); } else From 3665be7c4467126b64c43b8fd687dd3512ccc05a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:50:22 +0000 Subject: [PATCH 13/91] Tidy by splitting default key tables into two. --- tmux.h | 2 +- tty.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.h b/tmux.h index b0e63069..1a2b4155 100644 --- a/tmux.h +++ b/tmux.h @@ -1674,7 +1674,7 @@ int tty_term_flag(struct tty_term *, enum tty_code_code); const char *tty_acs_get(struct tty *, u_char); /* tty-keys.c */ -void tty_keys_init(struct tty *); +void tty_keys_build(struct tty *); void tty_keys_free(struct tty *); int tty_keys_next(struct tty *); diff --git a/tty.c b/tty.c index 79cac5bb..9618a333 100644 --- a/tty.c +++ b/tty.c @@ -156,7 +156,7 @@ tty_open(struct tty *tty, const char *overrides, char **cause) tty_start_tty(tty); - tty_keys_init(tty); + tty_keys_build(tty); return (0); } From d5139d140154ef3e90fa65d0a8f2632bad1c67e1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:52:02 +0000 Subject: [PATCH 14/91] Fix a comment for new key table names. --- tty-keys.c | 485 ++++++++++++++++++++++++++--------------------------- 1 file changed, 242 insertions(+), 243 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 341f7fb2..c7f5372d 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -28,9 +28,9 @@ #include "tmux.h" /* - * Handle keys input from the outside terminal. tty_keys[] is a base table of - * supported keys which are looked up in terminfo(5) and translated into a - * ternary tree (a binary tree of binary trees). + * Handle keys input from the outside terminal. tty_default_*_keys[] are a base + * table of supported keys which are looked up in terminfo(5) and translated + * into a ternary tree. */ void tty_keys_add1(struct tty_key **, const char *, int); @@ -43,249 +43,244 @@ void tty_keys_callback(int, short, void *); int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); int tty_keys_device(struct tty *, const char *, size_t, size_t *); -struct tty_key_ent { - enum tty_code_code code; +/* Default raw keys. */ +struct tty_default_key_raw { const char *string; - int key; - int flags; -#define TTYKEY_RAW 0x1 }; - -/* - * Default key tables. Those flagged with TTYKEY_RAW are inserted directly, - * otherwise they are looked up in terminfo(5). - */ -const struct tty_key_ent tty_keys[] = { +const struct tty_default_key_raw tty_default_raw_keys[] = { /* * Numeric keypad. Just use the vt100 escape sequences here and always * put the terminal into keypad_xmit mode. Translation of numbers * mode/applications mode is done in input-keys.c. */ - { 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW }, - { 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW }, - { 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW }, - { 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW }, - { 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW }, - { 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW }, - { 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW }, - { 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW }, - { 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW }, - { 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW }, - { 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW }, - { 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW }, - { 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW }, - { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW }, - { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW }, - { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW }, + { "\033Oo", KEYC_KP_SLASH }, + { "\033Oj", KEYC_KP_STAR }, + { "\033Om", KEYC_KP_MINUS }, + { "\033Ow", KEYC_KP_SEVEN }, + { "\033Ox", KEYC_KP_EIGHT }, + { "\033Oy", KEYC_KP_NINE }, + { "\033Ok", KEYC_KP_PLUS }, + { "\033Ot", KEYC_KP_FOUR }, + { "\033Ou", KEYC_KP_FIVE }, + { "\033Ov", KEYC_KP_SIX }, + { "\033Oq", KEYC_KP_ONE }, + { "\033Or", KEYC_KP_TWO }, + { "\033Os", KEYC_KP_THREE }, + { "\033OM", KEYC_KP_ENTER }, + { "\033Op", KEYC_KP_ZERO }, + { "\033On", KEYC_KP_PERIOD }, /* Arrow keys. */ - { 0, "\033OA", KEYC_UP, TTYKEY_RAW }, - { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW }, + { "\033OA", KEYC_UP }, + { "\033OB", KEYC_DOWN }, + { "\033OC", KEYC_RIGHT }, + { "\033OD", KEYC_LEFT }, - { 0, "\033[A", KEYC_UP, TTYKEY_RAW }, - { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW }, - { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW }, - { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW }, + { "\033[A", KEYC_UP }, + { "\033[B", KEYC_DOWN }, + { "\033[C", KEYC_RIGHT }, + { "\033[D", KEYC_LEFT }, /* rxvt-style arrow + modifier keys. */ - { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033Od", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW }, + { "\033Oa", KEYC_UP|KEYC_CTRL }, + { "\033Ob", KEYC_DOWN|KEYC_CTRL }, + { "\033Oc", KEYC_RIGHT|KEYC_CTRL }, + { "\033Od", KEYC_LEFT|KEYC_CTRL }, - { 0, "\033[a", KEYC_UP|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[b", KEYC_DOWN|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[d", KEYC_LEFT|KEYC_SHIFT, TTYKEY_RAW }, + { "\033[a", KEYC_UP|KEYC_SHIFT }, + { "\033[b", KEYC_DOWN|KEYC_SHIFT }, + { "\033[c", KEYC_RIGHT|KEYC_SHIFT }, + { "\033[d", KEYC_LEFT|KEYC_SHIFT }, - /* - * rxvt-style function + modifier keys: - * Ctrl = ^, Shift = $, Ctrl+Shift = @ - */ - { 0, "\033[11^", KEYC_F1|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[12^", KEYC_F2|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[13^", KEYC_F3|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[14^", KEYC_F4|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[15^", KEYC_F5|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[17^", KEYC_F6|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[18^", KEYC_F7|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[19^", KEYC_F8|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[20^", KEYC_F9|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[21^", KEYC_F10|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[23^", KEYC_F11|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[24^", KEYC_F12|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[25^", KEYC_F13|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[26^", KEYC_F14|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[28^", KEYC_F15|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[29^", KEYC_F16|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[31^", KEYC_F17|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[32^", KEYC_F18|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[33^", KEYC_F19|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[34^", KEYC_F20|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[2^", KEYC_IC|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[3^", KEYC_DC|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[7^", KEYC_HOME|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[8^", KEYC_END|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[6^", KEYC_NPAGE|KEYC_CTRL, TTYKEY_RAW }, - { 0, "\033[5^", KEYC_PPAGE|KEYC_CTRL, TTYKEY_RAW }, + /* rxvt-style function + modifier keys (C = ^, S = $, C-S = @). */ + { "\033[11^", KEYC_F1|KEYC_CTRL }, + { "\033[12^", KEYC_F2|KEYC_CTRL }, + { "\033[13^", KEYC_F3|KEYC_CTRL }, + { "\033[14^", KEYC_F4|KEYC_CTRL }, + { "\033[15^", KEYC_F5|KEYC_CTRL }, + { "\033[17^", KEYC_F6|KEYC_CTRL }, + { "\033[18^", KEYC_F7|KEYC_CTRL }, + { "\033[19^", KEYC_F8|KEYC_CTRL }, + { "\033[20^", KEYC_F9|KEYC_CTRL }, + { "\033[21^", KEYC_F10|KEYC_CTRL }, + { "\033[23^", KEYC_F11|KEYC_CTRL }, + { "\033[24^", KEYC_F12|KEYC_CTRL }, + { "\033[25^", KEYC_F13|KEYC_CTRL }, + { "\033[26^", KEYC_F14|KEYC_CTRL }, + { "\033[28^", KEYC_F15|KEYC_CTRL }, + { "\033[29^", KEYC_F16|KEYC_CTRL }, + { "\033[31^", KEYC_F17|KEYC_CTRL }, + { "\033[32^", KEYC_F18|KEYC_CTRL }, + { "\033[33^", KEYC_F19|KEYC_CTRL }, + { "\033[34^", KEYC_F20|KEYC_CTRL }, + { "\033[2^", KEYC_IC|KEYC_CTRL }, + { "\033[3^", KEYC_DC|KEYC_CTRL }, + { "\033[7^", KEYC_HOME|KEYC_CTRL }, + { "\033[8^", KEYC_END|KEYC_CTRL }, + { "\033[6^", KEYC_NPAGE|KEYC_CTRL }, + { "\033[5^", KEYC_PPAGE|KEYC_CTRL }, - { 0, "\033[11$", KEYC_F1|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[12$", KEYC_F2|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[13$", KEYC_F3|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[14$", KEYC_F4|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[15$", KEYC_F5|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[17$", KEYC_F6|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[18$", KEYC_F7|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[19$", KEYC_F8|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[20$", KEYC_F9|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[21$", KEYC_F10|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[23$", KEYC_F11|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[24$", KEYC_F12|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[25$", KEYC_F13|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[26$", KEYC_F14|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[28$", KEYC_F15|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[29$", KEYC_F16|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[31$", KEYC_F17|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[32$", KEYC_F18|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[33$", KEYC_F19|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[34$", KEYC_F20|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[2$", KEYC_IC|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[3$", KEYC_DC|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[7$", KEYC_HOME|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[8$", KEYC_END|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[6$", KEYC_NPAGE|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[5$", KEYC_PPAGE|KEYC_SHIFT, TTYKEY_RAW }, + { "\033[11$", KEYC_F1|KEYC_SHIFT }, + { "\033[12$", KEYC_F2|KEYC_SHIFT }, + { "\033[13$", KEYC_F3|KEYC_SHIFT }, + { "\033[14$", KEYC_F4|KEYC_SHIFT }, + { "\033[15$", KEYC_F5|KEYC_SHIFT }, + { "\033[17$", KEYC_F6|KEYC_SHIFT }, + { "\033[18$", KEYC_F7|KEYC_SHIFT }, + { "\033[19$", KEYC_F8|KEYC_SHIFT }, + { "\033[20$", KEYC_F9|KEYC_SHIFT }, + { "\033[21$", KEYC_F10|KEYC_SHIFT }, + { "\033[23$", KEYC_F11|KEYC_SHIFT }, + { "\033[24$", KEYC_F12|KEYC_SHIFT }, + { "\033[25$", KEYC_F13|KEYC_SHIFT }, + { "\033[26$", KEYC_F14|KEYC_SHIFT }, + { "\033[28$", KEYC_F15|KEYC_SHIFT }, + { "\033[29$", KEYC_F16|KEYC_SHIFT }, + { "\033[31$", KEYC_F17|KEYC_SHIFT }, + { "\033[32$", KEYC_F18|KEYC_SHIFT }, + { "\033[33$", KEYC_F19|KEYC_SHIFT }, + { "\033[34$", KEYC_F20|KEYC_SHIFT }, + { "\033[2$", KEYC_IC|KEYC_SHIFT }, + { "\033[3$", KEYC_DC|KEYC_SHIFT }, + { "\033[7$", KEYC_HOME|KEYC_SHIFT }, + { "\033[8$", KEYC_END|KEYC_SHIFT }, + { "\033[6$", KEYC_NPAGE|KEYC_SHIFT }, + { "\033[5$", KEYC_PPAGE|KEYC_SHIFT }, - { 0, "\033[11@", KEYC_F1|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[12@", KEYC_F2|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[13@", KEYC_F3|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[14@", KEYC_F4|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[15@", KEYC_F5|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[17@", KEYC_F6|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[18@", KEYC_F7|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[19@", KEYC_F8|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[20@", KEYC_F9|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[21@", KEYC_F10|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[23@", KEYC_F11|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[24@", KEYC_F12|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[25@", KEYC_F13|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[26@", KEYC_F14|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[28@", KEYC_F15|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[29@", KEYC_F16|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[31@", KEYC_F17|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[32@", KEYC_F18|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[33@", KEYC_F19|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[34@", KEYC_F20|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[2@", KEYC_IC|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[3@", KEYC_DC|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[7@", KEYC_HOME|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[8@", KEYC_END|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW }, - { 0, "\033[6@", KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW }, - { 0, "\033[5@", KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW }, - - /* terminfo lookups below this line so they can override raw keys. */ - - /* Function keys. */ - { TTYC_KF1, NULL, KEYC_F1, 0 }, - { TTYC_KF2, NULL, KEYC_F2, 0 }, - { TTYC_KF3, NULL, KEYC_F3, 0 }, - { TTYC_KF4, NULL, KEYC_F4, 0 }, - { TTYC_KF5, NULL, KEYC_F5, 0 }, - { TTYC_KF6, NULL, KEYC_F6, 0 }, - { TTYC_KF7, NULL, KEYC_F7, 0 }, - { TTYC_KF8, NULL, KEYC_F8, 0 }, - { TTYC_KF9, NULL, KEYC_F9, 0 }, - { TTYC_KF10, NULL, KEYC_F10, 0 }, - { TTYC_KF11, NULL, KEYC_F11, 0 }, - { TTYC_KF12, NULL, KEYC_F12, 0 }, - { TTYC_KF13, NULL, KEYC_F13, 0 }, - { TTYC_KF14, NULL, KEYC_F14, 0 }, - { TTYC_KF15, NULL, KEYC_F15, 0 }, - { TTYC_KF16, NULL, KEYC_F16, 0 }, - { TTYC_KF17, NULL, KEYC_F17, 0 }, - { TTYC_KF18, NULL, KEYC_F18, 0 }, - { TTYC_KF19, NULL, KEYC_F19, 0 }, - { TTYC_KF20, NULL, KEYC_F20, 0 }, - { TTYC_KICH1, NULL, KEYC_IC, 0 }, - { TTYC_KDCH1, NULL, KEYC_DC, 0 }, - { TTYC_KHOME, NULL, KEYC_HOME, 0 }, - { TTYC_KEND, NULL, KEYC_END, 0 }, - { TTYC_KNP, NULL, KEYC_NPAGE, 0 }, - { TTYC_KPP, NULL, KEYC_PPAGE, 0 }, - { TTYC_KCBT, NULL, KEYC_BTAB, 0 }, - - /* Arrow keys from terminfo. */ - { TTYC_KCUU1, NULL, KEYC_UP, 0 }, - { TTYC_KCUD1, NULL, KEYC_DOWN, 0 }, - { TTYC_KCUB1, NULL, KEYC_LEFT, 0 }, - { TTYC_KCUF1, NULL, KEYC_RIGHT, 0 }, - - /* Key and modifier capabilities. */ - { TTYC_KDC2, NULL, KEYC_DC|KEYC_SHIFT, 0 }, - { TTYC_KDC3, NULL, KEYC_DC|KEYC_ESCAPE, 0 }, - { TTYC_KDC4, NULL, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KDC5, NULL, KEYC_DC|KEYC_CTRL, 0 }, - { TTYC_KDC6, NULL, KEYC_DC|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KDC7, NULL, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KDN2, NULL, KEYC_DOWN|KEYC_SHIFT, 0 }, - { TTYC_KDN3, NULL, KEYC_DOWN|KEYC_ESCAPE, 0 }, - { TTYC_KDN4, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KDN5, NULL, KEYC_DOWN|KEYC_CTRL, 0 }, - { TTYC_KDN6, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KDN7, NULL, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KEND2, NULL, KEYC_END|KEYC_SHIFT, 0 }, - { TTYC_KEND3, NULL, KEYC_END|KEYC_ESCAPE, 0 }, - { TTYC_KEND4, NULL, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KEND5, NULL, KEYC_END|KEYC_CTRL, 0 }, - { TTYC_KEND6, NULL, KEYC_END|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KEND7, NULL, KEYC_END|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KHOM2, NULL, KEYC_HOME|KEYC_SHIFT, 0 }, - { TTYC_KHOM3, NULL, KEYC_HOME|KEYC_ESCAPE, 0 }, - { TTYC_KHOM4, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KHOM5, NULL, KEYC_HOME|KEYC_CTRL, 0 }, - { TTYC_KHOM6, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KHOM7, NULL, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KIC2, NULL, KEYC_IC|KEYC_SHIFT, 0 }, - { TTYC_KIC3, NULL, KEYC_IC|KEYC_ESCAPE, 0 }, - { TTYC_KIC4, NULL, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KIC5, NULL, KEYC_IC|KEYC_CTRL, 0 }, - { TTYC_KIC6, NULL, KEYC_IC|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KIC7, NULL, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KLFT2, NULL, KEYC_LEFT|KEYC_SHIFT, 0 }, - { TTYC_KLFT3, NULL, KEYC_LEFT|KEYC_ESCAPE, 0 }, - { TTYC_KLFT4, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KLFT5, NULL, KEYC_LEFT|KEYC_CTRL, 0 }, - { TTYC_KLFT6, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KLFT7, NULL, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KNXT2, NULL, KEYC_NPAGE|KEYC_SHIFT, 0 }, - { TTYC_KNXT3, NULL, KEYC_NPAGE|KEYC_ESCAPE, 0 }, - { TTYC_KNXT4, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KNXT5, NULL, KEYC_NPAGE|KEYC_CTRL, 0 }, - { TTYC_KNXT6, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KNXT7, NULL, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KPRV2, NULL, KEYC_PPAGE|KEYC_SHIFT, 0 }, - { TTYC_KPRV3, NULL, KEYC_PPAGE|KEYC_ESCAPE, 0 }, - { TTYC_KPRV4, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KPRV5, NULL, KEYC_PPAGE|KEYC_CTRL, 0 }, - { TTYC_KPRV6, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KPRV7, NULL, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KRIT2, NULL, KEYC_RIGHT|KEYC_SHIFT, 0 }, - { TTYC_KRIT3, NULL, KEYC_RIGHT|KEYC_ESCAPE, 0 }, - { TTYC_KRIT4, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KRIT5, NULL, KEYC_RIGHT|KEYC_CTRL, 0 }, - { TTYC_KRIT6, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KRIT7, NULL, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL, 0 }, - { TTYC_KUP2, NULL, KEYC_UP|KEYC_SHIFT, 0 }, - { TTYC_KUP3, NULL, KEYC_UP|KEYC_ESCAPE, 0 }, - { TTYC_KUP4, NULL, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE, 0 }, - { TTYC_KUP5, NULL, KEYC_UP|KEYC_CTRL, 0 }, - { TTYC_KUP6, NULL, KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 }, - { TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 }, + { "\033[11@", KEYC_F1|KEYC_CTRL|KEYC_SHIFT }, + { "\033[12@", KEYC_F2|KEYC_CTRL|KEYC_SHIFT }, + { "\033[13@", KEYC_F3|KEYC_CTRL|KEYC_SHIFT }, + { "\033[14@", KEYC_F4|KEYC_CTRL|KEYC_SHIFT }, + { "\033[15@", KEYC_F5|KEYC_CTRL|KEYC_SHIFT }, + { "\033[17@", KEYC_F6|KEYC_CTRL|KEYC_SHIFT }, + { "\033[18@", KEYC_F7|KEYC_CTRL|KEYC_SHIFT }, + { "\033[19@", KEYC_F8|KEYC_CTRL|KEYC_SHIFT }, + { "\033[20@", KEYC_F9|KEYC_CTRL|KEYC_SHIFT }, + { "\033[21@", KEYC_F10|KEYC_CTRL|KEYC_SHIFT }, + { "\033[23@", KEYC_F11|KEYC_CTRL|KEYC_SHIFT }, + { "\033[24@", KEYC_F12|KEYC_CTRL|KEYC_SHIFT }, + { "\033[25@", KEYC_F13|KEYC_CTRL|KEYC_SHIFT }, + { "\033[26@", KEYC_F14|KEYC_CTRL|KEYC_SHIFT }, + { "\033[28@", KEYC_F15|KEYC_CTRL|KEYC_SHIFT }, + { "\033[29@", KEYC_F16|KEYC_CTRL|KEYC_SHIFT }, + { "\033[31@", KEYC_F17|KEYC_CTRL|KEYC_SHIFT }, + { "\033[32@", KEYC_F18|KEYC_CTRL|KEYC_SHIFT }, + { "\033[33@", KEYC_F19|KEYC_CTRL|KEYC_SHIFT }, + { "\033[34@", KEYC_F20|KEYC_CTRL|KEYC_SHIFT }, + { "\033[2@", KEYC_IC|KEYC_CTRL|KEYC_SHIFT }, + { "\033[3@", KEYC_DC|KEYC_CTRL|KEYC_SHIFT }, + { "\033[7@", KEYC_HOME|KEYC_CTRL|KEYC_SHIFT }, + { "\033[8@", KEYC_END|KEYC_CTRL|KEYC_SHIFT }, + { "\033[6@", KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT }, + { "\033[5@", KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT }, }; +/* Default terminfo(5) keys. */ +struct tty_default_key_code { + enum tty_code_code code; + int key; +}; +const struct tty_default_key_code tty_default_code_keys[] = { + /* Function keys. */ + { TTYC_KF1, KEYC_F1 }, + { TTYC_KF2, KEYC_F2 }, + { TTYC_KF3, KEYC_F3 }, + { TTYC_KF4, KEYC_F4 }, + { TTYC_KF5, KEYC_F5 }, + { TTYC_KF6, KEYC_F6 }, + { TTYC_KF7, KEYC_F7 }, + { TTYC_KF8, KEYC_F8 }, + { TTYC_KF9, KEYC_F9 }, + { TTYC_KF10, KEYC_F10 }, + { TTYC_KF11, KEYC_F11 }, + { TTYC_KF12, KEYC_F12 }, + { TTYC_KF13, KEYC_F13 }, + { TTYC_KF14, KEYC_F14 }, + { TTYC_KF15, KEYC_F15 }, + { TTYC_KF16, KEYC_F16 }, + { TTYC_KF17, KEYC_F17 }, + { TTYC_KF18, KEYC_F18 }, + { TTYC_KF19, KEYC_F19 }, + { TTYC_KF20, KEYC_F20 }, + { TTYC_KICH1, KEYC_IC }, + { TTYC_KDCH1, KEYC_DC }, + { TTYC_KHOME, KEYC_HOME }, + { TTYC_KEND, KEYC_END }, + { TTYC_KNP, KEYC_NPAGE }, + { TTYC_KPP, KEYC_PPAGE }, + { TTYC_KCBT, KEYC_BTAB }, + + /* Arrow keys from terminfo. */ + { TTYC_KCUU1, KEYC_UP }, + { TTYC_KCUD1, KEYC_DOWN }, + { TTYC_KCUB1, KEYC_LEFT }, + { TTYC_KCUF1, KEYC_RIGHT }, + + /* Key and modifier capabilities. */ + { TTYC_KDC2, KEYC_DC|KEYC_SHIFT }, + { TTYC_KDC3, KEYC_DC|KEYC_ESCAPE }, + { TTYC_KDC4, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KDC5, KEYC_DC|KEYC_CTRL }, + { TTYC_KDC6, KEYC_DC|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KDC7, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KDN2, KEYC_DOWN|KEYC_SHIFT }, + { TTYC_KDN3, KEYC_DOWN|KEYC_ESCAPE }, + { TTYC_KDN4, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KDN5, KEYC_DOWN|KEYC_CTRL }, + { TTYC_KDN6, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KDN7, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KEND2, KEYC_END|KEYC_SHIFT }, + { TTYC_KEND3, KEYC_END|KEYC_ESCAPE }, + { TTYC_KEND4, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KEND5, KEYC_END|KEYC_CTRL }, + { TTYC_KEND6, KEYC_END|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KEND7, KEYC_END|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KHOM2, KEYC_HOME|KEYC_SHIFT }, + { TTYC_KHOM3, KEYC_HOME|KEYC_ESCAPE }, + { TTYC_KHOM4, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KHOM5, KEYC_HOME|KEYC_CTRL }, + { TTYC_KHOM6, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KHOM7, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KIC2, KEYC_IC|KEYC_SHIFT }, + { TTYC_KIC3, KEYC_IC|KEYC_ESCAPE }, + { TTYC_KIC4, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KIC5, KEYC_IC|KEYC_CTRL }, + { TTYC_KIC6, KEYC_IC|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KIC7, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KLFT2, KEYC_LEFT|KEYC_SHIFT }, + { TTYC_KLFT3, KEYC_LEFT|KEYC_ESCAPE }, + { TTYC_KLFT4, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KLFT5, KEYC_LEFT|KEYC_CTRL }, + { TTYC_KLFT6, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KLFT7, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KNXT2, KEYC_NPAGE|KEYC_SHIFT }, + { TTYC_KNXT3, KEYC_NPAGE|KEYC_ESCAPE }, + { TTYC_KNXT4, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KNXT5, KEYC_NPAGE|KEYC_CTRL }, + { TTYC_KNXT6, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KNXT7, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KPRV2, KEYC_PPAGE|KEYC_SHIFT }, + { TTYC_KPRV3, KEYC_PPAGE|KEYC_ESCAPE }, + { TTYC_KPRV4, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KPRV5, KEYC_PPAGE|KEYC_CTRL }, + { TTYC_KPRV6, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KPRV7, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KRIT2, KEYC_RIGHT|KEYC_SHIFT }, + { TTYC_KRIT3, KEYC_RIGHT|KEYC_ESCAPE }, + { TTYC_KRIT4, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KRIT5, KEYC_RIGHT|KEYC_CTRL }, + { TTYC_KRIT6, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KRIT7, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL }, + { TTYC_KUP2, KEYC_UP|KEYC_SHIFT }, + { TTYC_KUP3, KEYC_UP|KEYC_ESCAPE }, + { TTYC_KUP4, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE }, + { TTYC_KUP5, KEYC_UP|KEYC_CTRL }, + { TTYC_KUP6, KEYC_UP|KEYC_SHIFT|KEYC_CTRL }, + { TTYC_KUP7, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL }, +}; + +/* Add key to tree. */ void tty_keys_add(struct tty *tty, const char *s, int key) { @@ -343,27 +338,31 @@ tty_keys_add1(struct tty_key **tkp, const char *s, int key) /* Initialise a key tree from the table. */ void -tty_keys_init(struct tty *tty) +tty_keys_build(struct tty *tty) { - const struct tty_key_ent *tke; - u_int i; - const char *s; + const struct tty_default_key_raw *tdkr; + const struct tty_default_key_code *tdkc; + u_int i; + const char *s; + if (tty->key_tree != NULL) + tty_keys_free (tty); tty->key_tree = NULL; - for (i = 0; i < nitems(tty_keys); i++) { - tke = &tty_keys[i]; - if (tke->flags & TTYKEY_RAW) - s = tke->string; - else { - if (!tty_term_has(tty->term, tke->code)) - continue; - s = tty_term_string(tty->term, tke->code); - } - if (s[0] != '\033' || s[1] == '\0') - continue; + for (i = 0; i < nitems(tty_default_raw_keys); i++) { + tdkr = &tty_default_raw_keys[i]; + + s = tdkr->string; + if (s[0] == '\033' && s[1] != '\0') + tty_keys_add(tty, s + 1, tdkr->key); + } + for (i = 0; i < nitems(tty_default_code_keys); i++) { + tdkc = &tty_default_code_keys[i]; + + s = tty_term_string(tty->term, tdkc->code); + if (s[0] == '\033' || s[1] == '\0') + tty_keys_add(tty, s + 1, tdkc->key); - tty_keys_add(tty, s + 1, tke->key); } } From 48291f0eeb9c376f821c746ca1ab6b88fcb62db2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:53:12 +0000 Subject: [PATCH 15/91] Make choose-tree actually work again. --- cmd-choose-tree.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 1e6bba71..af85a3bf 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -203,8 +203,9 @@ windows_only: cur_win = idx_ses; } - xasprintf(&final_win_action, "%s ; %s", - wcd ? wcd->command : "", win_action); + xasprintf(&final_win_action, "%s %s %s", + wcd != NULL ? wcd->command : "", + wcd != NULL ? ";" : "", win_action); if (win_ses != win_max) cur_win_template = final_win_template_middle; From 51ac2a3202d55c439976ecce49229e35865c7ebd Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:54:37 +0000 Subject: [PATCH 16/91] Fix a couple of memory leaks, from Romain Francoise. --- cfg.c | 4 +++- mode-key.c | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cfg.c b/cfg.c index f9ad300f..aa2ceea4 100644 --- a/cfg.c +++ b/cfg.c @@ -131,8 +131,10 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) buf = copy; while (isspace((u_char)*buf)) buf++; - if (*buf == '\0') + if (*buf == '\0') { + free(copy); continue; + } if (cmd_string_parse(buf, &cmdlist, &cause) != 0) { free(copy); diff --git a/mode-key.c b/mode-key.c index 821f1ef4..6c041359 100644 --- a/mode-key.c +++ b/mode-key.c @@ -413,7 +413,6 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE }, { '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION }, { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, - { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, { 'f', 0, MODEKEYCOPY_JUMP }, { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND }, From 55bf2ecc68ad7ab5763def321669375764b3983a Mon Sep 17 00:00:00 2001 From: Jason McIntyre Date: Thu, 21 Mar 2013 17:42:36 +0000 Subject: [PATCH 17/91] tweak previous; ok nicm --- tmux.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.1 b/tmux.1 index 9ccf9054..122038ea 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1155,7 +1155,7 @@ By default, the tree is collapsed and sessions must be expanded to windows with the right arrow key. The .Fl u -will start with all all sessions expanded instead. +option will start with all sessions expanded instead. .Pp If .Fl b @@ -1946,8 +1946,8 @@ command. .Nm also supports user options which are prefixed with a .Ql \&@ . -User options may have any name, so long as it is prefixed with -.Ql \&@, +User options may have any name, so long as they are prefixed with +.Ql \&@ , and be set to any string. For example .Bd -literal -offset indent From 78543cce30245c3450adc31c8787373c5ca93e38 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 18:43:34 +0000 Subject: [PATCH 18/91] Support capture-pane -p to send to stdout. --- cmd-capture-pane.c | 53 +++++++++++++++++++++++++++++----------------- tmux.1 | 12 +++++++++-- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 86c614e9..ee42ddee 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -24,15 +24,16 @@ #include "tmux.h" /* - * Write the entire contents of a pane to a buffer. + * Write the entire contents of a pane to a buffer or stdout. */ enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", - "b:E:S:t:", 0, 0, - "[-b buffer-index] [-E end-line] [-S start-line] " + "b:c:E:pS:t:", 0, 0, + "[-p] [-c target-client] [-b buffer-index] [-E end-line] " + "[-S start-line] " CMD_TARGET_PANE_USAGE, 0, NULL, @@ -44,6 +45,7 @@ enum cmd_retval cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; + struct client *c; struct window_pane *wp; char *buf, *line, *cause; struct screen *s; @@ -52,6 +54,9 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i, limit, top, bottom, tmp; size_t len, linelen; + if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) + return (CMD_RETURN_ERROR); + if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); s = &wp->base; @@ -100,25 +105,33 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) free(line); } - limit = options_get_number(&global_options, "buffer-limit"); + if (args_has(args, 'p')) { + if (c == NULL) { + ctx->error(ctx, "can't write to stdout"); + return (CMD_RETURN_ERROR); + } + evbuffer_add(c->stdout_data, buf, len); + server_push_stdout(c); + } else { + limit = options_get_number(&global_options, "buffer-limit"); + if (!args_has(args, 'b')) { + paste_add(&global_buffers, buf, len, limit); + return (CMD_RETURN_NORMAL); + } - if (!args_has(args, 'b')) { - paste_add(&global_buffers, buf, len, limit); - return (CMD_RETURN_NORMAL); - } + buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); + if (cause != NULL) { + ctx->error(ctx, "buffer %s", cause); + free(buf); + free(cause); + return (CMD_RETURN_ERROR); + } - buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); - if (cause != NULL) { - ctx->error(ctx, "buffer %s", cause); - free(buf); - free(cause); - return (CMD_RETURN_ERROR); - } - - if (paste_replace(&global_buffers, buffer, buf, len) != 0) { - ctx->error(ctx, "no buffer %d", buffer); - free(buf); - return (CMD_RETURN_ERROR); + if (paste_replace(&global_buffers, buffer, buf, len) != 0) { + ctx->error(ctx, "no buffer %d", buffer); + free(buf); + return (CMD_RETURN_ERROR); + } } return (CMD_RETURN_NORMAL); diff --git a/tmux.1 b/tmux.1 index 122038ea..72001997 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1036,14 +1036,22 @@ By default, it uses the format but a different format may be specified with .Fl F . .It Xo Ic capture-pane +.Op Fl p .Op Fl b Ar buffer-index +.Op Fl c Ar target-client .Op Fl E Ar end-line .Op Fl S Ar start-line .Op Fl t Ar target-pane .Xc .D1 (alias: Ic capturep ) -Capture the contents of a pane to the specified buffer, or a new buffer if none -is specified. +Capture the contents of a pane. +If +.Fl p +is given, the output goes to +.Ar target-client +stdout, otherwise to the buffer specified with +.Fl b +or a new buffer if omitted. .Pp .Fl S and From 3d24c75d0f9234f7490f6e5277476fb8d6748da6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 18:44:47 +0000 Subject: [PATCH 19/91] Include the \033 in the key tree and adjust key matching for this change. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 9618a333..0749b510 100644 --- a/tty.c +++ b/tty.c @@ -149,7 +149,7 @@ tty_open(struct tty *tty, const char *overrides, char **cause) } tty->flags |= TTY_OPENED; - tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_ESCAPE); + tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_TIMER); tty->event = bufferevent_new( tty->fd, tty_read_callback, NULL, tty_error_callback, tty); From d4785fe798fff238c65a9324c0a7b6c9ed3efb7f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 18:45:38 +0000 Subject: [PATCH 20/91] Don't set key KEYC_NONE on xterm_keys_find match() When calling xterm_keys_find(); if we get a complete match, don't set the key to unknown before calling the action to complete the binding; otherwise non-prefixed bindings will not work. From Thomas Adam --- tty-keys.c | 148 +++++++++++++++++++++++------------------------------ 1 file changed, 64 insertions(+), 84 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index c7f5372d..7fb96786 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -353,17 +353,19 @@ tty_keys_build(struct tty *tty) tdkr = &tty_default_raw_keys[i]; s = tdkr->string; - if (s[0] == '\033' && s[1] != '\0') - tty_keys_add(tty, s + 1, tdkr->key); + if (*s != '\0') + tty_keys_add(tty, s, tdkr->key); } for (i = 0; i < nitems(tty_default_code_keys); i++) { tdkc = &tty_default_code_keys[i]; s = tty_term_string(tty->term, tdkc->code); - if (s[0] == '\033' || s[1] == '\0') - tty_keys_add(tty, s + 1, tdkc->key); + if (*s != '\0') + tty_keys_add(tty, s, tdkc->key); } + + tty_keys_add(tty, "abc", 'x'); } /* Free the entire key tree. */ @@ -439,34 +441,18 @@ tty_keys_next(struct tty *tty) cc_t bspace; int key, delay; + /* Get key buffer. */ buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); if (len == 0) return (0); log_debug("keys are %zu (%.*s)", len, (int) len, buf); - /* If a normal key, return it. */ - if (*buf != '\033') { - key = (u_char) *buf; - evbuffer_drain(tty->event->input, 1); - - /* - * Check for backspace key using termios VERASE - the terminfo - * kbs entry is extremely unreliable, so cannot be safely - * used. termios should have a better idea. - */ - bspace = tty->tio.c_cc[VERASE]; - if (bspace != _POSIX_VDISABLE && key == bspace) - key = KEYC_BSPACE; - goto handle_key; - } - /* Is this device attributes response? */ switch (tty_keys_device(tty, buf, len, &size)) { case 0: /* yes */ - evbuffer_drain(tty->event->input, size); key = KEYC_NONE; - goto handle_key; + goto complete_key; case -1: /* no, or not valid */ break; case 1: /* partial */ @@ -476,9 +462,8 @@ tty_keys_next(struct tty *tty) /* Is this a mouse key press? */ switch (tty_keys_mouse(tty, buf, len, &size)) { case 0: /* yes */ - evbuffer_drain(tty->event->input, size); key = KEYC_MOUSE; - goto handle_key; + goto complete_key; case -1: /* no, or not valid */ break; case 1: /* partial */ @@ -488,8 +473,7 @@ tty_keys_next(struct tty *tty) /* Try to parse a key with an xterm-style modifier. */ switch (xterm_keys_find(buf, len, &size, &key)) { case 0: /* found */ - evbuffer_drain(tty->event->input, size); - goto handle_key; + goto complete_key; case -1: /* not found */ break; case 1: @@ -497,93 +481,90 @@ tty_keys_next(struct tty *tty) } /* Look for matching key string and return if found. */ - tk = tty_keys_find(tty, buf + 1, len - 1, &size); + tk = tty_keys_find(tty, buf, len, &size); if (tk != NULL) { + if (tk->next != NULL) + goto partial_key; key = tk->key; - goto found_key; + goto complete_key; } - /* Skip the escape. */ - buf++; - len--; + /* Is this a meta key? */ + if (len >= 2 && buf[0] == '\033') { + if (buf[1] != '\033') { + key = buf[1] | KEYC_ESCAPE; + size = 2; + goto complete_key; + } - /* Is there a normal key following? */ - if (len != 0 && *buf != '\033') { - key = *buf | KEYC_ESCAPE; - evbuffer_drain(tty->event->input, 2); - goto handle_key; - } - - /* Or a key string? */ - if (len > 1) { tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { - key = tk->key | KEYC_ESCAPE; size++; /* include escape */ - goto found_key; + if (tk->next != NULL) + goto partial_key; + key = tk->key; + if (key != KEYC_NONE) + key |= KEYC_ESCAPE; + goto complete_key; } } - /* Escape and then nothing useful - fall through. */ +first_key: + /* No key found, take first. */ + key = (u_char) *buf; + size = 1; + + /* + * Check for backspace key using termios VERASE - the terminfo + * kbs entry is extremely unreliable, so cannot be safely + * used. termios should have a better idea. + */ + bspace = tty->tio.c_cc[VERASE]; + if (bspace != _POSIX_VDISABLE && key == bspace) + key = KEYC_BSPACE; + + goto complete_key; partial_key: - /* - * Escape but no key string. If have already seen an escape and the - * timer has expired, give up waiting and send the escape. - */ - if ((tty->flags & TTY_ESCAPE) && - evtimer_initialized(&tty->key_timer) && - !evtimer_pending(&tty->key_timer, NULL)) { - evbuffer_drain(tty->event->input, 1); - key = '\033'; - goto handle_key; + log_debug("partial key %.*s", (int) len, buf); + + /* If timer is going, check for expiration. */ + if (tty->flags & TTY_TIMER) { + if (evtimer_initialized(&tty->key_timer) && + !evtimer_pending(&tty->key_timer, NULL)) + goto first_key; + return (0); } - /* Fall through to start the timer. */ - -start_timer: - /* If already waiting for timer, do nothing. */ - if (evtimer_initialized(&tty->key_timer) && - evtimer_pending(&tty->key_timer, NULL)) - return (0); - - /* Start the timer and wait for expiry or more data. */ + /* Get the time period. */ delay = options_get_number(&global_options, "escape-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; + /* Start the timer. */ if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); evtimer_set(&tty->key_timer, tty_keys_callback, tty); evtimer_add(&tty->key_timer, &tv); - tty->flags |= TTY_ESCAPE; + tty->flags |= TTY_TIMER; return (0); -found_key: - if (tk->next != NULL) { - /* Partial key. Start the timer if not already expired. */ - if (!(tty->flags & TTY_ESCAPE)) - goto start_timer; +complete_key: + log_debug("complete key %.*s %#x", (int) size, buf, key); - /* Otherwise, if no key, send the escape alone. */ - if (tk->key == KEYC_NONE) - goto partial_key; + /* Remove data from buffer. */ + evbuffer_drain(tty->event->input, size); - /* Or fall through to send the partial key found. */ - } - evbuffer_drain(tty->event->input, size + 1); - - goto handle_key; - -handle_key: + /* Remove key timer. */ if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); + tty->flags &= ~TTY_TIMER; + /* Fire the key. */ if (key != KEYC_NONE) server_client_handle_key(tty->client, key); - tty->flags &= ~TTY_ESCAPE; return (1); } @@ -594,11 +575,10 @@ tty_keys_callback(unused int fd, unused short events, void *data) { struct tty *tty = data; - if (!(tty->flags & TTY_ESCAPE)) - return; - - while (tty_keys_next(tty)) - ; + if (tty->flags & TTY_TIMER) { + while (tty_keys_next(tty)) + ; + } } /* From 49ac5b5fe0aa9bf41b9193790eecf7c3736ed4de Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 18:46:12 +0000 Subject: [PATCH 21/91] Do not include status line in size calculations in control mode. --- resize.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/resize.c b/resize.c index 5553ce9a..d398ab37 100644 --- a/resize.c +++ b/resize.c @@ -49,10 +49,12 @@ recalculate_sizes(void) struct client *c; struct window *w; struct window_pane *wp; - u_int i, j, ssx, ssy, has, limit; - int flag; + u_int i, j, ssx, ssy, has, limit; + int flag, has_status; RB_FOREACH(s, sessions, &sessions) { + has_status = options_get_number(&s->options, "status"); + ssx = ssy = UINT_MAX; for (j = 0; j < ARRAY_LENGTH(&clients); j++) { c = ARRAY_ITEM(&clients, j); @@ -61,7 +63,11 @@ recalculate_sizes(void) if (c->session == s) { if (c->tty.sx < ssx) ssx = c->tty.sx; - if (c->tty.sy < ssy) + if (has_status && + !(c->flags & CLIENT_CONTROL) && + c->tty.sy > 1 && c->tty.sy - 1 < ssy) + ssy = c->tty.sy - 1; + else if (c->tty.sy < ssy) ssy = c->tty.sy; } } @@ -71,17 +77,14 @@ recalculate_sizes(void) } s->flags &= ~SESSION_UNATTACHED; - if (options_get_number(&s->options, "status")) { - if (ssy == 0) - ssy = 1; - else - ssy--; - } + if (has_status && ssy == 0) + ssy = 1; + if (s->sx == ssx && s->sy == ssy) continue; - log_debug( - "session size %u,%u (was %u,%u)", ssx, ssy, s->sx, s->sy); + log_debug("session size %u,%u (was %u,%u)", ssx, ssy, s->sx, + s->sy); s->sx = ssx; s->sy = ssy; @@ -121,8 +124,8 @@ recalculate_sizes(void) if (w->sx == ssx && w->sy == ssy) continue; - log_debug( - "window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy); + log_debug("window size %u,%u (was %u,%u)", ssx, ssy, w->sx, + w->sy); layout_resize(w, ssx, ssy); window_resize(w, ssx, ssy); From c5504af4a685707389888db475fb7451ff5d8d86 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 18:47:01 +0000 Subject: [PATCH 22/91] Add various checks to turn off bits that can't work in control mode (such as lock). --- server-client.c | 13 ++++++++++--- server-fn.c | 3 +++ server-window.c | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/server-client.c b/server-client.c index 1cae4733..b88b134e 100644 --- a/server-client.c +++ b/server-client.c @@ -356,6 +356,7 @@ server_client_handle_key(struct client *c, int key) /* Check the client is good to accept input. */ if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) return; + if (c->session == NULL) return; s = c->session; @@ -529,6 +530,9 @@ server_client_reset_state(struct client *c) if (c->flags & CLIENT_SUSPENDED) return; + if (c->flags & CLIENT_CONTROL) + return; + tty_region(&c->tty, 0, c->tty.sy - 1); status = options_get_number(oo, "status"); @@ -626,7 +630,7 @@ server_client_check_redraw(struct client *c) struct window_pane *wp; int flags, redraw; - if (c->flags & CLIENT_SUSPENDED) + if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; flags = c->tty.flags & TTY_FREEZE; @@ -756,6 +760,8 @@ server_client_msg_dispatch(struct client *c) if (datalen != 0) fatalx("bad MSG_RESIZE size"); + if (c->flags & CLIENT_CONTROL) + break; if (tty_resize(&c->tty)) { recalculate_sizes(); server_redraw_client(c); @@ -925,7 +931,7 @@ server_client_msg_identify( if (data->flags & IDENTIFY_CONTROL) { c->stdin_callback = control_callback; - c->flags |= (CLIENT_CONTROL|CLIENT_SUSPENDED); + c->flags |= CLIENT_CONTROL; server_write_client(c, MSG_STDIN, NULL, 0); c->tty.fd = -1; @@ -950,7 +956,8 @@ server_client_msg_identify( tty_resize(&c->tty); - c->flags |= CLIENT_TERMINAL; + if (!(data->flags & IDENTIFY_CONTROL)) + c->flags |= CLIENT_TERMINAL; } /* Handle shell message. */ diff --git a/server-fn.c b/server-fn.c index c22095dc..69857263 100644 --- a/server-fn.c +++ b/server-fn.c @@ -239,6 +239,9 @@ server_lock_client(struct client *c) size_t cmdlen; struct msg_lock_data lockdata; + if (!(c->flags & CLIENT_CONTROL)) + return; + if (c->flags & CLIENT_SUSPENDED) return; diff --git a/server-window.c b/server-window.c index 8b34fc6c..e82f0e36 100644 --- a/server-window.c +++ b/server-window.c @@ -85,7 +85,7 @@ server_window_check_bell(struct session *s, struct winlink *wl) return (0); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) + if (c == NULL || c->session != s || (c->flags & CLIENT_CONTROL)) continue; if (!visual) { tty_bell(&c->tty); @@ -242,7 +242,7 @@ ring_bell(struct session *s) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session == s) + if (c != NULL && c->session == s && !(c->flags & CLIENT_CONTROL)) tty_bell(&c->tty); } } From 10682b9e7e4b38d6dcbf2f826737d7d2c7fbc0a0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 18:47:56 +0000 Subject: [PATCH 23/91] Instead of loads of little screen_write_*_on and off functions which just change mode flags, just have screen_write_mode_set and screen_write_mode_clear. --- input.c | 37 +++++++-------- screen-write.c | 120 +++++++++---------------------------------------- tmux.h | 12 ++--- 3 files changed, 44 insertions(+), 125 deletions(-) diff --git a/input.c b/input.c index 20917fa1..f44f602c 100644 --- a/input.c +++ b/input.c @@ -1033,10 +1033,10 @@ input_esc_dispatch(struct input_ctx *ictx) screen_write_reverseindex(sctx); break; case INPUT_ESC_DECKPAM: - screen_write_kkeypadmode(sctx, 1); + screen_write_mode_set(sctx, MODE_KKEYPAD); break; case INPUT_ESC_DECKPNM: - screen_write_kkeypadmode(sctx, 0); + screen_write_mode_clear(sctx, MODE_KKEYPAD); break; case INPUT_ESC_DECSC: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); @@ -1232,7 +1232,7 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_RM: switch (input_get(ictx, 0, 0, -1)) { case 4: /* IRM */ - screen_write_insertmode(&ictx->ctx, 0); + screen_write_mode_clear(&ictx->ctx, MODE_INSERT); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); @@ -1242,23 +1242,23 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_RM_PRIVATE: switch (input_get(ictx, 0, 0, -1)) { case 1: /* GATM */ - screen_write_kcursormode(&ictx->ctx, 0); + screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR); break; case 3: /* DECCOLM */ screen_write_cursormove(&ictx->ctx, 0, 0); screen_write_clearscreen(&ictx->ctx); break; case 25: /* TCEM */ - screen_write_cursormode(&ictx->ctx, 0); + screen_write_mode_clear(&ictx->ctx, MODE_CURSOR); break; case 1000: case 1001: case 1002: case 1003: - screen_write_mousemode_off(&ictx->ctx); + screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); break; case 1005: - screen_write_utf8mousemode(&ictx->ctx, 0); + screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8); break; case 47: case 1047: @@ -1268,7 +1268,7 @@ input_csi_dispatch(struct input_ctx *ictx) window_pane_alternate_off(wp, &ictx->cell, 1); break; case 2004: - screen_write_bracketpaste(&ictx->ctx, 0); + screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); @@ -1286,7 +1286,7 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_SM: switch (input_get(ictx, 0, 0, -1)) { case 4: /* IRM */ - screen_write_insertmode(&ictx->ctx, 1); + screen_write_mode_set(&ictx->ctx, MODE_INSERT); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); @@ -1296,28 +1296,29 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_SM_PRIVATE: switch (input_get(ictx, 0, 0, -1)) { case 1: /* GATM */ - screen_write_kcursormode(&ictx->ctx, 1); + screen_write_mode_set(&ictx->ctx, MODE_KCURSOR); break; case 3: /* DECCOLM */ screen_write_cursormove(&ictx->ctx, 0, 0); screen_write_clearscreen(&ictx->ctx); break; case 25: /* TCEM */ - screen_write_cursormode(&ictx->ctx, 1); + screen_write_mode_set(&ictx->ctx, MODE_CURSOR); break; case 1000: - screen_write_mousemode_on( - &ictx->ctx, MODE_MOUSE_STANDARD); + screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); + screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD); break; case 1002: - screen_write_mousemode_on( - &ictx->ctx, MODE_MOUSE_BUTTON); + screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); + screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON); break; case 1003: - screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY); + screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); + screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY); break; case 1005: - screen_write_utf8mousemode(&ictx->ctx, 1); + screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); break; case 47: case 1047: @@ -1327,7 +1328,7 @@ input_csi_dispatch(struct input_ctx *ictx) window_pane_alternate_on(wp, &ictx->cell, 1); break; case 2004: - screen_write_bracketpaste(&ictx->ctx, 1); + screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); diff --git a/screen-write.c b/screen-write.c index e68e498d..9cbb5bb9 100644 --- a/screen-write.c +++ b/screen-write.c @@ -52,14 +52,11 @@ screen_write_stop(unused struct screen_write_ctx *ctx) void screen_write_reset(struct screen_write_ctx *ctx) { - screen_reset_tabs(ctx->s); + struct screen *s = ctx->s; - screen_write_scrollregion(ctx, 0, screen_size_y(ctx->s) - 1); - - screen_write_insertmode(ctx, 0); - screen_write_kcursormode(ctx, 0); - screen_write_kkeypadmode(ctx, 0); - screen_write_mousemode_off(ctx); + screen_reset_tabs(s); + screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); + s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|ALL_MOUSE_MODES); screen_write_clearscreen(ctx); screen_write_cursormove(ctx, 0, 0); @@ -454,6 +451,24 @@ screen_write_initctx( memcpy(&ttyctx->last_cell, gc, sizeof ttyctx->last_cell); } +/* Set a mode. */ +void +screen_write_mode_set(struct screen_write_ctx *ctx, int mode) +{ + struct screen *s = ctx->s; + + s->mode |= mode; +} + +/* Clear a mode. */ +void +screen_write_mode_clear(struct screen_write_ctx *ctx, int mode) +{ + struct screen *s = ctx->s; + + s->mode &= ~mode; +} + /* Cursor up by ny. */ void screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) @@ -805,18 +820,6 @@ screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) s->cy = py; } -/* Set cursor mode. */ -void -screen_write_cursormode(struct screen_write_ctx *ctx, int state) -{ - struct screen *s = ctx->s; - - if (state) - s->mode |= MODE_CURSOR; - else - s->mode &= ~MODE_CURSOR; -} - /* Reverse index (up with scroll). */ void screen_write_reverseindex(struct screen_write_ctx *ctx) @@ -856,61 +859,6 @@ screen_write_scrollregion( s->rlower = rlower; } -/* Set insert mode. */ -void -screen_write_insertmode(struct screen_write_ctx *ctx, int state) -{ - struct screen *s = ctx->s; - - if (state) - s->mode |= MODE_INSERT; - else - s->mode &= ~MODE_INSERT; -} - -/* Set UTF-8 mouse mode. */ -void -screen_write_utf8mousemode(struct screen_write_ctx *ctx, int state) -{ - struct screen *s = ctx->s; - - if (state) - s->mode |= MODE_MOUSE_UTF8; - else - s->mode &= ~MODE_MOUSE_UTF8; -} - -/* Set mouse mode off. */ -void -screen_write_mousemode_off(struct screen_write_ctx *ctx) -{ - struct screen *s = ctx->s; - - s->mode &= ~ALL_MOUSE_MODES; -} - -/* Set mouse mode on. */ -void -screen_write_mousemode_on(struct screen_write_ctx *ctx, int mode) -{ - struct screen *s = ctx->s; - - s->mode &= ~ALL_MOUSE_MODES; - s->mode |= mode; -} - -/* Set bracketed paste mode. */ -void -screen_write_bracketpaste(struct screen_write_ctx *ctx, int state) -{ - struct screen *s = ctx->s; - - if (state) - s->mode |= MODE_BRACKETPASTE; - else - s->mode &= ~MODE_BRACKETPASTE; -} - /* Line feed. */ void screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) @@ -945,30 +893,6 @@ screen_write_carriagereturn(struct screen_write_ctx *ctx) s->cx = 0; } -/* Set keypad cursor keys mode. */ -void -screen_write_kcursormode(struct screen_write_ctx *ctx, int state) -{ - struct screen *s = ctx->s; - - if (state) - s->mode |= MODE_KCURSOR; - else - s->mode &= ~MODE_KCURSOR; -} - -/* Set keypad number keys mode. */ -void -screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state) -{ - struct screen *s = ctx->s; - - if (state) - s->mode |= MODE_KKEYPAD; - else - s->mode &= ~MODE_KKEYPAD; -} - /* Clear to end of screen from cursor. */ void screen_write_clearendofscreen(struct screen_write_ctx *ctx) diff --git a/tmux.h b/tmux.h index 1a2b4155..afe55560 100644 --- a/tmux.h +++ b/tmux.h @@ -1206,7 +1206,7 @@ struct tty { #define TTY_NOCURSOR 0x1 #define TTY_FREEZE 0x2 -#define TTY_ESCAPE 0x4 +#define TTY_TIMER 0x4 #define TTY_UTF8 0x8 #define TTY_STARTED 0x10 #define TTY_OPENED 0x20 @@ -2016,6 +2016,8 @@ void screen_write_putc( void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int, u_int, u_int, u_int); void screen_write_backspace(struct screen_write_ctx *); +void screen_write_mode_set(struct screen_write_ctx *, int); +void screen_write_mode_clear(struct screen_write_ctx *, int); void screen_write_cursorup(struct screen_write_ctx *, u_int); void screen_write_cursordown(struct screen_write_ctx *, u_int); void screen_write_cursorright(struct screen_write_ctx *, u_int); @@ -2030,18 +2032,11 @@ void screen_write_clearline(struct screen_write_ctx *); void screen_write_clearendofline(struct screen_write_ctx *); void screen_write_clearstartofline(struct screen_write_ctx *); void screen_write_cursormove(struct screen_write_ctx *, u_int, u_int); -void screen_write_cursormode(struct screen_write_ctx *, int); void screen_write_reverseindex(struct screen_write_ctx *); void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); -void screen_write_insertmode(struct screen_write_ctx *, int); -void screen_write_utf8mousemode(struct screen_write_ctx *, int); -void screen_write_mousemode_on(struct screen_write_ctx *, int); -void screen_write_mousemode_off(struct screen_write_ctx *); void screen_write_linefeed(struct screen_write_ctx *, int); void screen_write_linefeedscreen(struct screen_write_ctx *, int); void screen_write_carriagereturn(struct screen_write_ctx *); -void screen_write_kcursormode(struct screen_write_ctx *, int); -void screen_write_kkeypadmode(struct screen_write_ctx *, int); void screen_write_clearendofscreen(struct screen_write_ctx *); void screen_write_clearstartofscreen(struct screen_write_ctx *); void screen_write_clearscreen(struct screen_write_ctx *); @@ -2049,7 +2044,6 @@ void screen_write_clearhistory(struct screen_write_ctx *); void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *); void screen_write_setselection(struct screen_write_ctx *, u_char *, u_int); void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int); -void screen_write_bracketpaste(struct screen_write_ctx *, int); /* screen-redraw.c */ void screen_redraw_screen(struct client *, int, int); From 306a3b8d8070146e22e26866390f9901fa1b7c4e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:30:04 +0000 Subject: [PATCH 24/91] In terminals with XT, turn on modifyOtherKeys=1 with the escape sequence and handle the most common set. Pass them through if xterm-keys is on. --- key-string.c | 11 ++++++----- xterm-keys.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/key-string.c b/key-string.c index e06a71eb..7aba190b 100644 --- a/key-string.c +++ b/key-string.c @@ -136,9 +136,10 @@ key_string_get_modifiers(const char **string) int key_string_lookup_string(const char *string) { - int key, modifiers; - u_short u; - int size; + static const char *other = "!#()+,-.0123456789:;<=>?'\r\t"; + int key, modifiers; + u_short u; + int size; /* Is this a hexadecimal value? */ if (string[0] == '0' && string[1] == 'x') { @@ -170,7 +171,7 @@ key_string_lookup_string(const char *string) } /* Convert the standard control keys. */ - if (key < KEYC_BASE && (modifiers & KEYC_CTRL)) { + if (key < KEYC_BASE && (modifiers & KEYC_CTRL) && !strchr(other, key)) { if (key >= 97 && key <= 122) key -= 96; else if (key >= 64 && key <= 95) @@ -193,7 +194,7 @@ key_string_lookup_key(int key) { static char out[24]; char tmp[8]; - u_int i; + u_int i; *out = '\0'; diff --git a/xterm-keys.c b/xterm-keys.c index 1956c0b4..75eb6751 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -87,6 +87,34 @@ const struct xterm_keys_entry xterm_keys_table[] = { { KEYC_NPAGE, "\033[6;_~" }, { KEYC_IC, "\033[2;_~" }, { KEYC_DC, "\033[3;_~" }, + + { '!', "\033[27;_;33~" }, + { '#', "\033[27;_;35~" }, + { '(', "\033[27;_;40~" }, + { ')', "\033[27;_;41~" }, + { '+', "\033[27;_;43~" }, + { ',', "\033[27;_;44~" }, + { '-', "\033[27;_;45~" }, + { '.', "\033[27;_;46~" }, + { '0', "\033[27;_;48~" }, + { '1', "\033[27;_;49~" }, + { '2', "\033[27;_;50~" }, + { '3', "\033[27;_;51~" }, + { '4', "\033[27;_;52~" }, + { '5', "\033[27;_;53~" }, + { '6', "\033[27;_;54~" }, + { '7', "\033[27;_;55~" }, + { '8', "\033[27;_;56~" }, + { '9', "\033[27;_;57~" }, + { ':', "\033[27;_;58~" }, + { ';', "\033[27;_;59~" }, + { '<', "\033[27;_;60~" }, + { '=', "\033[27;_;61~" }, + { '>', "\033[27;_;62~" }, + { '?', "\033[27;_;63~" }, + { '\'', "\033[27;_;39~" }, + { '\r', "\033[27;_;13~" }, + { '\t', "\033[27;_;9~" }, }; /* From 8d59b189cc9e83ac0049fc3108de1b822fa7b4ce Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:31:22 +0000 Subject: [PATCH 25/91] No more lint means no more ARGSUSED. --- cfg.c | 2 -- client.c | 4 ---- cmd-kill-server.c | 1 - cmd-list-buffers.c | 1 - cmd-list-clients.c | 1 - cmd-list-commands.c | 1 - cmd-lock-server.c | 1 - cmd-pipe-pane.c | 1 - cmd-server-info.c | 1 - cmd-start-server.c | 1 - job.c | 1 - names.c | 1 - server-client.c | 1 - server-fn.c | 1 - server.c | 3 --- status.c | 1 - window-choose.c | 2 -- window-clock.c | 1 - window-copy.c | 1 - window.c | 2 -- 20 files changed, 28 deletions(-) diff --git a/cfg.c b/cfg.c index aa2ceea4..1967fe99 100644 --- a/cfg.c +++ b/cfg.c @@ -40,13 +40,11 @@ int cfg_finished; int cfg_references; struct causelist cfg_causes; -/* ARGSUSED */ void printflike2 cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...) { } -/* ARGSUSED */ void printflike2 cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) { diff --git a/client.c b/client.c index 90993057..92c3fca3 100644 --- a/client.c +++ b/client.c @@ -360,7 +360,6 @@ client_update_event(void) } /* Callback to handle signals in the client. */ -/* ARGSUSED */ void client_signal(int sig, unused short events, unused void *data) { @@ -407,7 +406,6 @@ client_signal(int sig, unused short events, unused void *data) } /* Callback for client imsg read events. */ -/* ARGSUSED */ void client_callback(unused int fd, short events, void *data) { @@ -442,7 +440,6 @@ lost_server: } /* Callback for client stdin read events. */ -/* ARGSUSED */ void client_stdin_callback(unused int fd, unused short events, unused void *data1) { @@ -571,7 +568,6 @@ client_dispatch_wait(void *data) } /* Dispatch imsgs in attached state (after MSG_READY). */ -/* ARGSUSED */ int client_dispatch_attached(void) { diff --git a/cmd-kill-server.c b/cmd-kill-server.c index 6761dac4..fcf1e25c 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_kill_server_entry = { cmd_kill_server_exec }; -/* ARGSUSED */ enum cmd_retval cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index e7f4b735..b1d59f2f 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_list_buffers_entry = { cmd_list_buffers_exec }; -/* ARGSUSED */ enum cmd_retval cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 92d25a9d..70f6c809 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -40,7 +40,6 @@ const struct cmd_entry cmd_list_clients_entry = { cmd_list_clients_exec }; -/* ARGSUSED */ enum cmd_retval cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 261acefb..05a31ec5 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_list_commands_entry = { cmd_list_commands_exec }; -/* ARGSUSED */ enum cmd_retval cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 7a9ced33..16a34a44 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -60,7 +60,6 @@ const struct cmd_entry cmd_lock_client_entry = { cmd_lock_server_exec }; -/* ARGSUSED */ enum cmd_retval cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx) { diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index bf89e51a..a332b0ca 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -131,7 +131,6 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } -/* ARGSUSED */ void cmd_pipe_pane_error_callback( unused struct bufferevent *bufev, unused short what, void *data) diff --git a/cmd-server-info.c b/cmd-server-info.c index f434f942..cefb70f4 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -43,7 +43,6 @@ const struct cmd_entry cmd_server_info_entry = { cmd_server_info_exec }; -/* ARGSUSED */ enum cmd_retval cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) { diff --git a/cmd-start-server.c b/cmd-start-server.c index eb6143c1..ae425a73 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_start_server_entry = { cmd_start_server_exec }; -/* ARGSUSED */ enum cmd_retval cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) { diff --git a/job.c b/job.c index bc630128..64deeeab 100644 --- a/job.c +++ b/job.c @@ -134,7 +134,6 @@ job_free(struct job *job) } /* Job buffer error callback. */ -/* ARGSUSED */ void job_callback(unused struct bufferevent *bufev, unused short events, void *data) { diff --git a/names.c b/names.c index 1eb6a675..76dec82c 100644 --- a/names.c +++ b/names.c @@ -43,7 +43,6 @@ queue_window_name(struct window *w) evtimer_add(&w->name_timer, &tv); } -/* ARGSUSED */ void window_name_callback(unused int fd, unused short events, void *data) { diff --git a/server-client.c b/server-client.c index b88b134e..fc3989d9 100644 --- a/server-client.c +++ b/server-client.c @@ -587,7 +587,6 @@ server_client_reset_state(struct client *c) } /* Repeat time callback. */ -/* ARGSUSED */ void server_client_repeat_timer(unused int fd, unused short events, void *data) { diff --git a/server-fn.c b/server-fn.c index 69857263..fe5ed431 100644 --- a/server-fn.c +++ b/server-fn.c @@ -494,7 +494,6 @@ server_clear_identify(struct client *c) } } -/* ARGSUSED */ void server_callback_identify(unused int fd, unused short events, void *data) { diff --git a/server.c b/server.c index a3632ad7..994f3968 100644 --- a/server.c +++ b/server.c @@ -316,7 +316,6 @@ server_update_socket(void) } /* Callback for server socket. */ -/* ARGSUSED */ void server_accept_callback(int fd, short events, unused void *data) { @@ -370,7 +369,6 @@ server_add_accept(int timeout) } /* Signal handler. */ -/* ARGSUSED */ void server_signal_callback(int sig, unused short events, unused void *data) { @@ -466,7 +464,6 @@ server_child_stopped(pid_t pid, int status) } /* Handle once-per-second timer events. */ -/* ARGSUSED */ void server_second_callback(unused int fd, unused short events, unused void *arg) { diff --git a/status.c b/status.c index d9545218..0bee54e9 100644 --- a/status.c +++ b/status.c @@ -829,7 +829,6 @@ status_message_clear(struct client *c) } /* Clear status line message after timer expires. */ -/* ARGSUSED */ void status_message_callback(unused int fd, unused short event, void *data) { diff --git a/window-choose.c b/window-choose.c index d89386b0..22078bfd 100644 --- a/window-choose.c +++ b/window-choose.c @@ -480,7 +480,6 @@ window_choose_expand(struct window_pane *wp, struct session *s, u_int pos) } } -/* ARGSUSED */ void window_choose_key(struct window_pane *wp, unused struct session *sess, int key) { @@ -686,7 +685,6 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) } } -/* ARGSUSED */ void window_choose_mouse( struct window_pane *wp, unused struct session *sess, struct mouse_event *m) diff --git a/window-clock.c b/window-clock.c index 4cbe76a5..8ec1671e 100644 --- a/window-clock.c +++ b/window-clock.c @@ -83,7 +83,6 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy) window_clock_draw_screen(wp); } -/* ARGSUSED */ void window_clock_key( struct window_pane *wp, unused struct session *sess, unused int key) diff --git a/window-copy.c b/window-copy.c index 1d6b8f67..0cff3e13 100644 --- a/window-copy.c +++ b/window-copy.c @@ -814,7 +814,6 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key) return (0); } -/* ARGSUSED */ void window_copy_mouse( struct window_pane *wp, struct session *sess, struct mouse_event *m) diff --git a/window.c b/window.c index 20cd9aa3..79ade400 100644 --- a/window.c +++ b/window.c @@ -802,7 +802,6 @@ window_pane_timer_callback(unused int fd, unused short events, void *data) wp->changes = 0; } -/* ARGSUSED */ void window_pane_read_callback(unused struct bufferevent *bufev, void *data) { @@ -829,7 +828,6 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data) fatal("gettimeofday failed."); } -/* ARGSUSED */ void window_pane_error_callback( unused struct bufferevent *bufev, unused short what, void *data) From ad760b3bf702801eaa121715f2a283526d614913 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:32:36 +0000 Subject: [PATCH 26/91] Add client_session and client_last_session formats. --- format.c | 12 ++++++++++-- tmux.1 | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/format.c b/format.c index f005c1c4..9e3bc86a 100644 --- a/format.c +++ b/format.c @@ -301,8 +301,9 @@ format_session(struct format_tree *ft, struct session *s) void format_client(struct format_tree *ft, struct client *c) { - char *tim; - time_t t; + char *tim; + time_t t; + struct session *s; format_add(ft, "client_cwd", "%s", c->cwd); format_add(ft, "client_height", "%u", c->tty.sy); @@ -333,6 +334,13 @@ format_client(struct format_tree *ft, struct client *c) format_add(ft, "client_readonly", "%d", 1); else format_add(ft, "client_readonly", "%d", 0); + + s = c->session; + if (s != NULL) + format_add(ft, "client_session", "%s", s->name); + s = c->last_session; + if (s != NULL && session_alive(s)) + format_add(ft, "client_last_session", "%s", s->name); } /* Set default format keys for a winlink. */ diff --git a/tmux.1 b/tmux.1 index 72001997..acb1a4c1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2964,8 +2964,10 @@ The following variables are available, where appropriate: .It Li "client_created_string" Ta "String time client created" .It Li "client_cwd" Ta "Working directory of client" .It Li "client_height" Ta "Height of client" +.It Li "client_last_session" Ta "Name of the client's last session" .It Li "client_prefix" Ta "1 if prefix key has been pressed" .It Li "client_readonly" Ta "1 if client is readonly" +.It Li "client_session" Ta "Name of the client's session" .It Li "client_termname" Ta "Terminal name of client" .It Li "client_tty" Ta "Pseudo terminal of client" .It Li "client_utf8" Ta "1 if client supports utf8" From 67b4d5b6094c8845af344d1386bb3fed86f54b5a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:33:50 +0000 Subject: [PATCH 27/91] Support the latest theory for mouse input, this is enabled/disabled with SM/RM 1006 and is similar in style to SGR input: \033[screen->mode & ALL_MOUSE_MODES) { - if (wp->screen->mode & MODE_MOUSE_UTF8) { + /* + * Use the SGR (1006) extension only if the application + * requested it and the underlying terminal also sent the event + * in this format (this is because an old style mouse release + * event cannot be converted into the new SGR format, since the + * released button is unknown). Otherwise pretend that tmux + * doesn't speak this extension, and fall back to the UTF-8 + * (1005) extension if the application requested, or to the + * legacy format. + */ + if (m->sgr && (wp->screen->mode & MODE_MOUSE_SGR)) { + len = xsnprintf(buf, sizeof buf, "\033[<%d;%d;%d%c", + m->sgr_xb, m->x + 1, m->y + 1, m->sgr_rel ? 'm' : 'M'); + } else if (wp->screen->mode & MODE_MOUSE_UTF8) { len = xsnprintf(buf, sizeof buf, "\033[M"); len += utf8_split2(m->xb + 32, &buf[len]); len += utf8_split2(m->x + 33, &buf[len]); diff --git a/input.c b/input.c index f44f602c..30f4f95d 100644 --- a/input.c +++ b/input.c @@ -1260,6 +1260,9 @@ input_csi_dispatch(struct input_ctx *ictx) case 1005: screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8); break; + case 1006: + screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR); + break; case 47: case 1047: window_pane_alternate_off(wp, &ictx->cell, 0); @@ -1320,6 +1323,9 @@ input_csi_dispatch(struct input_ctx *ictx) case 1005: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); break; + case 1006: + screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR); + break; case 47: case 1047: window_pane_alternate_on(wp, &ictx->cell, 0); diff --git a/screen-write.c b/screen-write.c index 9cbb5bb9..bee6f6d7 100644 --- a/screen-write.c +++ b/screen-write.c @@ -41,7 +41,6 @@ screen_write_start( } /* Finish writing. */ -/* ARGSUSED */ void screen_write_stop(unused struct screen_write_ctx *ctx) { @@ -56,7 +55,9 @@ screen_write_reset(struct screen_write_ctx *ctx) screen_reset_tabs(s); screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); - s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|ALL_MOUSE_MODES); + + s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD); + s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR); screen_write_clearscreen(ctx); screen_write_cursormove(ctx, 0, 0); diff --git a/tmux.h b/tmux.h index afe55560..192a386f 100644 --- a/tmux.h +++ b/tmux.h @@ -665,7 +665,8 @@ struct mode_key_table { #define MODE_MOUSE_BUTTON 0x40 #define MODE_MOUSE_ANY 0x80 #define MODE_MOUSE_UTF8 0x100 -#define MODE_BRACKETPASTE 0x200 +#define MODE_MOUSE_SGR 0x200 +#define MODE_BRACKETPASTE 0x400 #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) @@ -1153,6 +1154,9 @@ LIST_HEAD(tty_terms, tty_term); * - bits 3, 4 and 5 are for keys * - bit 6 is set for dragging * - bit 7 for buttons 4 and 5 + * + * With the SGR 1006 extension the released button becomes known. Store these + * in separate fields and store the value converted to the old format in xb. */ struct mouse_event { u_int xb; @@ -1165,6 +1169,10 @@ struct mouse_event { u_int ly; u_int sy; + u_int sgr; /* whether the input arrived in SGR format */ + u_int sgr_xb; /* only for SGR: the unmangled button */ + u_int sgr_rel; /* only for SGR: whether it is a release event */ + u_int button; u_int clicks; diff --git a/tty-keys.c b/tty-keys.c index 7fb96786..cb34df93 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -364,8 +364,6 @@ tty_keys_build(struct tty *tty) tty_keys_add(tty, s, tdkc->key); } - - tty_keys_add(tty, "abc", 'x'); } /* Free the entire key tree. */ @@ -569,7 +567,6 @@ complete_key: } /* Key timer callback. */ -/* ARGSUSED */ void tty_keys_callback(unused int fd, unused short events, void *data) { @@ -590,20 +587,26 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) { struct mouse_event *m = &tty->mouse; struct utf8_data utf8data; - u_int i, value, x, y, b; + u_int i, value, x, y, b, sgr, sgr_b, sgr_rel; + unsigned char c; /* * Standard mouse sequences are \033[M followed by three characters - * indicating buttons, X and Y, all based at 32 with 1,1 top-left. + * indicating button, X and Y, all based at 32 with 1,1 top-left. * * UTF-8 mouse sequences are similar but the three are expressed as * UTF-8 characters. + * + * SGR extended mouse sequences are \033[< followed by three numbers in + * decimal and separated by semicolons indicating button, X and Y. A + * trailing 'M' is click or scroll and trailing 'm' release. All are + * based at 0 with 1,1 top-left. */ *size = 0; - x = y = b = 0; + x = y = b = sgr = sgr_b = sgr_rel = 0; - /* First three bytes are always \033[M. */ + /* First two bytes are always \033[. */ if (buf[0] != '\033') return (-1); if (len == 1) @@ -612,50 +615,99 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) return (-1); if (len == 2) return (1); - if (buf[2] != 'M') - return (-1); - if (len == 3) - return (1); - /* Read the three inputs. */ - *size = 3; - for (i = 0; i < 3; i++) { - if (len < *size) - return (1); + /* + * Third byte is M in old standard and UTF-8 extension, < in SGR + * extension. + */ + if (buf[2] == 'M') { + /* Read the three inputs. */ + *size = 3; + for (i = 0; i < 3; i++) { + if (len <= *size) + return (1); - if (tty->mode & MODE_MOUSE_UTF8) { - if (utf8_open(&utf8data, buf[*size])) { - if (utf8data.size != 2) - return (-1); + if (tty->mode & MODE_MOUSE_UTF8) { + if (utf8_open(&utf8data, buf[*size])) { + if (utf8data.size != 2) + return (-1); + (*size)++; + if (len <= *size) + return (1); + utf8_append(&utf8data, buf[*size]); + value = utf8_combine(&utf8data); + } else + value = (u_char) buf[*size]; (*size)++; - if (len < *size) - return (1); - utf8_append(&utf8data, buf[*size]); - value = utf8_combine(&utf8data); - } else - value = (unsigned char)buf[*size]; - (*size)++; - } else { - value = (unsigned char)buf[*size]; - (*size)++; + } else { + value = (u_char) buf[*size]; + (*size)++; + } + + if (i == 0) + b = value; + else if (i == 1) + x = value; + else + y = value; } + log_debug("mouse input: %.*s", (int) *size, buf); - if (i == 0) - b = value; - else if (i == 1) - x = value; - else - y = value; - } - log_debug("mouse input: %.*s", (int) *size, buf); + /* Check and return the mouse input. */ + if (b < 32 || x < 33 || y < 33) + return (-1); + b -= 32; + x -= 33; + y -= 33; + } else if (buf[2] == '<') { + /* Read the three inputs. */ + *size = 3; + while (1) { + if (len <= *size) + return (1); + c = (u_char)buf[(*size)++]; + if (c == ';') + break; + if (c < '0' || c > '9') + return (-1); + sgr_b = 10 * sgr_b + (c - '0'); + } + while (1) { + if (len <= *size) + return (1); + c = (u_char)buf[(*size)++]; + if (c == ';') + break; + if (c < '0' || c > '9') + return (-1); + x = 10 * x + (c - '0'); + } + while (1) { + if (len <= *size) + return (1); + c = (u_char) buf[(*size)++]; + if (c == 'M' || c == 'm') + break; + if (c < '0' || c > '9') + return (-1); + y = 10 * y + (c - '0'); + } + log_debug("mouse input (sgr): %.*s", (int) *size, buf); - /* Check and return the mouse input. */ - if (b < 32 || x < 33 || y < 33) + /* Check and return the mouse input. */ + if (x < 1 || y < 1) + return (-1); + x--; + y--; + sgr = 1; + sgr_rel = (c == 'm'); + + /* Figure out what b would be in old format. */ + b = sgr_b; + if (sgr_rel) + b |= 3; + } else return (-1); - b -= 32; - x -= 33; - y -= 33; - log_debug("mouse position: x=%u y=%u b=%u", x, y, b); /* Fill in mouse structure. */ if (~m->event & MOUSE_EVENT_WHEEL) { @@ -663,6 +715,9 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) m->ly = m->y; } m->xb = b; + m->sgr = sgr; + m->sgr_xb = sgr_b; + m->sgr_rel = sgr_rel; if (b & 64) { /* wheel button */ b &= 3; if (b == 0) From 22a2949bd23eaee1ceddc4b92da3c9fcf6c3864b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:34:46 +0000 Subject: [PATCH 28/91] Correctly handle UTF8 mouse option being toggled, from Egmont Koblinger. --- tty.c | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/tty.c b/tty.c index 0749b510..6be902f4 100644 --- a/tty.c +++ b/tty.c @@ -161,7 +161,6 @@ tty_open(struct tty *tty, const char *overrides, char **cause) return (0); } -/* ARGSUSED */ void tty_read_callback(unused struct bufferevent *bufev, void *data) { @@ -171,7 +170,6 @@ tty_read_callback(unused struct bufferevent *bufev, void *data) ; } -/* ARGSUSED */ void tty_error_callback( unused struct bufferevent *bufev, unused short what, unused void *data) @@ -220,10 +218,10 @@ tty_start_tty(struct tty *tty) tty_putcode(tty, TTYC_CNORM); if (tty_term_has(tty->term, TTYC_KMOUS)) - tty_puts(tty, "\033[?1000l"); + tty_puts(tty, "\033[?1000l\033[?1006l\033[?1005l"); if (tty_term_has(tty->term, TTYC_XT)) - tty_puts(tty, "\033[c"); + tty_puts(tty, "\033[c\033[>4;1m"); tty->cx = UINT_MAX; tty->cy = UINT_MAX; @@ -267,8 +265,6 @@ tty_stop_tty(struct tty *tty) if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) return; - setblocking(tty->fd, 1); - tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); if (tty_use_acs(tty)) tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); @@ -285,9 +281,14 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); if (tty_term_has(tty->term, TTYC_KMOUS)) - tty_raw(tty, "\033[?1000l"); + tty_raw(tty, "\033[?1000l\033[?1006l\033[?1005l"); + + if (tty_term_has(tty->term, TTYC_XT)) + tty_puts(tty, "\033[>4m"); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); + + setblocking(tty->fd, 1); } void @@ -332,7 +333,21 @@ tty_free(struct tty *tty) void tty_raw(struct tty *tty, const char *s) { - write(tty->fd, s, strlen(s)); + ssize_t n, slen; + u_int i; + + slen = strlen(s); + for (i = 0; i < 5; i++) { + n = write(tty->fd, s, slen); + if (n >= 0) { + s += n; + slen -= n; + if (slen == 0) + break; + } else if (n == -1 && errno != EAGAIN) + break; + usleep(100); + } } void @@ -474,10 +489,21 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) } tty->cstyle = s->cstyle; } - if (changed & ALL_MOUSE_MODES) { + if (changed & (ALL_MOUSE_MODES|MODE_MOUSE_UTF8)) { if (mode & ALL_MOUSE_MODES) { + /* + * Enable the UTF-8 (1005) extension if configured to. + * Enable the SGR (1006) extension unconditionally, as + * this is safe from misinterpretation. Do it in this + * order, because in some terminals it's the last one + * that takes effect and SGR is the preferred one. + */ if (mode & MODE_MOUSE_UTF8) tty_puts(tty, "\033[?1005h"); + else + tty_puts(tty, "\033[?1005l"); + tty_puts(tty, "\033[?1006h"); + if (mode & MODE_MOUSE_ANY) tty_puts(tty, "\033[?1003h"); else if (mode & MODE_MOUSE_BUTTON) @@ -491,6 +517,8 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) tty_puts(tty, "\033[?1002l"); else if (tty->mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000l"); + + tty_puts(tty, "\033[?1006l"); if (tty->mode & MODE_MOUSE_UTF8) tty_puts(tty, "\033[?1005l"); } From ad5df9bc2f00b3de89e1c2bd6714022cf99aacda Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:36:53 +0000 Subject: [PATCH 29/91] Implement DECAWM (SM/RM 7) using existing MODE_WRAP flag. --- input.c | 6 ++++++ screen-write.c | 23 +++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/input.c b/input.c index 30f4f95d..d345a0c4 100644 --- a/input.c +++ b/input.c @@ -1248,6 +1248,9 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_cursormove(&ictx->ctx, 0, 0); screen_write_clearscreen(&ictx->ctx); break; + case 7: /* DECAWM */ + screen_write_mode_clear(&ictx->ctx, MODE_WRAP); + break; case 25: /* TCEM */ screen_write_mode_clear(&ictx->ctx, MODE_CURSOR); break; @@ -1305,6 +1308,9 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_cursormove(&ictx->ctx, 0, 0); screen_write_clearscreen(&ictx->ctx); break; + case 7: /* DECAWM */ + screen_write_mode_set(&ictx->ctx, MODE_WRAP); + break; case 25: /* TCEM */ screen_write_mode_set(&ictx->ctx, MODE_CURSOR); break; diff --git a/screen-write.c b/screen-write.c index bee6f6d7..34dce95e 100644 --- a/screen-write.c +++ b/screen-write.c @@ -979,10 +979,10 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; - u_int width, xx; + u_int width, xx, last; struct grid_cell tmp_gc, *tmp_gcp; struct utf8_data ud; - int insert = 0; + int insert; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) @@ -1020,7 +1020,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) xx = screen_size_x(s) - s->cx - width; grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); insert = 1; - } + } else + insert = 0; /* Check this will fit on the current line and wrap if not. */ if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) { @@ -1028,9 +1029,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) s->cx = 0; /* carriage return */ } - /* Sanity checks. */ - if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) - || s->cy > screen_size_y(s) - 1) + /* Sanity check cursor position. */ + if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1) return; /* Handle overwriting of UTF-8 characters. */ @@ -1049,8 +1049,15 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) /* Set the cell. */ grid_view_set_cell(gd, s->cx, s->cy, gc); - /* Move the cursor. */ - s->cx += width; + /* + * Move the cursor. If not wrapping, stick at the last character and + * replace it. + */ + last = !!(s->mode & MODE_WRAP); + if (s->cx <= screen_size_x(s) - last - width) + s->cx += width; + else + s->cx = screen_size_x(s) - last; /* Draw to the screen if necessary. */ if (insert) { From f0efa576e002e77dc6363e0a5bc41d0c0649c946 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:37:39 +0000 Subject: [PATCH 30/91] Add resize-pane -x and -y for absolute pane size (much requested). --- cmd-resize-pane.c | 27 +++++++++++++++++++++++++-- layout.c | 36 ++++++++++++++++++++++++++++++++++++ tmux.1 | 20 ++++++++++++++------ tmux.h | 10 ++++++---- 4 files changed, 81 insertions(+), 12 deletions(-) diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index c200ee10..dbcebbcf 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", - "DLRt:U", 0, 1, - "[-DLRU] " CMD_TARGET_PANE_USAGE " [adjustment]", + "DLRt:Ux:y:", 0, 1, + "[-DLRU] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]", 0, cmd_resize_pane_key_binding, NULL, @@ -87,8 +87,10 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct winlink *wl; const char *errstr; + char *cause; struct window_pane *wp; u_int adjust; + int x, y; if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); @@ -103,6 +105,27 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } + if (args_has(self->args, 'x')) { + x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX, + &cause); + if (cause != NULL) { + ctx->error(ctx, "width %s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x); + } + if (args_has(self->args, 'y')) { + y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX, + &cause); + if (cause != NULL) { + ctx->error(ctx, "height %s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); + } + if (args_has(self->args, 'L')) layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust); else if (args_has(self->args, 'R')) diff --git a/layout.c b/layout.c index 7c13b539..f08580b7 100644 --- a/layout.c +++ b/layout.c @@ -443,6 +443,39 @@ layout_resize(struct window *w, u_int sx, u_int sy) layout_fix_panes(w, sx, sy); } +/* Resize a pane to an absolute size. */ +void +layout_resize_pane_to(struct window_pane *wp, enum layout_type type, + u_int new_size) +{ + struct layout_cell *lc, *lcparent; + int change, size; + + lc = wp->layout_cell; + + /* Find next parent of the same type. */ + lcparent = lc->parent; + while (lcparent != NULL && lcparent->type != type) { + lc = lcparent; + lcparent = lc->parent; + } + if (lcparent == NULL) + return; + + /* Work out the size adjustment. */ + if (type == LAYOUT_LEFTRIGHT) + size = lc->sx; + else + size = lc->sy; + if (lc == TAILQ_LAST(&lcparent->cells, layout_cells)) + change = size - new_size; + else + change = new_size - size; + + /* Resize the pane. */ + layout_resize_pane(wp, type, change); +} + /* Resize a single pane within the layout. */ void layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) @@ -486,6 +519,7 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change) notify_window_layout_changed(wp->window); } +/* Resize pane based on mouse events. */ void layout_resize_pane_mouse(struct client *c) { @@ -534,6 +568,7 @@ layout_resize_pane_mouse(struct client *c) m->flags &= ~MOUSE_RESIZE_PANE; } +/* Helper function to grow pane. */ int layout_resize_pane_grow( struct layout_cell *lc, enum layout_type type, int needed) @@ -574,6 +609,7 @@ layout_resize_pane_grow( return (size); } +/* Helper function to shrink pane. */ int layout_resize_pane_shrink( struct layout_cell *lc, enum layout_type type, int needed) diff --git a/tmux.1 b/tmux.1 index acb1a4c1..674b6506 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1553,17 +1553,25 @@ if specified, to .It Xo Ic resize-pane .Op Fl DLRU .Op Fl t Ar target-pane +.Op Fl x Ar width +.Op Fl y Ar height .Op Ar adjustment .Xc .D1 (alias: Ic resizep ) -Resize a pane, upward with -.Fl U -(the default), downward with +Resize a pane, up, down, left or right by +.Ar adjustment +with +.Fl U , .Fl D , -to the left with .Fl L -and to the right with -.Fl R . +or +.Fl R , +or +to an absolute size +with +.Fl x +or +.Fl y . The .Ar adjustment is given in lines or cells (the default is 1). diff --git a/tmux.h b/tmux.h index 192a386f..c5090c9f 100644 --- a/tmux.h +++ b/tmux.h @@ -1171,7 +1171,7 @@ struct mouse_event { u_int sgr; /* whether the input arrived in SGR format */ u_int sgr_xb; /* only for SGR: the unmangled button */ - u_int sgr_rel; /* only for SGR: whether it is a release event */ + u_int sgr_rel; /* only for SGR: if it is a release event */ u_int button; u_int clicks; @@ -2167,9 +2167,11 @@ void layout_resize_adjust( void layout_init(struct window *); void layout_free(struct window *); void layout_resize(struct window *, u_int, u_int); -void layout_resize_pane( - struct window_pane *, enum layout_type, int); -void layout_resize_pane_mouse(struct client *c); +void layout_resize_pane(struct window_pane *, enum layout_type, + int); +void layout_resize_pane_to(struct window_pane *, enum layout_type, + u_int); +void layout_resize_pane_mouse(struct client *); void layout_assign_pane(struct layout_cell *, struct window_pane *); struct layout_cell *layout_split_pane( struct window_pane *, enum layout_type, int, int); From db66d851761502bbf567dd1ad0222559819f5882 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:38:13 +0000 Subject: [PATCH 31/91] Fix double space in sessions template. --- tmux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.h b/tmux.h index c5090c9f..849ee827 100644 --- a/tmux.h +++ b/tmux.h @@ -105,7 +105,7 @@ extern char **environ; /* Default templates for choose-tree. */ #define CHOOSE_TREE_SESSION_TEMPLATE \ - "#{session_name}: #{session_windows} windows " \ + "#{session_name}: #{session_windows} windows" \ "#{?session_grouped, (group ,}" \ "#{session_group}#{?session_grouped,),}" \ "#{?session_attached, (attached),}" From 2f5fa4ee9d8fface2e5375ff777320b9613e9b6a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:38:33 +0000 Subject: [PATCH 32/91] Don't hang when clearing line in choose mode now that the cursor stays at the end with wrap. --- window-choose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/window-choose.c b/window-choose.c index 22078bfd..254cc0a7 100644 --- a/window-choose.c +++ b/window-choose.c @@ -753,7 +753,7 @@ window_choose_write_line( (item->wcd->type & TREE_SESSION) ? (item->state & TREE_EXPANDED ? "-" : "+") : "", item->name); } - while (s->cx < screen_size_x(s)) + while (s->cx < screen_size_x(s) - 1) screen_write_putc(ctx, &gc, ' '); if (data->input_type != WINDOW_CHOOSE_NORMAL) { From 79f5fe6f5bb7f24ab33ff365ff522c2c85df338d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:40:22 +0000 Subject: [PATCH 33/91] Use tty_raw on stop, not tty_puts. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 6be902f4..1ee70d39 100644 --- a/tty.c +++ b/tty.c @@ -284,7 +284,7 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, "\033[?1000l\033[?1006l\033[?1005l"); if (tty_term_has(tty->term, TTYC_XT)) - tty_puts(tty, "\033[>4m"); + tty_raw(tty, "\033[>4m"); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); From f19836550b70b447d6842e8da6cb32d559436c4b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:41:01 +0000 Subject: [PATCH 34/91] Unbreak line wrapping. --- screen-write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen-write.c b/screen-write.c index 34dce95e..348065c6 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1053,7 +1053,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) * Move the cursor. If not wrapping, stick at the last character and * replace it. */ - last = !!(s->mode & MODE_WRAP); + last = !(s->mode & MODE_WRAP); if (s->cx <= screen_size_x(s) - last - width) s->cx += width; else From 8c545bbfa8a9fd984437a61c3f0556822ad6ad92 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:41:57 +0000 Subject: [PATCH 35/91] Don't try to print unterminated strings when loading configuration file. --- cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfg.c b/cfg.c index 1967fe99..92e0bb45 100644 --- a/cfg.c +++ b/cfg.c @@ -97,7 +97,7 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) /* Trim \n. */ if (buf[len - 1] == '\n') len--; - log_debug ("%s: %s", path, buf); + log_debug("%s: %.*s", path, (int)len, buf); /* Current line is the continuation of the previous one. */ if (line != NULL) { From 29613f2f31117ed898455fdf75dd7b69d18129f3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 10:42:55 +0000 Subject: [PATCH 36/91] Prevent lock on control clients, not on others. --- server-fn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-fn.c b/server-fn.c index fe5ed431..6d66a9f0 100644 --- a/server-fn.c +++ b/server-fn.c @@ -239,7 +239,7 @@ server_lock_client(struct client *c) size_t cmdlen; struct msg_lock_data lockdata; - if (!(c->flags & CLIENT_CONTROL)) + if (c->flags & CLIENT_CONTROL) return; if (c->flags & CLIENT_SUSPENDED) From d1e6ce26722e3a0774d240e39bbc69b07e93c48b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:49:55 +0000 Subject: [PATCH 37/91] Add functions to allocate and free command contexts rather than doing it all on the stack. --- cmd-if-shell.c | 20 +++++++------------- cmd-list.c | 5 +++-- cmd-run-shell.c | 22 ++++++++-------------- cmd.c | 46 +++++++++++++++++++++++++++++++++------------- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 4cb9de82..ab69e8b5 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -47,7 +47,7 @@ const struct cmd_entry cmd_if_shell_entry = { struct cmd_if_shell_data { char *cmd_if; char *cmd_else; - struct cmd_ctx ctx; + struct cmd_ctx *ctx; }; enum cmd_retval @@ -63,12 +63,9 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->cmd_else = xstrdup(args->argv[2]); else cdata->cmd_else = NULL; - memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); - if (ctx->cmdclient != NULL) - ctx->cmdclient->references++; - if (ctx->curclient != NULL) - ctx->curclient->references++; + cdata->ctx = ctx; + cmd_ref_ctx(ctx); job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata); @@ -79,7 +76,7 @@ void cmd_if_shell_callback(struct job *job) { struct cmd_if_shell_data *cdata = job->data; - struct cmd_ctx *ctx = &cdata->ctx; + struct cmd_ctx *ctx = cdata->ctx; struct cmd_list *cmdlist; char *cause, *cmd; @@ -105,14 +102,11 @@ void cmd_if_shell_free(void *data) { struct cmd_if_shell_data *cdata = data; - struct cmd_ctx *ctx = &cdata->ctx; + struct cmd_ctx *ctx = cdata->ctx; - if (ctx->cmdclient != NULL) { - ctx->cmdclient->references--; + if (ctx->cmdclient != NULL) ctx->cmdclient->flags |= CLIENT_EXIT; - } - if (ctx->curclient != NULL) - ctx->curclient->references--; + cmd_free_ctx(ctx); free(cdata->cmd_else); free(cdata->cmd_if); diff --git a/cmd-list.c b/cmd-list.c index 2cf66a80..d1e72e93 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -97,7 +97,7 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if (guards) ctx->print(ctx, "%%begin"); - n = cmd_exec(cmd, ctx); + n = cmd->entry->exec(cmd, ctx); if (guards) ctx->print(ctx, "%%end"); @@ -146,7 +146,8 @@ cmd_list_free(struct cmd_list *cmdlist) while (!TAILQ_EMPTY(&cmdlist->list)) { cmd = TAILQ_FIRST(&cmdlist->list); TAILQ_REMOVE(&cmdlist->list, cmd, qentry); - cmd_free(cmd); + args_free(cmd->args); + free(cmd); } free(cmdlist); } diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 0fe7620b..ea7d1dcb 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -47,7 +47,7 @@ const struct cmd_entry cmd_run_shell_entry = { struct cmd_run_shell_data { char *cmd; - struct cmd_ctx ctx; + struct cmd_ctx *ctx; u_int wp_id; }; @@ -55,7 +55,7 @@ void cmd_run_shell_print(struct job *job, const char *msg) { struct cmd_run_shell_data *cdata = job->data; - struct cmd_ctx *ctx = &cdata->ctx; + struct cmd_ctx *ctx = cdata->ctx; struct window_pane *wp; wp = window_pane_find_by_id(cdata->wp_id); @@ -84,12 +84,9 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->cmd = xstrdup(args->argv[0]); cdata->wp_id = wp->id; - memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); - if (ctx->cmdclient != NULL) - ctx->cmdclient->references++; - if (ctx->curclient != NULL) - ctx->curclient->references++; + cdata->ctx = ctx; + cmd_ref_ctx(ctx); job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata); @@ -100,7 +97,7 @@ void cmd_run_shell_callback(struct job *job) { struct cmd_run_shell_data *cdata = job->data; - struct cmd_ctx *ctx = &cdata->ctx; + struct cmd_ctx *ctx = cdata->ctx; char *cmd, *msg, *line; size_t size; int retcode; @@ -154,14 +151,11 @@ void cmd_run_shell_free(void *data) { struct cmd_run_shell_data *cdata = data; - struct cmd_ctx *ctx = &cdata->ctx; + struct cmd_ctx *ctx = cdata->ctx; - if (ctx->cmdclient != NULL) { - ctx->cmdclient->references--; + if (ctx->cmdclient != NULL) ctx->cmdclient->flags |= CLIENT_EXIT; - } - if (ctx->curclient != NULL) - ctx->curclient->references--; + cmd_free_ctx(ctx); free(cdata->cmd); free(cdata); diff --git a/cmd.c b/cmd.c index 023a540d..beb3fb5e 100644 --- a/cmd.c +++ b/cmd.c @@ -133,6 +133,39 @@ struct winlink *cmd_find_window_offset(const char *, struct session *, int *); int cmd_find_index_offset(const char *, struct session *, int *); struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); +struct cmd_ctx * +cmd_get_ctx(void) +{ + struct cmd_ctx *ctx; + + ctx = xcalloc(1, sizeof *ctx); + ctx->references = 0; + + cmd_ref_ctx(ctx); + return (ctx); +} + +void +cmd_free_ctx(struct cmd_ctx *ctx) +{ + if (ctx->cmdclient != NULL) + ctx->cmdclient->references--; + if (ctx->curclient != NULL) + ctx->curclient->references--; + if (--ctx->references == 0) + free(ctx); +} + +void +cmd_ref_ctx(struct cmd_ctx *ctx) +{ + ctx->references++; + if (ctx->cmdclient != NULL) + ctx->cmdclient->references++; + if (ctx->curclient != NULL) + ctx->curclient->references++; +} + int cmd_pack_argv(int argc, char **argv, char *buf, size_t len) { @@ -282,19 +315,6 @@ usage: return (NULL); } -enum cmd_retval -cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx) -{ - return (cmd->entry->exec(cmd, ctx)); -} - -void -cmd_free(struct cmd *cmd) -{ - args_free(cmd->args); - free(cmd); -} - size_t cmd_print(struct cmd *cmd, char *buf, size_t len) { From 0ff9275ad75e7ef8933d290bb274d5420a625b4f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:50:13 +0000 Subject: [PATCH 38/91] load_cfg can actually use the same context now they are reference counted. --- cfg.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/cfg.c b/cfg.c index 92e0bb45..1548fb14 100644 --- a/cfg.c +++ b/cfg.c @@ -73,14 +73,13 @@ cfg_add_cause(struct causelist *causes, const char *fmt, ...) * causes. Note that causes must be initialised by the caller! */ enum cmd_retval -load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) +load_cfg(const char *path, struct cmd_ctx *ctx, struct causelist *causes) { FILE *f; u_int n; char *buf, *copy, *line, *cause; size_t len, oldlen; struct cmd_list *cmdlist; - struct cmd_ctx ctx; enum cmd_retval retval; if ((f = fopen(path, "rb")) == NULL) { @@ -90,6 +89,15 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) cfg_references++; + if (ctx != NULL) + cmd_ref_ctx(ctx); + else { + ctx = cmd_get_ctx(); + ctx->error = cfg_error; + ctx->print = cfg_print; + ctx->info = cfg_print; + } + n = 0; line = NULL; retval = CMD_RETURN_NORMAL; @@ -146,22 +154,8 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) if (cmdlist == NULL) continue; - if (ctxin == NULL) { - ctx.msgdata = NULL; - ctx.curclient = NULL; - ctx.cmdclient = NULL; - } else { - ctx.msgdata = ctxin->msgdata; - ctx.curclient = ctxin->curclient; - ctx.cmdclient = ctxin->cmdclient; - } - - ctx.error = cfg_error; - ctx.print = cfg_print; - ctx.info = cfg_print; - cfg_cause = NULL; - switch (cmd_list_exec(cmdlist, &ctx)) { + switch (cmd_list_exec(cmdlist, ctx)) { case CMD_RETURN_YIELD: if (retval != CMD_RETURN_ATTACH) retval = CMD_RETURN_YIELD; @@ -186,6 +180,8 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes) } fclose(f); + cmd_free_ctx(ctx); + cfg_references--; return (retval); From a1722d5c2e545e4cce376848aab8a39465d3a036 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:50:42 +0000 Subject: [PATCH 39/91] Remove unnecessary initializers of cmd_ctx. --- cmd-command-prompt.c | 18 ++++++++---------- cmd-confirm-before.c | 18 ++++++++---------- control.c | 17 ++++++++--------- key-bindings.c | 20 +++++++++----------- server-client.c | 25 +++++++++++++------------ window-choose.c | 18 ++++++++---------- 6 files changed, 54 insertions(+), 62 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 6c3df4ef..68573195 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -150,7 +150,7 @@ cmd_command_prompt_callback(void *data, const char *s) struct cmd_command_prompt_cdata *cdata = data; struct client *c = cdata->c; struct cmd_list *cmdlist; - struct cmd_ctx ctx; + struct cmd_ctx *ctx; char *cause, *new_template, *prompt, *ptr; char *input = NULL; @@ -184,17 +184,15 @@ cmd_command_prompt_callback(void *data, const char *s) return (0); } - ctx.msgdata = NULL; - ctx.curclient = c; + ctx = cmd_get_ctx(); + ctx->curclient = c; + ctx->error = key_bindings_error; + ctx->print = key_bindings_print; + ctx->info = key_bindings_info; - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; - - cmd_list_exec(cmdlist, &ctx); + cmd_list_exec(cmdlist, ctx); cmd_list_free(cmdlist); + cmd_free_ctx(ctx); if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback) return (1); diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 16607d0e..5e3e4e12 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -108,7 +108,7 @@ cmd_confirm_before_callback(void *data, const char *s) struct cmd_confirm_before_data *cdata = data; struct client *c = cdata->c; struct cmd_list *cmdlist; - struct cmd_ctx ctx; + struct cmd_ctx *ctx; char *cause; if (s == NULL || *s == '\0') @@ -125,17 +125,15 @@ cmd_confirm_before_callback(void *data, const char *s) return (0); } - ctx.msgdata = NULL; - ctx.curclient = c; + ctx = cmd_get_ctx(); + ctx->curclient = c; + ctx->error = key_bindings_error; + ctx->print = key_bindings_print; + ctx->info = key_bindings_info; - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; - - cmd_list_exec(cmdlist, &ctx); + cmd_list_exec(cmdlist, ctx); cmd_list_free(cmdlist); + cmd_free_ctx(ctx); return (0); } diff --git a/control.c b/control.c index cb6633ce..71a0a26c 100644 --- a/control.c +++ b/control.c @@ -93,7 +93,7 @@ void control_callback(struct client *c, int closed, unused void *data) { char *line, *cause; - struct cmd_ctx ctx; + struct cmd_ctx *ctx; struct cmd_list *cmdlist; if (closed) @@ -108,22 +108,21 @@ control_callback(struct client *c, int closed, unused void *data) break; } - ctx.msgdata = NULL; - ctx.cmdclient = NULL; - ctx.curclient = c; - - ctx.error = control_msg_error; - ctx.print = control_msg_print; - ctx.info = control_msg_info; + ctx = cmd_get_ctx(); + ctx->curclient = c; + ctx->error = control_msg_error; + ctx->print = control_msg_print; + ctx->info = control_msg_info; if (cmd_string_parse(line, &cmdlist, &cause) != 0) { control_write(c, "%%error in line \"%s\": %s", line, cause); free(cause); } else { - cmd_list_exec(cmdlist, &ctx); + cmd_list_exec(cmdlist, ctx); cmd_list_free(cmdlist); } + cmd_free_ctx(ctx); free(line); } diff --git a/key-bindings.c b/key-bindings.c index 5ebde40c..6909b4b6 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -262,18 +262,15 @@ key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) void key_bindings_dispatch(struct key_binding *bd, struct client *c) { - struct cmd_ctx ctx; + struct cmd_ctx *ctx; struct cmd *cmd; int readonly; - ctx.msgdata = NULL; - ctx.curclient = c; - - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; + ctx = cmd_get_ctx(); + ctx->curclient = c; + ctx->error = key_bindings_error; + ctx->print = key_bindings_print; + ctx->info = key_bindings_info; readonly = 1; TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) { @@ -281,9 +278,10 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c) readonly = 0; } if (!readonly && c->flags & CLIENT_READONLY) { - key_bindings_info(&ctx, "Client is read-only"); + key_bindings_info(ctx, "client is read-only"); return; } - cmd_list_exec(bd->cmdlist, &ctx); + cmd_list_exec(bd->cmdlist, ctx); + cmd_free_ctx(ctx); } diff --git a/server-client.c b/server-client.c index fc3989d9..0feaa8b2 100644 --- a/server-client.c +++ b/server-client.c @@ -865,24 +865,22 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) void server_client_msg_command(struct client *c, struct msg_command_data *data) { - struct cmd_ctx ctx; + struct cmd_ctx *ctx; struct cmd_list *cmdlist = NULL; int argc; char **argv, *cause; - ctx.error = server_client_msg_error; - ctx.print = server_client_msg_print; - ctx.info = server_client_msg_info; - - ctx.msgdata = data; - ctx.curclient = NULL; - - ctx.cmdclient = c; + ctx = cmd_get_ctx(); + ctx->msgdata = data; + ctx->cmdclient = c; + ctx->error = server_client_msg_error; + ctx->print = server_client_msg_print; + ctx->info = server_client_msg_info; argc = data->argc; data->argv[(sizeof data->argv) - 1] = '\0'; if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { - server_client_msg_error(&ctx, "command too long"); + server_client_msg_error(ctx, "command too long"); goto error; } @@ -893,13 +891,13 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) } if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { - server_client_msg_error(&ctx, "%s", cause); + server_client_msg_error(ctx, "%s", cause); cmd_free_argv(argc, argv); goto error; } cmd_free_argv(argc, argv); - switch (cmd_list_exec(cmdlist, &ctx)) + switch (cmd_list_exec(cmdlist, ctx)) { case CMD_RETURN_ERROR: case CMD_RETURN_NORMAL: @@ -910,11 +908,14 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) break; } cmd_list_free(cmdlist); + cmd_free_ctx(ctx); return; error: if (cmdlist != NULL) cmd_list_free(cmdlist); + cmd_free_ctx(ctx); + c->flags |= CLIENT_EXIT; } diff --git a/window-choose.c b/window-choose.c index 254cc0a7..14222d65 100644 --- a/window-choose.c +++ b/window-choose.c @@ -200,7 +200,7 @@ window_choose_data_free(struct window_choose_data *wcd) void window_choose_data_run(struct window_choose_data *cdata) { - struct cmd_ctx ctx; + struct cmd_ctx *ctx; struct cmd_list *cmdlist; char *cause; @@ -220,17 +220,15 @@ window_choose_data_run(struct window_choose_data *cdata) return; } - ctx.msgdata = NULL; - ctx.curclient = cdata->start_client; + ctx = cmd_get_ctx(); + ctx->curclient = cdata->start_client; + ctx->error = key_bindings_error; + ctx->print = key_bindings_print; + ctx->info = key_bindings_info; - ctx.error = key_bindings_error; - ctx.print = key_bindings_print; - ctx.info = key_bindings_info; - - ctx.cmdclient = NULL; - - cmd_list_exec(cmdlist, &ctx); + cmd_list_exec(cmdlist, ctx); cmd_list_free(cmdlist); + cmd_free_ctx(ctx); } void From 8a6fbfa14829ad41b9b6f05f4382d8f4537b7271 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:51:15 +0000 Subject: [PATCH 40/91] Don't use a target-client for stdout, just always cmdclient. --- cmd-capture-pane.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index ee42ddee..fa4a5da2 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -31,9 +31,8 @@ enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", - "b:c:E:pS:t:", 0, 0, - "[-p] [-c target-client] [-b buffer-index] [-E end-line] " - "[-S start-line] " + "b:E:pS:t:", 0, 0, + "[-p] [-b buffer-index] [-E end-line] [-S start-line]" CMD_TARGET_PANE_USAGE, 0, NULL, @@ -45,7 +44,7 @@ enum cmd_retval cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct client *c; + struct client *c = ctx->cmdclient; struct window_pane *wp; char *buf, *line, *cause; struct screen *s; @@ -54,9 +53,6 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i, limit, top, bottom, tmp; size_t len, linelen; - if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) - return (CMD_RETURN_ERROR); - if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); s = &wp->base; From 8478895eeb014a4219c4d61edd598c05b073db68 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:51:54 +0000 Subject: [PATCH 41/91] Add -e flag to capture-pane to include embedded ANSI SGR escape sequences, from George Nachman. --- tmux.1 | 9 +++++---- tmux.h | 14 +++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tmux.1 b/tmux.1 index 674b6506..9f48c78f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1036,9 +1036,9 @@ By default, it uses the format but a different format may be specified with .Fl F . .It Xo Ic capture-pane +.Op Fl e .Op Fl p .Op Fl b Ar buffer-index -.Op Fl c Ar target-client .Op Fl E Ar end-line .Op Fl S Ar start-line .Op Fl t Ar target-pane @@ -1047,11 +1047,12 @@ but a different format may be specified with Capture the contents of a pane. If .Fl p -is given, the output goes to -.Ar target-client -stdout, otherwise to the buffer specified with +is given, the output goes to stdout, otherwise to the buffer specified with .Fl b or a new buffer if omitted. +If +.Fl e +is given, the output includes escape sequences for text and background attributes. .Pp .Fl S and diff --git a/tmux.h b/tmux.h index 849ee827..deb52da1 100644 --- a/tmux.h +++ b/tmux.h @@ -1366,8 +1366,10 @@ struct cmd_ctx { * cmdclient and curclient may both be NULL if the command is in the * configuration file. */ - struct client *curclient; - struct client *cmdclient; + struct client *curclient; + struct client *cmdclient; + + int references; struct msg_command_data *msgdata; @@ -1714,13 +1716,14 @@ long long args_strtonum( struct args *, u_char, long long, long long, char **); /* cmd.c */ +struct cmd_ctx *cmd_get_ctx(void); +void cmd_free_ctx(struct cmd_ctx *); +void cmd_ref_ctx(struct cmd_ctx *); int cmd_pack_argv(int, char **, char *, size_t); int cmd_unpack_argv(char *, size_t, int, char ***); char **cmd_copy_argv(int, char *const *); void cmd_free_argv(int, char **); struct cmd *cmd_parse(int, char **, char **); -enum cmd_retval cmd_exec(struct cmd *, struct cmd_ctx *); -void cmd_free(struct cmd *); size_t cmd_print(struct cmd *, char *, size_t); struct session *cmd_current_session(struct cmd_ctx *, int); struct client *cmd_current_client(struct cmd_ctx *); @@ -1974,7 +1977,8 @@ void grid_clear(struct grid *, u_int, u_int, u_int, u_int); void grid_clear_lines(struct grid *, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int); void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); -char *grid_string_cells(struct grid *, u_int, u_int, u_int); +char *grid_string_cells(struct grid *, u_int, u_int, u_int, + struct grid_cell **, int); void grid_duplicate_lines( struct grid *, u_int, struct grid *, u_int, u_int); u_int grid_reflow(struct grid *, struct grid *, u_int); From 58932295fcd80062569e808897e9e1d252ec888a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:52:40 +0000 Subject: [PATCH 42/91] Add copy-pipe mode command to copy selection and also pipe to a command. --- cmd-bind-key.c | 30 ++++++++++++++------ cmd-list-keys.c | 7 +++-- mode-key.c | 6 +++- window-copy.c | 74 +++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 94 insertions(+), 23 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 909f4839..086ac4ec 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -46,7 +46,7 @@ enum cmd_retval cmd_bind_key_check(struct args *args) { if (args_has(args, 't')) { - if (args->argc != 2) + if (args->argc != 2 && args->argc != 3) return (CMD_RETURN_ERROR); } else { if (args->argc < 2) @@ -93,6 +93,7 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) const struct mode_key_table *mtab; struct mode_key_binding *mbind, mtmp; enum mode_key_cmd cmd; + const char *arg; tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { @@ -106,16 +107,29 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) return (CMD_RETURN_ERROR); } + if (cmd != MODEKEYCOPY_COPYPIPE) { + if (args->argc != 2) { + ctx->error(ctx, "no argument allowed"); + return (CMD_RETURN_ERROR); + } + arg = NULL; + } else { + if (args->argc != 3) { + ctx->error(ctx, "no argument given"); + return (CMD_RETURN_ERROR); + } + arg = args->argv[2]; + } + mtmp.key = key; mtmp.mode = !!args_has(args, 'c'); - if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) { - mbind->cmd = cmd; - return (CMD_RETURN_NORMAL); + if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) == NULL) { + mbind = xmalloc(sizeof *mbind); + mbind->key = mtmp.key; + mbind->mode = mtmp.mode; + RB_INSERT(mode_key_tree, mtab->tree, mbind); } - mbind = xmalloc(sizeof *mbind); - mbind->key = mtmp.key; - mbind->mode = mtmp.mode; mbind->cmd = cmd; - RB_INSERT(mode_key_tree, mtab->tree, mbind); + mbind->arg = arg != NULL ? xstrdup(arg) : NULL; return (CMD_RETURN_NORMAL); } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index ff6421ad..dab6d545 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -138,9 +138,12 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) mode = "c"; cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd); if (cmdstr != NULL) { - ctx->print(ctx, "bind-key -%st %s%s %*s %s", + ctx->print(ctx, "bind-key -%st %s%s %*s %s%s%s%s", mode, any_mode && *mode == '\0' ? " " : "", - mtab->name, (int) width, key, cmdstr); + mtab->name, (int) width, key, cmdstr, + mbind->arg != NULL ? " \"" : "", + mbind->arg != NULL ? mbind->arg : "", + mbind->arg != NULL ? "\"": ""); } } diff --git a/mode-key.c b/mode-key.c index 6c041359..54abcf32 100644 --- a/mode-key.c +++ b/mode-key.c @@ -99,6 +99,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_BOTTOMLINE, "bottom-line" }, { MODEKEYCOPY_CANCEL, "cancel" }, { MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, + { MODEKEYCOPY_COPYPIPE, "copy-pipe" }, { MODEKEYCOPY_COPYLINE, "copy-line" }, { MODEKEYCOPY_COPYENDOFLINE, "copy-end-of-line" }, { MODEKEYCOPY_COPYSELECTION, "copy-selection" }, @@ -513,6 +514,7 @@ mode_key_init_trees(void) mbind->key = ment->key; mbind->mode = ment->mode; mbind->cmd = ment->cmd; + mbind->arg = NULL; RB_INSERT(mode_key_tree, mtab->tree, mbind); } } @@ -526,7 +528,7 @@ mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree) } enum mode_key_cmd -mode_key_lookup(struct mode_key_data *mdata, int key) +mode_key_lookup(struct mode_key_data *mdata, int key, const char **arg) { struct mode_key_binding *mbind, mtmp; @@ -546,6 +548,8 @@ mode_key_lookup(struct mode_key_data *mdata, int key) mdata->mode = 1 - mdata->mode; /* FALLTHROUGH */ default: + if (arg != NULL) + *arg = mbind->arg; return (mbind->cmd); } } diff --git a/window-copy.c b/window-copy.c index 0cff3e13..61fa382a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -52,6 +52,9 @@ void window_copy_goto_line(struct window_pane *, const char *); void window_copy_update_cursor(struct window_pane *, u_int, u_int); void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); +void *window_copy_get_selection(struct window_pane *, size_t *); +void window_copy_copy_buffer(struct window_pane *, int, void *, size_t); +void window_copy_copy_pipe(struct window_pane *, int, const char *); void window_copy_copy_selection(struct window_pane *, int); void window_copy_clear_selection(struct window_pane *); void window_copy_copy_line( @@ -364,6 +367,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) u_int n; int np, keys; enum mode_key_cmd cmd; + const char *arg; np = data->numprefix; if (np <= 0) @@ -405,7 +409,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) return; } - cmd = mode_key_lookup(&data->mdata, key); + cmd = mode_key_lookup(&data->mdata, key, &arg); switch (cmd) { case MODEKEYCOPY_CANCEL: window_pane_reset_mode(wp); @@ -533,6 +537,13 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) window_copy_clear_selection(wp); window_copy_redraw_screen(wp); break; + case MODEKEYCOPY_COPYPIPE: + if (sess != NULL) { + window_copy_copy_pipe(wp, data->numprefix, arg); + window_pane_reset_mode(wp); + return; + } + break; case MODEKEYCOPY_COPYSELECTION: if (sess != NULL) { window_copy_copy_selection(wp, data->numprefix); @@ -735,7 +746,7 @@ window_copy_key_input(struct window_pane *wp, int key) size_t inputlen; int np; - switch (mode_key_lookup(&data->mdata, key)) { + switch (mode_key_lookup(&data->mdata, key, NULL)) { case MODEKEYEDIT_CANCEL: data->numprefix = -1; return (-1); @@ -1259,19 +1270,19 @@ window_copy_update_selection(struct window_pane *wp) return (1); } -void -window_copy_copy_selection(struct window_pane *wp, int idx) +void * +window_copy_get_selection(struct window_pane *wp, size_t *len) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; char *buf; size_t off; - u_int i, xx, yy, sx, sy, ex, ey, limit; + u_int i, xx, yy, sx, sy, ex, ey; u_int firstsx, lastex, restex, restsx; int keys; if (!s->sel.flag) - return; + return (NULL); buf = xmalloc(1); off = 0; @@ -1364,19 +1375,58 @@ window_copy_copy_selection(struct window_pane *wp, int idx) /* Don't bother if no data. */ if (off == 0) { free(buf); - return; + return (NULL); } - off--; /* remove final \n */ + *len = off - 1; /* remove final \n */ + return (buf); +} + +void +window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len) +{ + u_int limit; if (options_get_number(&global_options, "set-clipboard")) - screen_write_setselection(&wp->ictx.ctx, buf, off); + screen_write_setselection(&wp->ictx.ctx, buf, len); - /* Add the buffer to the stack. */ if (idx == -1) { limit = options_get_number(&global_options, "buffer-limit"); - paste_add(&global_buffers, buf, off, limit); + paste_add(&global_buffers, buf, len, limit); } else - paste_replace(&global_buffers, idx, buf, off); + paste_replace(&global_buffers, idx, buf, len); +} + +void +window_copy_copy_pipe(struct window_pane *wp, int idx, const char *arg) +{ + void* buf; + size_t len; + FILE* f; + + buf = window_copy_get_selection(wp, &len); + if (buf == NULL) + return; + + f = popen(arg, "w"); + if (f != NULL) { + fwrite(buf, 1, len, f); + pclose(f); + } + + window_copy_copy_buffer(wp, idx, buf, len); +} + +void +window_copy_copy_selection(struct window_pane *wp, int idx) +{ + void* buf; + size_t len; + + buf = window_copy_get_selection(wp, &len); + if (buf == NULL) + return; + + window_copy_copy_buffer(wp, idx, buf, len); } void From d644e5143fbce243ddcca468a1b8a1d5bfd21b34 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:53:24 +0000 Subject: [PATCH 43/91] Fix so capture-pane/save-buffer can work in control clients, from George Nachman. --- cmd-save-buffer.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index b8f9968b..6031a562 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -45,7 +45,7 @@ enum cmd_retval cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct client *c = ctx->cmdclient; + struct client *c; struct session *s; struct paste_buffer *pb; const char *path, *newpath, *wd; @@ -76,13 +76,17 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) path = args->argv[0]; if (strcmp(path, "-") == 0) { + c = ctx->curclient; + if (c == NULL || !(c->flags & CLIENT_CONTROL)) + c = ctx->cmdclient; if (c == NULL) { - ctx->error(ctx, "%s: can't write to stdout", path); + ctx->error(ctx, "can't write to stdout"); return (CMD_RETURN_ERROR); } evbuffer_add(c->stdout_data, pb->data, pb->size); server_push_stdout(c); } else { + c = ctx->cmdclient; if (c != NULL) wd = c->cwd; else if ((s = cmd_current_session(ctx, 0)) != NULL) { From 2243cfbe7559e6cf48194ff95dcd7eb6df5fe41d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:54:29 +0000 Subject: [PATCH 44/91] Need to set clients in context before changing their reference count. --- cfg.c | 2 +- cmd-command-prompt.c | 3 +-- cmd-confirm-before.c | 3 +-- cmd.c | 5 ++++- control.c | 3 +-- key-bindings.c | 3 +-- server-client.c | 3 +-- window-choose.c | 11 +++++------ 8 files changed, 15 insertions(+), 18 deletions(-) diff --git a/cfg.c b/cfg.c index 1548fb14..b7b0ec78 100644 --- a/cfg.c +++ b/cfg.c @@ -92,7 +92,7 @@ load_cfg(const char *path, struct cmd_ctx *ctx, struct causelist *causes) if (ctx != NULL) cmd_ref_ctx(ctx); else { - ctx = cmd_get_ctx(); + ctx = cmd_get_ctx(NULL, NULL); ctx->error = cfg_error; ctx->print = cfg_print; ctx->info = cfg_print; diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 68573195..80407b7d 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -184,8 +184,7 @@ cmd_command_prompt_callback(void *data, const char *s) return (0); } - ctx = cmd_get_ctx(); - ctx->curclient = c; + ctx = cmd_get_ctx(NULL, c); ctx->error = key_bindings_error; ctx->print = key_bindings_print; ctx->info = key_bindings_info; diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 5e3e4e12..f9491095 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -125,8 +125,7 @@ cmd_confirm_before_callback(void *data, const char *s) return (0); } - ctx = cmd_get_ctx(); - ctx->curclient = c; + ctx = cmd_get_ctx(NULL, c); ctx->error = key_bindings_error; ctx->print = key_bindings_print; ctx->info = key_bindings_info; diff --git a/cmd.c b/cmd.c index beb3fb5e..6ab1f430 100644 --- a/cmd.c +++ b/cmd.c @@ -134,13 +134,16 @@ int cmd_find_index_offset(const char *, struct session *, int *); struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); struct cmd_ctx * -cmd_get_ctx(void) +cmd_get_ctx(struct client *cmdclient, struct client *curclient) { struct cmd_ctx *ctx; ctx = xcalloc(1, sizeof *ctx); ctx->references = 0; + ctx->cmdclient = cmdclient; + ctx->curclient = curclient; + cmd_ref_ctx(ctx); return (ctx); } diff --git a/control.c b/control.c index 71a0a26c..a248e91f 100644 --- a/control.c +++ b/control.c @@ -108,8 +108,7 @@ control_callback(struct client *c, int closed, unused void *data) break; } - ctx = cmd_get_ctx(); - ctx->curclient = c; + ctx = cmd_get_ctx(NULL, c); ctx->error = control_msg_error; ctx->print = control_msg_print; ctx->info = control_msg_info; diff --git a/key-bindings.c b/key-bindings.c index 6909b4b6..0f944c4c 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -266,8 +266,7 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c) struct cmd *cmd; int readonly; - ctx = cmd_get_ctx(); - ctx->curclient = c; + ctx = cmd_get_ctx(NULL, c); ctx->error = key_bindings_error; ctx->print = key_bindings_print; ctx->info = key_bindings_info; diff --git a/server-client.c b/server-client.c index 0feaa8b2..492d6b22 100644 --- a/server-client.c +++ b/server-client.c @@ -870,9 +870,8 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) int argc; char **argv, *cause; - ctx = cmd_get_ctx(); + ctx = cmd_get_ctx(c, NULL); ctx->msgdata = data; - ctx->cmdclient = c; ctx->error = server_client_msg_error; ctx->print = server_client_msg_print; ctx->info = server_client_msg_info; diff --git a/window-choose.c b/window-choose.c index 14222d65..4443e1a5 100644 --- a/window-choose.c +++ b/window-choose.c @@ -220,8 +220,7 @@ window_choose_data_run(struct window_choose_data *cdata) return; } - ctx = cmd_get_ctx(); - ctx->curclient = cdata->start_client; + ctx = cmd_get_ctx(NULL, cdata->start_client); ctx->error = key_bindings_error; ctx->print = key_bindings_print; ctx->info = key_bindings_info; @@ -492,7 +491,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) items = ARRAY_LENGTH(&data->list); if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) { - switch (mode_key_lookup(&data->mdata, key)) { + switch (mode_key_lookup(&data->mdata, key, NULL)) { case MODEKEYCHOICE_CANCEL: data->input_type = WINDOW_CHOOSE_NORMAL; window_choose_redraw_screen(wp); @@ -523,7 +522,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) return; } - switch (mode_key_lookup(&data->mdata, key)) { + switch (mode_key_lookup(&data->mdata, key, NULL)) { case MODEKEYCHOICE_CANCEL: window_choose_fire_callback(wp, NULL); break; @@ -777,7 +776,7 @@ window_choose_key_index(struct window_choose_mode_data *data, u_int idx) int mkey; for (ptr = keys; *ptr != '\0'; ptr++) { - mkey = mode_key_lookup(&data->mdata, *ptr); + mkey = mode_key_lookup(&data->mdata, *ptr, NULL); if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) continue; if (idx-- == 0) @@ -797,7 +796,7 @@ window_choose_index_key(struct window_choose_mode_data *data, int key) u_int idx = 0; for (ptr = keys; *ptr != '\0'; ptr++) { - mkey = mode_key_lookup(&data->mdata, *ptr); + mkey = mode_key_lookup(&data->mdata, *ptr, NULL); if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER) continue; if (key == *ptr) From c519f9a84cd9fc3fdec8b61afaf42995f9e48b46 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:55:22 +0000 Subject: [PATCH 45/91] evbuffer_readline returns allocated storage, don't leak it. --- cmd-break-pane.c | 1 - cmd-run-shell.c | 1 + status.c | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 038ec85c..57628a7a 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -93,7 +93,6 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) server_status_session_group(s); if (args_has(args, 'P')) { - if ((template = args_get(args, 'F')) == NULL) template = BREAK_PANE_TEMPLATE; diff --git a/cmd-run-shell.c b/cmd-run-shell.c index ea7d1dcb..0d19a8e6 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -112,6 +112,7 @@ cmd_run_shell_callback(struct job *job) do { if ((line = evbuffer_readline(job->event->input)) != NULL) { cmd_run_shell_print (job, line); + free(line); lines++; } } while (line != NULL); diff --git a/status.c b/status.c index 0bee54e9..fc773dca 100644 --- a/status.c +++ b/status.c @@ -676,7 +676,7 @@ status_job_callback(struct job *job) memcpy(buf, EVBUFFER_DATA(job->event->input), len); buf[len] = '\0'; } else - buf = xstrdup(line); + buf = line; so->out = buf; server_status_client(c); @@ -1042,7 +1042,7 @@ status_prompt_key(struct client *c, int key) size_t size, n, off, idx; size = strlen(c->prompt_buffer); - switch (mode_key_lookup(&c->prompt_mdata, key)) { + switch (mode_key_lookup(&c->prompt_mdata, key, NULL)) { case MODEKEYEDIT_CURSORLEFT: if (c->prompt_index > 0) { c->prompt_index--; From 295d86911e7f7823785d138d96d94ccfa924e29d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 15:56:11 +0000 Subject: [PATCH 46/91] Add -C and -J to capture pane to escape control sequences and to join wrapped line, based on a diff from George Nachman. --- cmd-capture-pane.c | 40 +++++--- grid-view.c | 2 +- grid.c | 228 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 250 insertions(+), 20 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index fa4a5da2..6a10b7c9 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", - "b:E:pS:t:", 0, 0, - "[-p] [-b buffer-index] [-E end-line] [-S start-line]" + "b:CeE:JpS:t:", 0, 0, + "[-CeJp] [-b buffer-index] [-E end-line] [-S start-line]" CMD_TARGET_PANE_USAGE, 0, NULL, @@ -44,14 +44,16 @@ enum cmd_retval cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; - struct client *c = ctx->cmdclient; + struct client *c; struct window_pane *wp; - char *buf, *line, *cause; + char *buf, *line, *cause; struct screen *s; struct grid *gd; - int buffer, n; + int buffer, n, with_codes, escape_c0, join_lines; u_int i, limit, top, bottom, tmp; - size_t len, linelen; + size_t len, linelen; + struct grid_cell *gc; + const struct grid_line *gl; if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); @@ -89,19 +91,31 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) top = tmp; } + with_codes = args_has(args, 'e'); + escape_c0 = args_has(args, 'C'); + join_lines = args_has(args, 'J'); + + gc = NULL; for (i = top; i <= bottom; i++) { - line = grid_string_cells(s->grid, 0, i, screen_size_x(s)); - linelen = strlen(line); + line = grid_string_cells(s->grid, 0, i, screen_size_x(s), + &gc, with_codes, escape_c0); + linelen = strlen(line); - buf = xrealloc(buf, 1, len + linelen + 1); - memcpy(buf + len, line, linelen); - len += linelen; - buf[len++] = '\n'; + buf = xrealloc(buf, 1, len + linelen + 1); + memcpy(buf + len, line, linelen); + len += linelen; - free(line); + gl = grid_peek_line(s->grid, i); + if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED)) + buf[len++] = '\n'; + + free(line); } if (args_has(args, 'p')) { + c = ctx->curclient; + if (c == NULL || !(c->flags & CLIENT_CONTROL)) + c = ctx->cmdclient; if (c == NULL) { ctx->error(ctx, "can't write to stdout"); return (CMD_RETURN_ERROR); diff --git a/grid-view.c b/grid-view.c index bde624cc..a9a7e189 100644 --- a/grid-view.c +++ b/grid-view.c @@ -234,5 +234,5 @@ grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) px = grid_view_x(gd, px); py = grid_view_y(gd, py); - return (grid_string_cells(gd, px, py, nx)); + return (grid_string_cells(gd, px, py, nx, NULL, 0, 0)); } diff --git a/grid.c b/grid.c index 93160a06..35e719b5 100644 --- a/grid.c +++ b/grid.c @@ -74,6 +74,10 @@ void grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int); void grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int, u_int); void grid_reflow_move(struct grid *, u_int *, struct grid_line *); +size_t grid_string_cells_fg(const struct grid_cell *, int *); +size_t grid_string_cells_bg(const struct grid_cell *, int *); +void grid_string_cells_code(const struct grid_cell *, + const struct grid_cell *, char *, size_t, int); /* Create a new grid. */ struct grid * @@ -230,6 +234,15 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx) gl->cellsize = sx; } +/* Peek at grid line. */ +const struct grid_line * +grid_peek_line(struct grid *gd, u_int py) +{ + if (grid_check_y(gd, py) != 0) + return (NULL); + return (&gd->linedata[py]); +} + /* Get cell for reading. */ const struct grid_cell * grid_peek_cell(struct grid *gd, u_int px, u_int py) @@ -392,18 +405,201 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) } } +/* Get ANSI foreground sequence. */ +size_t +grid_string_cells_fg(const struct grid_cell *gc, int *values) +{ + size_t n; + + n = 0; + if (gc->flags & GRID_FLAG_FG256) { + values[n++] = 38; + values[n++] = 5; + values[n++] = gc->fg; + } else { + switch (gc->fg) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + values[n++] = gc->fg + 30; + break; + case 8: + values[n++] = 39; + break; + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + values[n++] = gc->fg; + break; + } + } + return (n); +} + +/* Get ANSI background sequence. */ +size_t +grid_string_cells_bg(const struct grid_cell *gc, int *values) +{ + size_t n; + + n = 0; + if (gc->flags & GRID_FLAG_BG256) { + values[n++] = 48; + values[n++] = 5; + values[n++] = gc->bg; + } else { + switch (gc->bg) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + values[n++] = gc->bg + 40; + break; + case 8: + values[n++] = 49; + break; + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + values[n++] = gc->bg - 10; + break; + } + } + return (n); +} + +/* + * Returns ANSI code to set particular attributes (colour, bold and so on) + * given a current state. The output buffer must be able to hold at least 57 + * bytes. + */ +void +grid_string_cells_code(const struct grid_cell *lastgc, + const struct grid_cell *gc, char *buf, size_t len, int escape_c0) +{ + int oldc[16], newc[16], s[32]; + size_t noldc, nnewc, n, i; + u_int attr = gc->attr; + u_int lastattr = lastgc->attr; + char tmp[64]; + + struct { + u_int mask; + u_int code; + } attrs[] = { + { GRID_ATTR_BRIGHT, 1 }, + { GRID_ATTR_DIM, 2 }, + { GRID_ATTR_ITALICS, 3 }, + { GRID_ATTR_UNDERSCORE, 4 }, + { GRID_ATTR_BLINK, 5 }, + { GRID_ATTR_REVERSE, 7 }, + { GRID_ATTR_HIDDEN, 8 } + }; + n = 0; + + /* If any attribute is removed, begin with 0. */ + for (i = 0; i < nitems(attrs); i++) { + if (!(attr & attrs[i].mask) && (lastattr & attrs[i].mask)) { + s[n++] = 0; + lastattr &= GRID_ATTR_CHARSET; + break; + } + } + /* For each attribute that is newly set, add its code. */ + for (i = 0; i < nitems(attrs); i++) { + if ((attr & attrs[i].mask) && !(lastattr & attrs[i].mask)) + s[n++] = attrs[i].code; + } + + /* If the foreground c changed, append its parameters. */ + nnewc = grid_string_cells_fg(gc, newc); + noldc = grid_string_cells_fg(lastgc, oldc); + if (nnewc != noldc || + memcmp(newc,oldc, nnewc * sizeof newc[0]) != 0) { + for (i = 0; i < nnewc; i++) + s[n++] = newc[i]; + } + + /* If the background c changed, append its parameters. */ + nnewc = grid_string_cells_bg(gc, newc); + noldc = grid_string_cells_bg(lastgc, oldc); + if (nnewc != noldc || + memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0) { + for (i = 0; i < nnewc; i++) + s[n++] = newc[i]; + } + + /* If there are any parameters, append an SGR code. */ + *buf = '\0'; + if (n > 0) { + if (escape_c0) + strlcat(buf, "\\033[", len); + else + strlcat(buf, "\033[", len); + for (i = 0; i < n; i++) { + if (i + 1 < n) + xsnprintf(tmp, sizeof tmp, "%d;", s[i]); + else + xsnprintf(tmp, sizeof tmp, "%d", s[i]); + strlcat(buf, tmp, len); + } + strlcat(buf, "m", len); + } + + /* Append shift in/shift out if needed. */ + if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) { + if (escape_c0) + strlcat(buf, "\\016", len); /* SO */ + else + strlcat(buf, "\016", len); /* SO */ + } + if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) { + if (escape_c0) + strlcat(buf, "\\017", len); /* SI */ + else + strlcat(buf, "\017", len); /* SI */ + } +} + /* Convert cells into a string. */ char * -grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) +grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, + struct grid_cell **lastgc, int with_codes, int escape_c0) { const struct grid_cell *gc; + static struct grid_cell lastgc1; struct utf8_data ud; - char *buf; - size_t len, off; + const char* data; + char *buf, code[128]; + size_t len, off, size, codelen; u_int xx; GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + if (*lastgc == NULL) { + memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1); + *lastgc = &lastgc1; + } + len = 128; buf = xmalloc(len); off = 0; @@ -414,18 +610,38 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) continue; grid_cell_get(gc, &ud); - while (len < off + ud.size + 1) { + if (with_codes) { + grid_string_cells_code(*lastgc, gc, code, sizeof code, + escape_c0); + codelen = strlen(code); + memcpy(*lastgc, gc, sizeof *gc); + } else + codelen = 0; + + data = ud.data; + size = ud.size; + if (escape_c0 && size == 1 && *data == '\\') { + data = "\\"; + size = 2; + } + + while (len < off + size + codelen + 1) { buf = xrealloc(buf, 2, len); len *= 2; } - memcpy(buf + off, ud.data, ud.size); - off += ud.size; + if (codelen != 0) { + memcpy(buf + off, code, codelen); + off += codelen; + } + memcpy(buf + off, data, size); + off += size; } while (off > 0 && buf[off - 1] == ' ') off--; buf[off] = '\0'; + return (buf); } From eaaeb28cda0ca1a31d1bf5662330388c585a0921 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 16:00:26 +0000 Subject: [PATCH 47/91] Add session_set_current helper function, extracted from a diff from Aaron Jensen. --- session.c | 38 +++++++++++++++----------------------- tmux.h | 18 +++++++++++------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/session.c b/session.c index 21929d8b..b1944bc3 100644 --- a/session.c +++ b/session.c @@ -346,13 +346,7 @@ session_next(struct session *s, int alert) if (alert && ((wl = session_next_alert(wl)) == NULL)) return (-1); } - if (wl == s->curw) - return (1); - winlink_stack_remove(&s->lastw, wl); - winlink_stack_push(&s->lastw, s->curw); - s->curw = wl; - winlink_clear_flags(wl); - return (0); + return (session_set_current(s, wl)); } struct winlink * @@ -383,13 +377,7 @@ session_previous(struct session *s, int alert) if (alert && (wl = session_previous_alert(wl)) == NULL) return (-1); } - if (wl == s->curw) - return (1); - winlink_stack_remove(&s->lastw, wl); - winlink_stack_push(&s->lastw, s->curw); - s->curw = wl; - winlink_clear_flags(wl); - return (0); + return (session_set_current(s, wl)); } /* Move session to specific window. */ @@ -399,15 +387,7 @@ session_select(struct session *s, int idx) struct winlink *wl; wl = winlink_find_by_index(&s->windows, idx); - if (wl == NULL) - return (-1); - if (wl == s->curw) - return (1); - winlink_stack_remove(&s->lastw, wl); - winlink_stack_push(&s->lastw, s->curw); - s->curw = wl; - winlink_clear_flags(wl); - return (0); + return (session_set_current(s, wl)); } /* Move session to last used window. */ @@ -422,6 +402,18 @@ session_last(struct session *s) if (wl == s->curw) return (1); + return (session_set_current(s, wl)); +} + +/* Set current winlink to wl .*/ +int +session_set_current(struct session *s, struct winlink *wl) +{ + if (wl == NULL) + return (-1); + if (wl == s->curw) + return (1); + winlink_stack_remove(&s->lastw, wl); winlink_stack_push(&s->lastw, s->curw); s->curw = wl; diff --git a/tmux.h b/tmux.h index deb52da1..720c1429 100644 --- a/tmux.h +++ b/tmux.h @@ -566,6 +566,7 @@ enum mode_key_cmd { MODEKEYCOPY_BOTTOMLINE, MODEKEYCOPY_CANCEL, MODEKEYCOPY_CLEARSELECTION, + MODEKEYCOPY_COPYPIPE, MODEKEYCOPY_COPYLINE, MODEKEYCOPY_COPYENDOFLINE, MODEKEYCOPY_COPYSELECTION, @@ -632,12 +633,13 @@ struct mode_key_data { /* Binding between a key and a command. */ struct mode_key_binding { - int key; + int key; - int mode; - enum mode_key_cmd cmd; + int mode; + enum mode_key_cmd cmd; + const char *arg; - RB_ENTRY(mode_key_binding) entry; + RB_ENTRY(mode_key_binding) entry; }; RB_HEAD(mode_key_tree, mode_key_binding); @@ -1548,7 +1550,7 @@ enum mode_key_cmd mode_key_fromstring(const struct mode_key_cmdstr *, const struct mode_key_table *mode_key_findtable(const char *); void mode_key_init_trees(void); void mode_key_init(struct mode_key_data *, struct mode_key_tree *); -enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int); +enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int, const char **); /* notify.c */ void notify_enable(void); @@ -1716,7 +1718,7 @@ long long args_strtonum( struct args *, u_char, long long, long long, char **); /* cmd.c */ -struct cmd_ctx *cmd_get_ctx(void); +struct cmd_ctx *cmd_get_ctx(struct client *, struct client *); void cmd_free_ctx(struct cmd_ctx *); void cmd_ref_ctx(struct cmd_ctx *); int cmd_pack_argv(int, char **, char *, size_t); @@ -1971,6 +1973,7 @@ void grid_scroll_history(struct grid *); void grid_scroll_history_region(struct grid *, u_int, u_int); void grid_expand_line(struct grid *, u_int, u_int); const struct grid_cell *grid_peek_cell(struct grid *, u_int, u_int); +const struct grid_line *grid_peek_line(struct grid *, u_int); struct grid_cell *grid_get_cell(struct grid *, u_int, u_int); void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *); void grid_clear(struct grid *, u_int, u_int, u_int, u_int); @@ -1978,7 +1981,7 @@ void grid_clear_lines(struct grid *, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int); void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); char *grid_string_cells(struct grid *, u_int, u_int, u_int, - struct grid_cell **, int); + struct grid_cell **, int, int); void grid_duplicate_lines( struct grid *, u_int, struct grid *, u_int, u_int); u_int grid_reflow(struct grid *, struct grid *, u_int); @@ -2277,6 +2280,7 @@ int session_next(struct session *, int); int session_previous(struct session *, int); int session_select(struct session *, int); int session_last(struct session *); +int session_set_current(struct session *, struct winlink *); struct session_group *session_group_find(struct session *); u_int session_group_index(struct session_group *); void session_group_add(struct session *, struct session *); From 702ab8bab0e88613aa0e6e6cf8a2e18fdd47341a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 16:03:35 +0000 Subject: [PATCH 48/91] Add a load of miscellaneous pane formats, from George Nachman. --- format.c | 48 +++++++++++++++++++++++++++++++++++++++++------- tmux.1 | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/format.c b/format.c index 9e3bc86a..7e442e0a 100644 --- a/format.c +++ b/format.c @@ -384,29 +384,63 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) size += gl->cellsize * sizeof *gl->celldata; } size += gd->hsize * sizeof *gd->linedata; + format_add(ft, "history_size", "%u", gd->hsize); + format_add(ft, "history_limit", "%u", gd->hlimit); + format_add(ft, "history_bytes", "%llu", size); if (window_pane_index(wp, &idx) != 0) fatalx("index not found"); + format_add(ft, "pane_index", "%u", idx); format_add(ft, "pane_width", "%u", wp->sx); format_add(ft, "pane_height", "%u", wp->sy); format_add(ft, "pane_title", "%s", wp->base.title); - format_add(ft, "pane_index", "%u", idx); - format_add(ft, "history_size", "%u", gd->hsize); - format_add(ft, "history_limit", "%u", gd->hlimit); - format_add(ft, "history_bytes", "%llu", size); format_add(ft, "pane_id", "%%%u", wp->id); format_add(ft, "pane_active", "%d", wp == wp->window->active); format_add(ft, "pane_dead", "%d", wp->fd == -1); + + format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base); + + if (wp->tty != NULL) + format_add(ft, "pane_tty", "%s", wp->tty); + format_add(ft, "pane_pid", "%ld", (long) wp->pid); if (wp->cmd != NULL) format_add(ft, "pane_start_command", "%s", wp->cmd); if (wp->cwd != NULL) format_add(ft, "pane_start_path", "%s", wp->cwd); if ((cwd = get_proc_cwd(wp->fd)) != NULL) format_add(ft, "pane_current_path", "%s", cwd); - format_add(ft, "pane_pid", "%ld", (long) wp->pid); - if (wp->tty != NULL) - format_add(ft, "pane_tty", "%s", wp->tty); + + format_add(ft, "cursor_x", "%d", wp->base.cx); + format_add(ft, "cursor_y", "%d", wp->base.cy); + format_add(ft, "scroll_region_upper", "%d", wp->base.rupper); + format_add(ft, "scroll_region_lower", "%d", wp->base.rlower); + format_add(ft, "saved_cursor_x", "%d", wp->ictx.old_cx); + format_add(ft, "saved_cursor_y", "%d", wp->ictx.old_cy); + + format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0); + format_add(ft, "alternate_saved_x", "%d", wp->saved_cx); + format_add(ft, "alternate_saved_y", "%d", wp->saved_cy); + + format_add(ft, "cursor_flag", "%d", + !!(wp->base.mode & MODE_CURSOR)); + format_add(ft, "insert_flag", "%d", + !!(wp->base.mode & MODE_INSERT)); + format_add(ft, "keypad_cursor_flag", "%d", + !!(wp->base.mode & MODE_KCURSOR)); + format_add(ft, "keypad_flag", "%d", + !!(wp->base.mode & MODE_KKEYPAD)); + format_add(ft, "wrap_flag", "%d", + !!(wp->base.mode & MODE_WRAP)); + + format_add(ft, "mouse_standard_flag", "%d", + !!(wp->base.mode & MODE_MOUSE_STANDARD)); + format_add(ft, "mouse_button_flag", "%d", + !!(wp->base.mode & MODE_MOUSE_BUTTON)); + format_add(ft, "mouse_any_flag", "%d", + !!(wp->base.mode & MODE_MOUSE_ANY)); + format_add(ft, "mouse_utf8_flag", "%d", + !!(wp->base.mode & MODE_MOUSE_UTF8)); } void diff --git a/tmux.1 b/tmux.1 index 9f48c78f..416cefa7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -850,7 +850,7 @@ The following keys are supported as appropriate for the mode: .It Li "Start of line" Ta "0" Ta "C-a" .It Li "Start selection" Ta "Space" Ta "C-Space" .It Li "Top of history" Ta "g" Ta "M->" -.It Li "Transpose chars" Ta "" Ta "C-t" +.It Li "Transpose characters" Ta "" Ta "C-t" .El .Pp The next and previous word keys use space and the @@ -912,6 +912,17 @@ command and keys modified or removed with .Ic bind-key and .Ic unbind-key . +One command in accepts an argument, +.Ic copy-pipe , +which copies the selection and pipes it to a command. +For example the following will bind +.Ql C-q +to copy the selection into +.Pa /tmp +as well as the paste buffer: +.Bd -literal -offset indent +bind-key -temacs-copy C-q copy-pipe "cat >/tmp/out" +.Ed .Pp The paste buffer key pastes the first line from the top paste buffer on the stack. @@ -1052,7 +1063,12 @@ is given, the output goes to stdout, otherwise to the buffer specified with or a new buffer if omitted. If .Fl e -is given, the output includes escape sequences for text and background attributes. +is given, the output includes escape sequences for text and background +attributes. +.Fl C +also escapes non-printable characters as octal \\xxx. +.Fl J +joins wrapped lines. .Pp .Fl S and @@ -2965,6 +2981,9 @@ if it is unattached. The following variables are available, where appropriate: .Bl -column "session_created_string" "Replaced with" -offset indent .It Sy "Variable name" Ta Sy "Replaced with" +.It Li "alternate_on" Ta "If pane is in alternate screen" +.It Li "alternate_saved_x" Ta "Saved cursor X in alternate screen" +.It Li "alternate_saved_y" Ta "Saved cursor Y in alternate screen" .It Li "buffer_sample" Ta "First 50 characters from the specified buffer" .It Li "buffer_size" Ta "Size of the specified buffer in bytes" .It Li "client_activity" Ta "Integer time client last had activity" @@ -2981,16 +3000,27 @@ The following variables are available, where appropriate: .It Li "client_tty" Ta "Pseudo terminal of client" .It Li "client_utf8" Ta "1 if client supports utf8" .It Li "client_width" Ta "Width of client" -.It Li "host" Ta "Hostname of local host" +.It Li "cursor_flag" Ta "Pane cursor flag" +.It Li "cursor_x" Ta "Cursor X position in pane" +.It Li "cursor_y" Ta "Cursor Y position in pane" .It Li "history_bytes" Ta "Number of bytes in window history" .It Li "history_limit" Ta "Maximum window history lines" .It Li "history_size" Ta "Size of history in bytes" +.It Li "host" Ta "Hostname of local host" +.It Li "insert_flag" Ta "Pane insert flag" +.It Li "keypad_cursor_flag" Ta "Pane keypad cursor flag" +.It Li "keypad_flag" Ta "Pane keypad flag" .It Li "line" Ta "Line number in the list" +.It Li "mouse_any_flag" Ta "Pane mouse any flag" +.It Li "mouse_button_flag" Ta "Pane mouse button flag" +.It Li "mouse_standard_flag" Ta "Pane mouse standard flag" +.It Li "mouse_utf8_flag" Ta "Pane mouse UTF-8 flag" .It Li "pane_active" Ta "1 if active pane" .It Li "pane_current_path" Ta "Current path if available" .It Li "pane_dead" Ta "1 if pane is dead" .It Li "pane_height" Ta "Height of pane" .It Li "pane_id" Ta "Unique pane ID" +.It Li "pane_in_mode" Ta "If pane is in a mode" .It Li "pane_index" Ta "Index of pane" .It Li "pane_pid" Ta "PID of first process in pane" .It Li "pane_start_command" Ta "Command pane started with" @@ -2998,6 +3028,10 @@ The following variables are available, where appropriate: .It Li "pane_title" Ta "Title of pane" .It Li "pane_tty" Ta "Pseudo terminal of pane" .It Li "pane_width" Ta "Width of pane" +.It Li "saved_cursor_x" Ta "Saved cursor X in pane" +.It Li "saved_cursor_y" Ta "Saved cursor Y in pane" +.It Li "scroll_region_lower" Ta "Bottom of scroll region in pane" +.It Li "scroll_region_upper" Ta "Top of scroll region in pane" .It Li "session_attached" Ta "1 if session attached" .It Li "session_created" Ta "Integer time session created" .It Li "session_created_string" Ta "String time session created" @@ -3017,6 +3051,7 @@ The following variables are available, where appropriate: .It Li "window_name" Ta "Name of window" .It Li "window_panes" Ta "Number of panes in window" .It Li "window_width" Ta "Width of window" +.It Li "wrap_flag" Ta "Pane wrap flag" .El .Sh NAMES AND TITLES .Nm From ac1fe83596c7e7aa3639b61be8e5531e09b5bbe8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 22 Mar 2013 18:45:36 +0000 Subject: [PATCH 49/91] Couple of fixes pointed out by jmc. --- tmux.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 416cefa7..33929eff 100644 --- a/tmux.1 +++ b/tmux.1 @@ -912,7 +912,7 @@ command and keys modified or removed with .Ic bind-key and .Ic unbind-key . -One command in accepts an argument, +One command accepts an argument, .Ic copy-pipe , which copies the selection and pipes it to a command. For example the following will bind @@ -1066,7 +1066,7 @@ If is given, the output includes escape sequences for text and background attributes. .Fl C -also escapes non-printable characters as octal \\xxx. +also escapes non-printable characters as octal \exxx. .Fl J joins wrapped lines. .Pp From 1ec43549989208019f6e5b71348594067819aed4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:18:16 +0000 Subject: [PATCH 50/91] Add support for focus notifications when tmux pane changes, based on work by Aaron Jensen. --- input.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/input.c b/input.c index d345a0c4..0dcdee96 100644 --- a/input.c +++ b/input.c @@ -1260,6 +1260,9 @@ input_csi_dispatch(struct input_ctx *ictx) case 1003: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); break; + case 1004: + screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON); + break; case 1005: screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8); break; @@ -1326,6 +1329,12 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY); break; + case 1004: + if (s->mode & MODE_FOCUSON) + break; + screen_write_mode_set(&ictx->ctx, MODE_FOCUSON); + wp->flags &= ~PANE_FOCUSED; /* force update if needed */ + break; case 1005: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); break; From 8094e822873fd22d614a1e2fe7d0dfd63f9d2a47 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:21:27 +0000 Subject: [PATCH 51/91] Add option command-prefix which is automatically prepended to any command (apart from a naked default-shell). The default is "exec ". --- names.c | 24 ++++++++++++++---------- options-table.c | 6 +++++- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/names.c b/names.c index 76dec82c..ce5d0c51 100644 --- a/names.c +++ b/names.c @@ -26,8 +26,8 @@ #include "tmux.h" -void window_name_callback(unused int, unused short, void *); -char *parse_window_name(const char *); +void window_name_callback(int, short, void *); +char *parse_window_name(struct window *, const char *); void queue_window_name(struct window *w) @@ -73,9 +73,9 @@ window_name_callback(unused int fd, unused short events, void *data) */ if (w->active->cmd != NULL && *w->active->cmd == '\0' && name != NULL && name[0] == '-' && name[1] != '\0') - wname = parse_window_name(name + 1); + wname = parse_window_name(w, name + 1); else - wname = parse_window_name(name); + wname = parse_window_name(w, name); free(name); } @@ -98,18 +98,22 @@ default_window_name(struct window *w) if (w->active->screen != &w->active->base) return (xstrdup("[tmux]")); if (w->active->cmd != NULL && *w->active->cmd != '\0') - return (parse_window_name(w->active->cmd)); - return (parse_window_name(w->active->shell)); + return (parse_window_name(w, w->active->cmd)); + return (parse_window_name(w, w->active->shell)); } char * -parse_window_name(const char *in) +parse_window_name(struct window *w, const char *in) { - char *copy, *name, *ptr; + char *copy, *name, *ptr, *prefix; + size_t prefixlen; + + prefix = options_get_string(&w->options, "command-prefix"); + prefixlen = strlen(prefix); name = copy = xstrdup(in); - if (strncmp(name, "exec ", (sizeof "exec ") - 1) == 0) - name = name + (sizeof "exec ") - 1; + if (strncmp(name, prefix, prefixlen) == 0) + name = name + prefixlen; while (*name == ' ') name++; diff --git a/options-table.c b/options-table.c index 23828bf8..5f9c81b1 100644 --- a/options-table.c +++ b/options-table.c @@ -477,7 +477,6 @@ const struct options_table_entry window_options_table[] = { .default_num = 1 }, - { .name = "c0-change-trigger", .type = OPTIONS_TABLE_NUMBER, .default_num = 250, @@ -503,6 +502,11 @@ const struct options_table_entry window_options_table[] = { .default_num = 1 }, + { .name = "command-prefix", + .type = OPTIONS_TABLE_STRING, + .default_str = "exec " + }, + { .name = "force-height", .type = OPTIONS_TABLE_NUMBER, .minimum = 0, From 3eae71b5b28cf591f6cff652e2f2c67be394c040 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:25:04 +0000 Subject: [PATCH 52/91] Do pane resize ioctls once at the end of the server loop rather than immediately. --- window.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/window.c b/window.c index 79ade400..dfece2ee 100644 --- a/window.c +++ b/window.c @@ -310,24 +310,36 @@ window_create1(u_int sx, u_int sy) struct window * window_create(const char *name, const char *cmd, const char *shell, const char *cwd, struct environ *env, struct termios *tio, - u_int sx, u_int sy, u_int hlimit,char **cause) + u_int sx, u_int sy, u_int hlimit, char **cause) { struct window *w; struct window_pane *wp; + const char *prefix; + char *cmd1; w = window_create1(sx, sy); wp = window_add_pane(w, hlimit); layout_init(w); - if (window_pane_spawn(wp, cmd, shell, cwd, env, tio, cause) != 0) { + + if (*cmd != '\0') { + prefix = options_get_string(&w->options, "command-prefix"); + xasprintf(&cmd1, "%s%s", prefix, cmd); + } else + cmd1 = xstrdup(""); + if (window_pane_spawn(wp, cmd1, shell, cwd, env, tio, cause) != 0) { window_destroy(w); + free(cmd1); return (NULL); } + free(cmd1); + w->active = TAILQ_FIRST(&w->panes); if (name != NULL) { w->name = xstrdup(name); options_set_number(&w->options, "automatic-rename", 0); } else w->name = default_window_name(w); + return (w); } @@ -704,6 +716,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, wp->cwd = xstrdup(cwd); } + log_debug("spawn: %s -- %s", wp->shell, wp->cmd); + memset(&ws, 0, sizeof ws); ws.ws_col = screen_size_x(&wp->base); ws.ws_row = screen_size_y(&wp->base); @@ -840,23 +854,14 @@ window_pane_error_callback( void window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) { - struct winsize ws; - if (sx == wp->sx && sy == wp->sy) return; wp->sx = sx; wp->sy = sy; - memset(&ws, 0, sizeof ws); - ws.ws_col = sx; - ws.ws_row = sy; - screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL); if (wp->mode != NULL) wp->mode->resize(wp, sx, sy); - - if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) - fatal("ioctl failed"); } /* From bb8457b166635bc8d069012bb33d94e44178bfdc Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:27:19 +0000 Subject: [PATCH 53/91] Fix error reporting for client commands by adding a flag to cmd_find_client to tell it whether or not to show errors, sometimes it's needed and sometimes not. --- cmd-break-pane.c | 2 +- cmd-command-prompt.c | 2 +- cmd-confirm-before.c | 2 +- cmd-detach-client.c | 2 +- cmd-display-message.c | 6 ++---- cmd-display-panes.c | 2 +- cmd-lock-server.c | 2 +- cmd-new-window.c | 2 +- cmd-pipe-pane.c | 2 +- cmd-refresh-client.c | 2 +- cmd-show-messages.c | 2 +- cmd-split-window.c | 19 ++++++++++++++----- cmd-suspend-client.c | 2 +- cmd-switch-client.c | 2 +- cmd.c | 12 ++++++++---- 15 files changed, 36 insertions(+), 25 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 57628a7a..a5a78077 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -97,7 +97,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) template = BREAK_PANE_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(ctx, NULL)) != NULL) + if ((c = cmd_find_client(ctx, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 80407b7d..3a43b24f 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -94,7 +94,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) char *prompt, *ptr, *input = NULL; size_t n; - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); if (c->prompt_string != NULL) diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index f9491095..765f58df 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -79,7 +79,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_ERROR); } - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); if ((prompt = args_get(args, 'p')) != NULL) diff --git a/cmd-detach-client.c b/cmd-detach-client.c index b437ddd3..a1d3a386 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -61,7 +61,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) server_write_client(c, msgtype, NULL, 0); } } else { - c = cmd_find_client(ctx, args_get(args, 't')); + c = cmd_find_client(ctx, args_get(args, 't'), 0); if (c == NULL) return (CMD_RETURN_ERROR); diff --git a/cmd-display-message.c b/cmd-display-message.c index 899957f8..05c3a408 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -55,9 +55,6 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) time_t t; size_t len; - if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) - return (CMD_RETURN_ERROR); - if (args_has(args, 't')) { wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); if (wl == NULL) @@ -80,7 +77,8 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) template = DISPLAY_MESSAGE_TEMPLATE; ft = format_create(); - format_client(ft, c); + if ((c = cmd_find_client(ctx, args_get(args, 'c'), 1)) != NULL) + format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); format_window_pane(ft, wp); diff --git a/cmd-display-panes.c b/cmd-display-panes.c index 5f0893d4..b3e67fd2 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -42,7 +42,7 @@ cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct client *c; - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); server_set_identify(c); diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 16a34a44..c95379ac 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -74,7 +74,7 @@ cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx) return (CMD_RETURN_ERROR); server_lock_session(s); } else { - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); server_lock_client(c); } diff --git a/cmd-new-window.c b/cmd-new-window.c index 331c9fc8..0ab05e26 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -126,7 +126,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) template = NEW_WINDOW_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(ctx, NULL)) != NULL) + if ((c = cmd_find_client(ctx, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index a332b0ca..bb17c6be 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -57,7 +57,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); - c = cmd_find_client(ctx, NULL); + c = cmd_find_client(ctx, NULL, 1); /* Destroy the old pipe. */ old_fd = wp->pipe_fd; diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 885e8165..25df230f 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -44,7 +44,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx) const char *size; u_int w, h; - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); if (args_has(args, 'C')) { diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 038b673c..8394e3de 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -48,7 +48,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) char *tim; u_int i; - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { diff --git a/cmd-split-window.c b/cmd-split-window.c index d225ce23..b9eb92e3 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -59,8 +59,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; struct window_pane *wp, *new_wp = NULL; struct environ env; - const char *cmd, *cwd, *shell; - char *cause, *new_cause; + const char *cmd, *cwd, *shell, *prefix; + char *cause, *new_cause, *cmd1; u_int hlimit; int size, percentage; enum layout_type type; @@ -122,9 +122,18 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) goto error; } new_wp = window_add_pane(w, hlimit); - if (window_pane_spawn( - new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0) + + if (*cmd != '\0') { + prefix = options_get_string(&w->options, "command-prefix"); + xasprintf(&cmd1, "%s%s", prefix, cmd); + } else + cmd1 = xstrdup(""); + if (window_pane_spawn(new_wp, cmd1, shell, cwd, &env, s->tio, + &cause) != 0) { + free(cmd1); goto error; + } + free(cmd1); layout_assign_pane(lc, new_wp); server_redraw_window(w); @@ -143,7 +152,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) template = SPLIT_WINDOW_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(ctx, NULL)) != NULL) + if ((c = cmd_find_client(ctx, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index 24077d7f..c3806c6f 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -45,7 +45,7 @@ cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx) struct args *args = self->args; struct client *c; - if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); tty_stop_tty(&c->tty); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 991974fd..0fcf0146 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -64,7 +64,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) struct client *c; struct session *s; - if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL) + if ((c = cmd_find_client(ctx, args_get(args, 'c'), 0)) == NULL) return (CMD_RETURN_ERROR); if (args_has(args, 'r')) { diff --git a/cmd.c b/cmd.c index 6ab1f430..6fe4d565 100644 --- a/cmd.c +++ b/cmd.c @@ -517,15 +517,19 @@ cmd_choose_client(struct clients *cc) /* Find the target client or report an error and return NULL. */ struct client * -cmd_find_client(struct cmd_ctx *ctx, const char *arg) +cmd_find_client(struct cmd_ctx *ctx, const char *arg, int quiet) { struct client *c; char *tmparg; size_t arglen; /* A NULL argument means the current client. */ - if (arg == NULL) - return (cmd_current_client(ctx)); + if (arg == NULL) { + c = cmd_current_client(ctx); + if (c == NULL && !quiet) + ctx->error(ctx, "no clients"); + return (c); + } tmparg = xstrdup(arg); /* Trim a single trailing colon if any. */ @@ -537,7 +541,7 @@ cmd_find_client(struct cmd_ctx *ctx, const char *arg) c = cmd_lookup_client(tmparg); /* If no client found, report an error. */ - if (c == NULL) + if (c == NULL && !quiet) ctx->error(ctx, "client not found: %s", tmparg); free(tmparg); From a60687f9ba924abcb2934f1e7b603e3885dcd2ef Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:28:59 +0000 Subject: [PATCH 54/91] Handle focus events from the terminal, from Aaron Jensen. --- server-client.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++-- tmux.h | 9 ++++- tty-keys.c | 13 +++++++ tty.c | 4 +-- 4 files changed, 111 insertions(+), 5 deletions(-) diff --git a/server-client.c b/server-client.c index 492d6b22..ef4936fc 100644 --- a/server-client.c +++ b/server-client.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -28,6 +29,8 @@ #include "tmux.h" +void server_client_check_focus(struct window_pane *); +void server_client_check_resize(struct window_pane *); void server_client_check_mouse(struct client *, struct window_pane *); void server_client_repeat_timer(int, short, void *); void server_client_check_exit(struct client *); @@ -94,6 +97,8 @@ server_client_create(int fd) c->tty.mouse.event = MOUSE_EVENT_UP; c->tty.mouse.flags = 0; + c->flags |= CLIENT_FOCUSED; + evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { @@ -495,7 +500,7 @@ server_client_loop(void) /* * Any windows will have been redrawn as part of clients, so clear - * their flags now. + * their flags now. Also check pane focus and resize. */ for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); @@ -503,11 +508,92 @@ server_client_loop(void) continue; w->flags &= ~WINDOW_REDRAW; - TAILQ_FOREACH(wp, &w->panes, entry) + TAILQ_FOREACH(wp, &w->panes, entry) { + server_client_check_focus(wp); + server_client_check_resize(wp); wp->flags &= ~PANE_REDRAW; + } } } +/* Check if pane should be resized. */ +void +server_client_check_resize(struct window_pane *wp) +{ + struct winsize ws; + + if (wp->fd == -1 || !(wp->flags & PANE_RESIZE)) + return; + + memset(&ws, 0, sizeof ws); + ws.ws_col = wp->sx; + ws.ws_row = wp->sy; + + if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) { +#ifdef __sun + /* + * Some versions of Solaris apparently can return an error when + * resizing; don't know why this happens, can't reproduce on + * other platforms and ignoring it doesn't seem to cause any + * issues. + */ + if (errno != EINVAL) +#endif + fatal("ioctl failed"); + } + + wp->flags &= ~PANE_RESIZE; +} + +/* Check whether pane should be focused. */ +void +server_client_check_focus(struct window_pane *wp) +{ + u_int i; + struct client *c; + + /* If we don't care about focus, forget it. */ + if (!(wp->base.mode & MODE_FOCUSON)) + return; + + /* If we're not the active pane in our window, we're not focused. */ + if (wp->window->active != wp) + goto not_focused; + + /* If we're in a mode, we're not focused. */ + if (wp->screen != &wp->base) + goto not_focused; + + /* + * If our window is the current window in any focused clients with an + * attached session, we're focused. + */ + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + + if (!(c->flags & CLIENT_FOCUSED)) + continue; + if (c->session->flags & SESSION_UNATTACHED) + continue; + + if (c->session->curw->window == wp->window) + goto focused; + } + +not_focused: + if (wp->flags & PANE_FOCUSED) + bufferevent_write(wp->event, "\033[O", 3); + wp->flags &= ~PANE_FOCUSED; + return; + +focused: + if (!(wp->flags & PANE_FOCUSED)) + bufferevent_write(wp->event, "\033[I", 3); + wp->flags |= PANE_FOCUSED; +} + /* * Update cursor position and mode settings. The scroll region and attributes * are cleared when idle (waiting for an event) as this is the most likely time diff --git a/tmux.h b/tmux.h index 720c1429..b71df280 100644 --- a/tmux.h +++ b/tmux.h @@ -241,6 +241,9 @@ enum key_code { KEYC_KP_ENTER, KEYC_KP_ZERO, KEYC_KP_PERIOD, + + KEYC_FOCUS_IN, + KEYC_FOCUS_OUT, }; /* Termcap codes. */ @@ -669,6 +672,7 @@ struct mode_key_table { #define MODE_MOUSE_UTF8 0x100 #define MODE_MOUSE_SGR 0x200 #define MODE_BRACKETPASTE 0x400 +#define MODE_FOCUSON 0x800 #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY) @@ -930,6 +934,8 @@ struct window_pane { int flags; #define PANE_REDRAW 0x1 #define PANE_DROP 0x2 +#define PANE_FOCUSED 0x4 +#define PANE_RESIZE 0x8 char *cmd; char *shell; @@ -1317,6 +1323,7 @@ struct client { #define CLIENT_READONLY 0x800 #define CLIENT_REDRAWWINDOW 0x1000 #define CLIENT_CONTROL 0x2000 +#define CLIENT_FOCUSED 0x4000 int flags; struct event identify_timer; @@ -1729,7 +1736,7 @@ struct cmd *cmd_parse(int, char **, char **); size_t cmd_print(struct cmd *, char *, size_t); struct session *cmd_current_session(struct cmd_ctx *, int); struct client *cmd_current_client(struct cmd_ctx *); -struct client *cmd_find_client(struct cmd_ctx *, const char *); +struct client *cmd_find_client(struct cmd_ctx *, const char *, int); struct session *cmd_find_session(struct cmd_ctx *, const char *, int); struct winlink *cmd_find_window( struct cmd_ctx *, const char *, struct session **); diff --git a/tty-keys.c b/tty-keys.c index cb34df93..fc79c89b 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -174,6 +174,10 @@ const struct tty_default_key_raw tty_default_raw_keys[] = { { "\033[8@", KEYC_END|KEYC_CTRL|KEYC_SHIFT }, { "\033[6@", KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT }, { "\033[5@", KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT }, + + /* Focus tracking. */ + { "\033[I", KEYC_FOCUS_IN }, + { "\033[O", KEYC_FOCUS_OUT }, }; /* Default terminfo(5) keys. */ @@ -559,6 +563,15 @@ complete_key: evtimer_del(&tty->key_timer); tty->flags &= ~TTY_TIMER; + /* Check for focus events. */ + if (key == KEYC_FOCUS_OUT) { + tty->client->flags &= ~CLIENT_FOCUSED; + return (1); + } else if (key == KEYC_FOCUS_IN) { + tty->client->flags |= CLIENT_FOCUSED; + return (1); + } + /* Fire the key. */ if (key != KEYC_NONE) server_client_handle_key(tty->client, key); diff --git a/tty.c b/tty.c index 1ee70d39..75a2f657 100644 --- a/tty.c +++ b/tty.c @@ -221,7 +221,7 @@ tty_start_tty(struct tty *tty) tty_puts(tty, "\033[?1000l\033[?1006l\033[?1005l"); if (tty_term_has(tty->term, TTYC_XT)) - tty_puts(tty, "\033[c\033[>4;1m"); + tty_puts(tty, "\033[c\033[>4;1m\033[?1004h"); tty->cx = UINT_MAX; tty->cy = UINT_MAX; @@ -284,7 +284,7 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, "\033[?1000l\033[?1006l\033[?1005l"); if (tty_term_has(tty->term, TTYC_XT)) - tty_raw(tty, "\033[>4m"); + tty_raw(tty, "\033[>4m\033[?1004l"); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); From 86adcd4b2666344e9e77fc8f27ab8124557713f2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:29:40 +0000 Subject: [PATCH 55/91] Add pane_tabs format to format_window_pane based on code from George Nachman. --- format.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/format.c b/format.c index 7e442e0a..4c93c766 100644 --- a/format.c +++ b/format.c @@ -32,8 +32,9 @@ * string. */ -int format_replace(struct format_tree *, - const char *, size_t, char **, size_t *, size_t *); +int format_replace(struct format_tree *, const char *, size_t, char **, + size_t *, size_t *); +void format_window_pane_tabs(struct format_tree *, struct window_pane *); /* Format key-value replacement entry. */ RB_GENERATE(format_tree, format_entry, entry, format_cmp); @@ -367,6 +368,28 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) free(layout); } +/* Add window pane tabs. */ +void +format_window_pane_tabs(struct format_tree *ft, struct window_pane *wp) +{ + struct evbuffer *buffer; + u_int i; + + buffer = evbuffer_new(); + for (i = 0; i < wp->base.grid->sx; i++) { + if (!bit_test(wp->base.tabs, i)) + continue; + + if (EVBUFFER_LENGTH(buffer) > 0) + evbuffer_add(buffer, ",", 1); + evbuffer_add_printf(buffer, "%d", i); + } + + format_add(ft, "pane_tabs", "%.*s", (int) EVBUFFER_LENGTH(buffer), + EVBUFFER_DATA(buffer)); + evbuffer_free(buffer); +} + /* Set default format keys for a window pane. */ void format_window_pane(struct format_tree *ft, struct window_pane *wp) @@ -377,6 +400,7 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) u_int i; u_int idx; const char *cwd; + const char *cmd; size = 0; for (i = 0; i < gd->hsize; i++) { @@ -410,6 +434,8 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_start_path", "%s", wp->cwd); if ((cwd = get_proc_cwd(wp->fd)) != NULL) format_add(ft, "pane_current_path", "%s", cwd); + if ((cmd = get_proc_name(wp->fd, wp->tty)) != NULL) + format_add(ft, "pane_current_command", "%s", cmd); format_add(ft, "cursor_x", "%d", wp->base.cx); format_add(ft, "cursor_y", "%d", wp->base.cy); @@ -441,8 +467,11 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) !!(wp->base.mode & MODE_MOUSE_ANY)); format_add(ft, "mouse_utf8_flag", "%d", !!(wp->base.mode & MODE_MOUSE_UTF8)); + + format_window_pane_tabs(ft, wp); } +/* Set default format keys for paste buffer. */ void format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) { From 66edb3392b234ccd9a940039936edb34258c2102 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:33:35 +0000 Subject: [PATCH 56/91] Expand format variables in the run-shell and if-shell shell commands, from Thiago Padilha. --- cmd-if-shell.c | 22 +++++++++++++++++++--- cmd-run-shell.c | 17 ++++++++++++++--- tmux.1 | 23 ++++++++++++++++++++++- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index ab69e8b5..e0e2c230 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -36,8 +36,8 @@ void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", - "", 2, 3, - "shell-command command [command]", + "t:", 2, 3, + CMD_TARGET_PANE_USAGE " shell-command command [command]", 0, NULL, NULL, @@ -55,7 +55,22 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct cmd_if_shell_data *cdata; - const char *shellcmd = args->argv[0]; + char *shellcmd; + struct session *s; + struct winlink *wl; + struct window_pane *wp; + struct format_tree *ft; + + wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); + if (wl == NULL) + return (CMD_RETURN_ERROR); + + ft = format_create(); + format_session(ft, s); + format_winlink(ft, s, wl); + format_window_pane(ft, wp); + shellcmd = format_expand(ft, args->argv[0]); + format_free(ft); cdata = xmalloc(sizeof *cdata); cdata->cmd_if = xstrdup(args->argv[1]); @@ -68,6 +83,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_ref_ctx(ctx); job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata); + free(shellcmd); return (CMD_RETURN_YIELD); /* don't let client exit */ } diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 0d19a8e6..3942fa11 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -75,14 +75,25 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct cmd_run_shell_data *cdata; - const char *shellcmd = args->argv[0]; + char *shellcmd; + struct session *s; + struct winlink *wl; struct window_pane *wp; + struct format_tree *ft; - if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) + wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); + if (wl == NULL) return (CMD_RETURN_ERROR); + ft = format_create(); + format_session(ft, s); + format_winlink(ft, s, wl); + format_window_pane(ft, wp); + shellcmd = format_expand(ft, args->argv[0]); + format_free(ft); + cdata = xmalloc(sizeof *cdata); - cdata->cmd = xstrdup(args->argv[0]); + cdata->cmd = shellcmd; cdata->wp_id = wp->id; cdata->ctx = ctx; diff --git a/tmux.1 b/tmux.1 index 33929eff..d708aace 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2704,6 +2704,13 @@ Set clock colour. .Xc Set clock hour format. .Pp +.It Ic command-prefix Ar string +String prefixed to commands (apart from a plain shell as set by the +.Ic default-shell +option). +The default is +.Ql "exec\ " . +.Pp .It Ic force-height Ar height .It Ic force-width Ar width Prevent @@ -3016,6 +3023,7 @@ The following variables are available, where appropriate: .It Li "mouse_standard_flag" Ta "Pane mouse standard flag" .It Li "mouse_utf8_flag" Ta "Pane mouse UTF-8 flag" .It Li "pane_active" Ta "1 if active pane" +.It Li "pane_current_command" Ta "Current command if available" .It Li "pane_current_path" Ta "Current path if available" .It Li "pane_dead" Ta "1 if pane is dead" .It Li "pane_height" Ta "Height of pane" @@ -3025,6 +3033,7 @@ The following variables are available, where appropriate: .It Li "pane_pid" Ta "PID of first process in pane" .It Li "pane_start_command" Ta "Command pane started with" .It Li "pane_start_path" Ta "Path pane started with" +.It Li "pane_tabs" Ta "Pane tab positions" .It Li "pane_title" Ta "Title of pane" .It Li "pane_tty" Ta "Pseudo terminal of pane" .It Li "pane_width" Ta "Width of pane" @@ -3455,7 +3464,11 @@ Miscellaneous commands are as follows: .Bl -tag -width Ds .It Ic clock-mode Op Fl t Ar target-pane Display a large clock. -.It Ic if-shell Ar shell-command command Op Ar command +.It Xo Ic if-shell +.Op Fl t Ar target-pane +.Ar shell-command command +.Op Ar command +.Xc .D1 (alias: Ic if ) Execute the first .Ar command @@ -3464,6 +3477,10 @@ if returns success or the second .Ar command otherwise. +Before being executed, shell-command is expanded using the rules specified in the +.Sx FORMATS +section, including those relevant to +.Ar target-pane . .It Ic lock-server .D1 (alias: Ic lock ) Lock each client individually by running the command specified by the @@ -3477,6 +3494,10 @@ option. Execute .Ar shell-command in the background without creating a window. +Before being executed, shell-command is expanded using the rules specified in +the +.Sx FORMATS +section. After it finishes, any output to stdout is displayed in copy mode (in the pane specified by .Fl t From 20636d956dd36c1f14152569a4d44a50eea9083d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:54:10 +0000 Subject: [PATCH 57/91] Add a command queue to standardize and simplify commands that call other commands and allow a command to block execution of subsequent commands. This allows run-shell and if-shell to be synchronous which has been much requested. Each client has a default command queue and commands are consumed one at a time from it. A command may suspend execution from the queue by returning CMD_RETURN_WAIT and then resume it by calling cmd_continue() - for example run-shell does this from the callback that is fired after the job is freed. When the command queue becomes empty, command clients are automatically exited (unless attaching). A callback is also fired - this is used for nested commands in, for example, if-shell which can block execution of the client's cmdq until a new cmdq becomes empty. Also merge all the old error/info/print functions together and lose the old curclient/cmdclient distinction - a cmdq is bound to one client (or none if in the configuration file), this is a command client if c->session is NULL otherwise an attached client. --- Makefile | 3 +- cfg.c | 130 ++++++--------------- client.c | 3 +- cmd-attach-session.c | 43 +++---- cmd-bind-key.c | 25 ++-- cmd-break-pane.c | 12 +- cmd-capture-pane.c | 19 ++- cmd-choose-buffer.c | 10 +- cmd-choose-client.c | 12 +- cmd-choose-list.c | 10 +- cmd-choose-tree.c | 10 +- cmd-clear-history.c | 6 +- cmd-clock-mode.c | 6 +- cmd-command-prompt.c | 17 +-- cmd-confirm-before.c | 44 ++++--- cmd-copy-mode.c | 6 +- cmd-delete-buffer.c | 8 +- cmd-detach-client.c | 10 +- cmd-display-message.c | 16 +-- cmd-display-panes.c | 6 +- cmd-find-window.c | 12 +- cmd-has-session.c | 6 +- cmd-if-shell.c | 77 ++++++++---- cmd-join-pane.c | 24 ++-- cmd-kill-pane.c | 6 +- cmd-kill-server.c | 4 +- cmd-kill-session.c | 6 +- cmd-kill-window.c | 6 +- cmd-link-window.c | 10 +- cmd-list-buffers.c | 6 +- cmd-list-clients.c | 8 +- cmd-list-commands.c | 8 +- cmd-list-keys.c | 16 +-- cmd-list-panes.c | 32 ++--- cmd-list-sessions.c | 6 +- cmd-list-windows.c | 22 ++-- cmd-list.c | 73 ++---------- cmd-load-buffer.c | 30 ++--- cmd-lock-server.c | 10 +- cmd-move-window.c | 12 +- cmd-new-session.c | 148 ++++++++++------------- cmd-new-window.c | 20 ++-- cmd-paste-buffer.c | 10 +- cmd-pipe-pane.c | 12 +- cmd-queue.c | 258 +++++++++++++++++++++++++++++++++++++++++ cmd-refresh-client.c | 14 +-- cmd-rename-session.c | 10 +- cmd-rename-window.c | 6 +- cmd-resize-pane.c | 12 +- cmd-respawn-pane.c | 10 +- cmd-respawn-window.c | 10 +- cmd-rotate-window.c | 6 +- cmd-run-shell.c | 45 ++++--- cmd-save-buffer.c | 140 +++++++++++++++------- cmd-select-layout.c | 14 +-- cmd-select-pane.c | 14 +-- cmd-select-window.c | 16 +-- cmd-send-keys.c | 25 +++- cmd-server-info.c | 54 ++++----- cmd-set-buffer.c | 8 +- cmd-set-environment.c | 16 +-- cmd-show-environment.c | 16 +-- cmd-show-messages.c | 8 +- cmd-show-options.c | 42 +++---- cmd-source-file.c | 80 +++++++++---- cmd-split-window.c | 16 +-- cmd-start-server.c | 4 +- cmd-string.c | 5 +- cmd-suspend-client.c | 6 +- cmd-swap-pane.c | 8 +- cmd-swap-window.c | 10 +- cmd-switch-client.c | 18 +-- cmd-unbind-key.c | 14 +-- cmd-unlink-window.c | 8 +- cmd.c | 156 ++++++++++--------------- control.c | 51 +------- format.c | 6 +- key-bindings.c | 79 +------------ server-client.c | 83 ++----------- server-fn.c | 4 +- server.c | 42 ++++--- tmux.c | 2 - tmux.h | 136 ++++++++++++---------- window-choose.c | 15 +-- 84 files changed, 1240 insertions(+), 1187 deletions(-) create mode 100644 cmd-queue.c diff --git a/Makefile b/Makefile index cebcac8e..f78b1615 100644 --- a/Makefile +++ b/Makefile @@ -60,12 +60,10 @@ SRCS= arguments.c \ cmd-select-pane.c \ cmd-select-window.c \ cmd-send-keys.c \ - cmd-send-prefix.c \ cmd-server-info.c \ cmd-set-buffer.c \ cmd-set-environment.c \ cmd-set-option.c \ - cmd-show-buffer.c \ cmd-show-environment.c \ cmd-show-messages.c \ cmd-show-options.c \ @@ -80,6 +78,7 @@ SRCS= arguments.c \ cmd-unbind-key.c \ cmd-unlink-window.c \ cmd.c \ + cmd-queue.c \ colour.c \ control.c \ control-notify.c \ diff --git a/cfg.c b/cfg.c index b7b0ec78..e4069d68 100644 --- a/cfg.c +++ b/cfg.c @@ -27,80 +27,27 @@ #include "tmux.h" -/* - * Config file parser. Pretty quick and simple, each line is parsed into a - * argv array and executed as a command. - */ - -void printflike2 cfg_print(struct cmd_ctx *, const char *, ...); -void printflike2 cfg_error(struct cmd_ctx *, const char *, ...); - -char *cfg_cause; +struct cmd_q *cfg_cmd_q; int cfg_finished; -int cfg_references; +int cfg_references; struct causelist cfg_causes; -void printflike2 -cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...) -{ -} - -void printflike2 -cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - xvasprintf(&cfg_cause, fmt, ap); - va_end(ap); -} - -void printflike2 -cfg_add_cause(struct causelist *causes, const char *fmt, ...) -{ - char *cause; - va_list ap; - - va_start(ap, fmt); - xvasprintf(&cause, fmt, ap); - va_end(ap); - - ARRAY_ADD(causes, cause); -} - -/* - * Load configuration file. Returns -1 for an error with a list of messages in - * causes. Note that causes must be initialised by the caller! - */ -enum cmd_retval -load_cfg(const char *path, struct cmd_ctx *ctx, struct causelist *causes) +int +load_cfg(const char *path, struct cmd_q *cmdq, char **cause) { FILE *f; - u_int n; - char *buf, *copy, *line, *cause; + u_int n, found; + char *buf, *copy, *line, *cause1, *msg; size_t len, oldlen; struct cmd_list *cmdlist; - enum cmd_retval retval; if ((f = fopen(path, "rb")) == NULL) { - cfg_add_cause(causes, "%s: %s", path, strerror(errno)); - return (CMD_RETURN_ERROR); + xasprintf(cause, "%s: %s", path, strerror(errno)); + return (-1); } - cfg_references++; - - if (ctx != NULL) - cmd_ref_ctx(ctx); - else { - ctx = cmd_get_ctx(NULL, NULL); - ctx->error = cfg_error; - ctx->print = cfg_print; - ctx->info = cfg_print; - } - - n = 0; + n = found = 0; line = NULL; - retval = CMD_RETURN_NORMAL; while ((buf = fgetln(f, &len))) { /* Trim \n. */ if (buf[len - 1] == '\n') @@ -142,53 +89,47 @@ load_cfg(const char *path, struct cmd_ctx *ctx, struct causelist *causes) continue; } - if (cmd_string_parse(buf, &cmdlist, &cause) != 0) { + /* Parse and run the command. */ + if (cmd_string_parse(buf, &cmdlist, path, n, &cause1) != 0) { free(copy); - if (cause == NULL) + if (cause1 == NULL) continue; - cfg_add_cause(causes, "%s: %u: %s", path, n, cause); - free(cause); + xasprintf(&msg, "%s:%u: %s", path, n, cause1); + ARRAY_ADD(&cfg_causes, msg); + free(cause1); continue; } free(copy); + if (cmdlist == NULL) continue; - - cfg_cause = NULL; - switch (cmd_list_exec(cmdlist, ctx)) { - case CMD_RETURN_YIELD: - if (retval != CMD_RETURN_ATTACH) - retval = CMD_RETURN_YIELD; - break; - case CMD_RETURN_ATTACH: - retval = CMD_RETURN_ATTACH; - break; - case CMD_RETURN_ERROR: - case CMD_RETURN_NORMAL: - break; - } + cmdq_append(cmdq, cmdlist); cmd_list_free(cmdlist); - if (cfg_cause != NULL) { - cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause); - free(cfg_cause); - } + found++; } - if (line != NULL) { - cfg_add_cause(causes, - "%s: %d: line continuation at end of file", path, n); + if (line != NULL) free(line); - } fclose(f); - cmd_free_ctx(ctx); - - cfg_references--; - - return (retval); + return (found); } void -show_cfg_causes(struct session *s) +cfg_default_done(unused struct cmd_q *cmdq) +{ + if (--cfg_references != 0) + return; + cfg_finished = 1; + + if (!RB_EMPTY(&sessions)) + cfg_show_causes(RB_MIN(sessions, &sessions)); + + cmdq_free(cfg_cmd_q); + cfg_cmd_q = NULL; +} + +void +cfg_show_causes(struct session *s) { struct window_pane *wp; char *cause; @@ -196,7 +137,6 @@ show_cfg_causes(struct session *s) if (s == NULL || ARRAY_EMPTY(&cfg_causes)) return; - wp = s->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); diff --git a/client.c b/client.c index 92c3fca3..8693afeb 100644 --- a/client.c +++ b/client.c @@ -188,7 +188,8 @@ client_main(int argc, char **argv, int flags) * later in server) but it is necessary to get the start server * flag. */ - if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { + cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause); + if (cmdlist == NULL) { fprintf(stderr, "%s\n", cause); return (1); } diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 30451389..0298dda1 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -26,7 +26,7 @@ * Attach existing session to the current terminal. */ -enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_attach_session_entry = { }; enum cmd_retval -cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -49,17 +49,17 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i; if (RB_EMPTY(&sessions)) { - ctx->error(ctx, "no sessions"); + cmdq_error(cmdq, "no sessions"); return (CMD_RETURN_ERROR); } - if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL) + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 1)) == NULL) return (CMD_RETURN_ERROR); - if (ctx->cmdclient == NULL && ctx->curclient == NULL) + if (cmdq->client == NULL) return (CMD_RETURN_NORMAL); - if (ctx->cmdclient == NULL) { + if (cmdq->client->session != NULL) { if (args_has(self->args, 'd')) { /* * Can't use server_write_session in case attaching to @@ -69,43 +69,44 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; - if (c == ctx->curclient) + if (c == cmdq->client) continue; server_write_client(c, MSG_DETACH, NULL, 0); } } - ctx->curclient->session = s; - notify_attached_session_changed(ctx->curclient); + cmdq->client->session = s; + notify_attached_session_changed(cmdq->client); session_update_activity(s); - server_redraw_client(ctx->curclient); + server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { - if (server_client_open(ctx->cmdclient, s, &cause) != 0) { - ctx->error(ctx, "open terminal failed: %s", cause); + if (server_client_open(cmdq->client, s, &cause) != 0) { + cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } if (args_has(self->args, 'r')) - ctx->cmdclient->flags |= CLIENT_READONLY; + cmdq->client->flags |= CLIENT_READONLY; if (args_has(self->args, 'd')) server_write_session(s, MSG_DETACH, NULL, 0); - ctx->cmdclient->session = s; - notify_attached_session_changed(ctx->cmdclient); - session_update_activity(s); - server_write_ready(ctx->cmdclient); - update = options_get_string(&s->options, "update-environment"); - environ_update(update, &ctx->cmdclient->environ, &s->environ); + environ_update(update, &cmdq->client->environ, &s->environ); - server_redraw_client(ctx->cmdclient); + cmdq->client->session = s; + notify_attached_session_changed(cmdq->client); + session_update_activity(s); + server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; + + server_write_ready(cmdq->client); + cmdq->client_exit = 0; } recalculate_sizes(); server_update_socket(); - return (CMD_RETURN_ATTACH); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 086ac4ec..d9b65bec 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -28,9 +28,9 @@ */ enum cmd_retval cmd_bind_key_check(struct args *); -enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); -enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int); +enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_q *, int); const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", @@ -56,7 +56,7 @@ cmd_bind_key_check(struct args *args) } enum cmd_retval -cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; char *cause; @@ -65,16 +65,17 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { - ctx->error(ctx, "unknown key: %s", args->argv[0]); + cmdq_error(cmdq, "unknown key: %s", args->argv[0]); return (CMD_RETURN_ERROR); } if (args_has(args, 't')) - return (cmd_bind_key_table(self, ctx, key)); + return (cmd_bind_key_table(self, cmdq, key)); - cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, &cause); + cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0, + &cause); if (cmdlist == NULL) { - ctx->error(ctx, "%s", cause); + cmdq_error(cmdq, "%s", cause); free(cause); return (CMD_RETURN_ERROR); } @@ -86,7 +87,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) } enum cmd_retval -cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) +cmd_bind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) { struct args *args = self->args; const char *tablename; @@ -97,25 +98,25 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { - ctx->error(ctx, "unknown key table: %s", tablename); + cmdq_error(cmdq, "unknown key table: %s", tablename); return (CMD_RETURN_ERROR); } cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]); if (cmd == MODEKEY_NONE) { - ctx->error(ctx, "unknown command: %s", args->argv[1]); + cmdq_error(cmdq, "unknown command: %s", args->argv[1]); return (CMD_RETURN_ERROR); } if (cmd != MODEKEYCOPY_COPYPIPE) { if (args->argc != 2) { - ctx->error(ctx, "no argument allowed"); + cmdq_error(cmdq, "no argument allowed"); return (CMD_RETURN_ERROR); } arg = NULL; } else { if (args->argc != 3) { - ctx->error(ctx, "no argument given"); + cmdq_error(cmdq, "no argument given"); return (CMD_RETURN_ERROR); } arg = args->argv[2]; diff --git a/cmd-break-pane.c b/cmd-break-pane.c index a5a78077..27ae1624 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -26,7 +26,7 @@ * Break pane off into a window. */ -enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_break_pane_entry = { }; enum cmd_retval -cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; @@ -54,11 +54,11 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) const char *template; char *cp; - if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) + if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) return (CMD_RETURN_ERROR); if (window_count_panes(wl->window) == 1) { - ctx->error(ctx, "can't break with only one pane"); + cmdq_error(cmdq, "can't break with only one pane"); return (CMD_RETURN_ERROR); } @@ -97,14 +97,14 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) template = BREAK_PANE_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(ctx, NULL, 1)) != NULL) + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); format_window_pane(ft, wp); cp = format_expand(ft, template); - ctx->print(ctx, "%s", cp); + cmdq_print(cmdq, "%s", cp); free(cp); format_free(ft); diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 6a10b7c9..aa032ce8 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -27,7 +27,7 @@ * Write the entire contents of a pane to a buffer or stdout. */ -enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", @@ -41,7 +41,7 @@ const struct cmd_entry cmd_capture_pane_entry = { }; enum cmd_retval -cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -55,7 +55,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct grid_cell *gc; const struct grid_line *gl; - if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) + if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); s = &wp->base; gd = s->grid; @@ -113,11 +113,10 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } if (args_has(args, 'p')) { - c = ctx->curclient; - if (c == NULL || !(c->flags & CLIENT_CONTROL)) - c = ctx->cmdclient; - if (c == NULL) { - ctx->error(ctx, "can't write to stdout"); + c = cmdq->client; + if (c == NULL || + (c->session != NULL && !(c->flags & CLIENT_CONTROL))) { + cmdq_error(cmdq, "can't write to stdout"); return (CMD_RETURN_ERROR); } evbuffer_add(c->stdout_data, buf, len); @@ -131,14 +130,14 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "buffer %s", cause); + cmdq_error(cmdq, "buffer %s", cause); free(buf); free(cause); return (CMD_RETURN_ERROR); } if (paste_replace(&global_buffers, buffer, buf, len) != 0) { - ctx->error(ctx, "no buffer %d", buffer); + cmdq_error(cmdq, "no buffer %d", buffer); free(buf); return (CMD_RETURN_ERROR); } diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index a58e38b7..8713815d 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -27,7 +27,7 @@ * Enter choice mode to choose a buffer. */ -enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_choose_buffer_entry = { "choose-buffer", NULL, @@ -40,7 +40,7 @@ const struct cmd_entry cmd_choose_buffer_entry = { }; enum cmd_retval -cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -51,15 +51,15 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) const char *template; u_int idx; - if ((c = cmd_current_client(ctx)) == NULL) { - ctx->error(ctx, "no client available"); + if ((c = cmd_current_client(cmdq)) == NULL) { + cmdq_error(cmdq, "no client available"); return (CMD_RETURN_ERROR); } if ((template = args_get(args, 'F')) == NULL) template = CHOOSE_BUFFER_TEMPLATE; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); if (paste_get_top(&global_buffers) == NULL) diff --git a/cmd-choose-client.c b/cmd-choose-client.c index 962aefca..b32703c4 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -27,7 +27,7 @@ * Enter choice mode to choose a client. */ -enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *); void cmd_choose_client_callback(struct window_choose_data *); @@ -46,7 +46,7 @@ struct cmd_choose_client_data { }; enum cmd_retval -cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -57,12 +57,12 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) char *action; u_int i, idx, cur; - if ((c = cmd_current_client(ctx)) == NULL) { - ctx->error(ctx, "no client available"); + if ((c = cmd_current_client(cmdq)) == NULL) { + cmdq_error(cmdq, "no client available"); return (CMD_RETURN_ERROR); } - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) @@ -81,7 +81,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx) c1 = ARRAY_ITEM(&clients, i); if (c1 == NULL || c1->session == NULL) continue; - if (c1 == ctx->curclient) + if (c1 == cmdq->client) cur = idx; idx++; diff --git a/cmd-choose-list.c b/cmd-choose-list.c index 9634fef4..15f87294 100644 --- a/cmd-choose-list.c +++ b/cmd-choose-list.c @@ -31,7 +31,7 @@ * Enter choose mode to choose a custom list. */ -enum cmd_retval cmd_choose_list_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_choose_list_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_choose_list_entry = { "choose-list", NULL, @@ -44,7 +44,7 @@ const struct cmd_entry cmd_choose_list_entry = { }; enum cmd_retval -cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_choose_list_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -53,15 +53,15 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx) char *template, *item, *copy, *list; u_int idx; - if ((c = cmd_current_client(ctx)) == NULL) { - ctx->error(ctx, "no client available"); + if ((c = cmd_current_client(cmdq)) == NULL) { + cmdq_error(cmdq, "no client available"); return (CMD_RETURN_ERROR); } if ((list1 = args_get(args, 'l')) == NULL) return (CMD_RETURN_ERROR); - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index af85a3bf..f22f17c2 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -32,7 +32,7 @@ * Enter choice mode to choose a session and/or window. */ -enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_choose_tree_entry = { "choose-tree", NULL, @@ -66,7 +66,7 @@ const struct cmd_entry cmd_choose_window_entry = { }; enum cmd_retval -cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl, *wm; @@ -84,15 +84,15 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) ses_template = win_template = NULL; ses_action = win_action = NULL; - if ((c = cmd_current_client(ctx)) == NULL) { - ctx->error(ctx, "no client available"); + if ((c = cmd_current_client(cmdq)) == NULL) { + cmdq_error(cmdq, "no client available"); return (CMD_RETURN_ERROR); } if ((s = c->session) == NULL) return (CMD_RETURN_ERROR); - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 8a88e46c..768ba86d 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -24,7 +24,7 @@ * Clear pane history. */ -enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_clear_history_entry = { "clear-history", "clearhist", @@ -37,13 +37,13 @@ const struct cmd_entry cmd_clear_history_entry = { }; enum cmd_retval -cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_clear_history_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct window_pane *wp; struct grid *gd; - if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) + if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); gd = wp->base.grid; diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index f1d9eceb..b1837004 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -24,7 +24,7 @@ * Enter clock mode. */ -enum cmd_retval cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_clock_mode_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_clock_mode_entry = { "clock-mode", NULL, @@ -37,12 +37,12 @@ const struct cmd_entry cmd_clock_mode_entry = { }; enum cmd_retval -cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_clock_mode_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct window_pane *wp; - if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) + if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); window_pane_set_mode(wp, &window_clock_mode); diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 3a43b24f..3b773316 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -31,7 +31,7 @@ void cmd_command_prompt_key_binding(struct cmd *, int); int cmd_command_prompt_check(struct args *); -enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *); int cmd_command_prompt_callback(void *, const char *); void cmd_command_prompt_free(void *); @@ -85,7 +85,7 @@ cmd_command_prompt_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; const char *inputs, *prompts; @@ -94,7 +94,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) char *prompt, *ptr, *input = NULL; size_t n; - if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) + if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); if (c->prompt_string != NULL) @@ -150,7 +150,6 @@ cmd_command_prompt_callback(void *data, const char *s) struct cmd_command_prompt_cdata *cdata = data; struct client *c = cdata->c; struct cmd_list *cmdlist; - struct cmd_ctx *ctx; char *cause, *new_template, *prompt, *ptr; char *input = NULL; @@ -175,7 +174,7 @@ cmd_command_prompt_callback(void *data, const char *s) return (1); } - if (cmd_string_parse(new_template, &cmdlist, &cause) != 0) { + if (cmd_string_parse(new_template, &cmdlist, NULL, 0, &cause) != 0) { if (cause != NULL) { *cause = toupper((u_char) *cause); status_message_set(c, "%s", cause); @@ -184,14 +183,8 @@ cmd_command_prompt_callback(void *data, const char *s) return (0); } - ctx = cmd_get_ctx(NULL, c); - ctx->error = key_bindings_error; - ctx->print = key_bindings_print; - ctx->info = key_bindings_info; - - cmd_list_exec(cmdlist, ctx); + cmdq_run(c->cmdq, cmdlist); cmd_list_free(cmdlist); - cmd_free_ctx(ctx); if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback) return (1); diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 765f58df..6282be2e 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -27,7 +27,7 @@ */ void cmd_confirm_before_key_binding(struct cmd *, int); -enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_q *); int cmd_confirm_before_callback(void *, const char *); void cmd_confirm_before_free(void *); @@ -43,8 +43,8 @@ const struct cmd_entry cmd_confirm_before_entry = { }; struct cmd_confirm_before_data { - struct client *c; char *cmd; + struct client *client; }; void @@ -66,7 +66,7 @@ cmd_confirm_before_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct cmd_confirm_before_data *cdata; @@ -74,12 +74,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) char *cmd, *copy, *new_prompt, *ptr; const char *prompt; - if (ctx->curclient == NULL) { - ctx->error(ctx, "must be run interactively"); - return (CMD_RETURN_ERROR); - } - - if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) + if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); if ((prompt = args_get(args, 'p')) != NULL) @@ -93,46 +88,44 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->cmd = xstrdup(args->argv[0]); - cdata->c = c; - status_prompt_set(cdata->c, new_prompt, NULL, + + cdata->client = c; + cdata->client->references++; + + status_prompt_set(c, new_prompt, NULL, cmd_confirm_before_callback, cmd_confirm_before_free, cdata, PROMPT_SINGLE); free(new_prompt); - return (CMD_RETURN_YIELD); + return (CMD_RETURN_NORMAL); } int cmd_confirm_before_callback(void *data, const char *s) { struct cmd_confirm_before_data *cdata = data; - struct client *c = cdata->c; + struct client *c = cdata->client; struct cmd_list *cmdlist; - struct cmd_ctx *ctx; char *cause; + if (c->flags & CLIENT_DEAD) + return (0); + if (s == NULL || *s == '\0') return (0); if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') return (0); - if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) { + if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) { if (cause != NULL) { - *cause = toupper((u_char) *cause); - status_message_set(c, "%s", cause); + cmdq_error(c->cmdq, "%s", cause); free(cause); } return (0); } - ctx = cmd_get_ctx(NULL, c); - ctx->error = key_bindings_error; - ctx->print = key_bindings_print; - ctx->info = key_bindings_info; - - cmd_list_exec(cmdlist, ctx); + cmdq_run(c->cmdq, cmdlist); cmd_list_free(cmdlist); - cmd_free_ctx(ctx); return (0); } @@ -141,6 +134,9 @@ void cmd_confirm_before_free(void *data) { struct cmd_confirm_before_data *cdata = data; + struct client *c = cdata->client; + + c->references--; free(cdata->cmd); free(cdata); diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 3f80cd8c..59b5a9e5 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -25,7 +25,7 @@ */ void cmd_copy_mode_key_binding(struct cmd *, int); -enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, @@ -46,12 +46,12 @@ cmd_copy_mode_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct window_pane *wp; - if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) + if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); if (window_pane_set_mode(wp, &window_copy_mode) != 0) diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index c3f8776a..6e425b57 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -26,7 +26,7 @@ * Delete a paste buffer. */ -enum cmd_retval cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_delete_buffer_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_delete_buffer_entry = { "delete-buffer", "deleteb", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_delete_buffer_entry = { }; enum cmd_retval -cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; char *cause; @@ -52,13 +52,13 @@ cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "buffer %s", cause); + cmdq_error(cmdq, "buffer %s", cause); free(cause); return (CMD_RETURN_ERROR); } if (paste_free_index(&global_buffers, buffer) != 0) { - ctx->error(ctx, "no buffer %d", buffer); + cmdq_error(cmdq, "no buffer %d", buffer); return (CMD_RETURN_ERROR); } diff --git a/cmd-detach-client.c b/cmd-detach-client.c index a1d3a386..17b437ab 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -24,7 +24,7 @@ * Detach a client. */ -enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", @@ -37,7 +37,7 @@ const struct cmd_entry cmd_detach_client_entry = { }; enum cmd_retval -cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c, *c2; @@ -51,7 +51,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) msgtype = MSG_DETACH; if (args_has(args, 's')) { - s = cmd_find_session(ctx, args_get(args, 's'), 0); + s = cmd_find_session(cmdq, args_get(args, 's'), 0); if (s == NULL) return (CMD_RETURN_ERROR); @@ -61,7 +61,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) server_write_client(c, msgtype, NULL, 0); } } else { - c = cmd_find_client(ctx, args_get(args, 't'), 0); + c = cmd_find_client(cmdq, args_get(args, 't'), 0); if (c == NULL) return (CMD_RETURN_ERROR); @@ -76,5 +76,5 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx) server_write_client(c, msgtype, NULL, 0); } - return (CMD_RETURN_NORMAL); + return (CMD_RETURN_STOP); } diff --git a/cmd-display-message.c b/cmd-display-message.c index 05c3a408..7f31d7e2 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -27,7 +27,7 @@ * Displays a message in the status line. */ -enum cmd_retval cmd_display_message_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_display_message_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_display_message_entry = { "display-message", "display", @@ -41,7 +41,7 @@ const struct cmd_entry cmd_display_message_entry = { }; enum cmd_retval -cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -56,17 +56,17 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) size_t len; if (args_has(args, 't')) { - wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); + wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); if (wl == NULL) return (CMD_RETURN_ERROR); } else { - wl = cmd_find_pane(ctx, NULL, &s, &wp); + wl = cmd_find_pane(cmdq, NULL, &s, &wp); if (wl == NULL) return (CMD_RETURN_ERROR); } if (args_has(args, 'F') && args->argc != 0) { - ctx->error(ctx, "only one of -F or argument must be given"); + cmdq_error(cmdq, "only one of -F or argument must be given"); return (CMD_RETURN_ERROR); } @@ -77,7 +77,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) template = DISPLAY_MESSAGE_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(ctx, args_get(args, 'c'), 1)) != NULL) + if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); @@ -89,11 +89,11 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx) msg = format_expand(ft, out); if (args_has(self->args, 'p')) - ctx->print(ctx, "%s", msg); + cmdq_print(cmdq, "%s", msg); else status_message_set(c, "%s", msg); - free(msg); format_free(ft); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-display-panes.c b/cmd-display-panes.c index b3e67fd2..a97a1809 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -24,7 +24,7 @@ * Display panes on a client. */ -enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_display_panes_entry = { "display-panes", "displayp", @@ -37,12 +37,12 @@ const struct cmd_entry cmd_display_panes_entry = { }; enum cmd_retval -cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; - if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) + if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); server_set_identify(c); diff --git a/cmd-find-window.c b/cmd-find-window.c index acd63c84..f757d10f 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -28,7 +28,7 @@ * Find window containing text. */ -enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_q *); void cmd_find_window_callback(struct window_choose_data *); @@ -127,7 +127,7 @@ cmd_find_window_match(struct cmd_find_window_data_list *find_list, } enum cmd_retval -cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -139,13 +139,13 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) const char *template; u_int i, match_flags; - if ((c = cmd_current_client(ctx)) == NULL) { - ctx->error(ctx, "no client available"); + if ((c = cmd_current_client(cmdq)) == NULL) { + cmdq_error(cmdq, "no client available"); return (CMD_RETURN_ERROR); } s = c->session; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); if ((template = args_get(args, 'F')) == NULL) @@ -162,7 +162,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx) free(searchstr); if (ARRAY_LENGTH(&find_list) == 0) { - ctx->error(ctx, "no windows matching: %s", str); + cmdq_error(cmdq, "no windows matching: %s", str); ARRAY_FREE(&find_list); return (CMD_RETURN_ERROR); } diff --git a/cmd-has-session.c b/cmd-has-session.c index 8e77942a..28e3aea3 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -24,7 +24,7 @@ * Cause client to report an error and exit with 1 if session doesn't exist. */ -enum cmd_retval cmd_has_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_has_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_has_session_entry = { "has-session", "has", @@ -37,11 +37,11 @@ const struct cmd_entry cmd_has_session_entry = { }; enum cmd_retval -cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_has_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - if (cmd_find_session(ctx, args_get(args, 't'), 0) == NULL) + if (cmd_find_session(cmdq, args_get(args, 't'), 0) == NULL) return (CMD_RETURN_ERROR); return (CMD_RETURN_NORMAL); diff --git a/cmd-if-shell.c b/cmd-if-shell.c index e0e2c230..e2a45972 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -29,15 +29,16 @@ * Executes a tmux command if a shell command returns true or false. */ -enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *); void cmd_if_shell_callback(struct job *); +void cmd_if_shell_done(struct cmd_q *); void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", - "t:", 2, 3, - CMD_TARGET_PANE_USAGE " shell-command command [command]", + "bt:", 2, 3, + "[-b] " CMD_TARGET_PANE_USAGE " shell-command command [command]", 0, NULL, NULL, @@ -47,11 +48,13 @@ const struct cmd_entry cmd_if_shell_entry = { struct cmd_if_shell_data { char *cmd_if; char *cmd_else; - struct cmd_ctx *ctx; + struct cmd_q *cmdq; + int bflag; + int started; }; enum cmd_retval -cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct cmd_if_shell_data *cdata; @@ -61,7 +64,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; struct format_tree *ft; - wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); + wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); if (wl == NULL) return (CMD_RETURN_ERROR); @@ -78,51 +81,83 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx) cdata->cmd_else = xstrdup(args->argv[2]); else cdata->cmd_else = NULL; + cdata->bflag = args_has(args, 'b'); - cdata->ctx = ctx; - cmd_ref_ctx(ctx); + cdata->started = 0; + cdata->cmdq = cmdq; + cmdq->references++; job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata); free(shellcmd); - return (CMD_RETURN_YIELD); /* don't let client exit */ + if (cdata->bflag) + return (CMD_RETURN_NORMAL); + return (CMD_RETURN_WAIT); } void cmd_if_shell_callback(struct job *job) { struct cmd_if_shell_data *cdata = job->data; - struct cmd_ctx *ctx = cdata->ctx; + struct cmd_q *cmdq = cdata->cmdq, *cmdq1; struct cmd_list *cmdlist; char *cause, *cmd; - if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) { + if (cmdq->dead) + return; + + if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) cmd = cdata->cmd_else; - if (cmd == NULL) - return; - } else + else cmd = cdata->cmd_if; - if (cmd_string_parse(cmd, &cmdlist, &cause) != 0) { + if (cmd == NULL) + return; + + if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) { if (cause != NULL) { - ctx->error(ctx, "%s", cause); + cmdq_error(cmdq, "%s", cause); free(cause); } return; } - cmd_list_exec(cmdlist, ctx); + cdata->started = 1; + + cmdq1 = cmdq_new(cmdq->client); + cmdq1->emptyfn = cmd_if_shell_done; + cmdq1->data = cdata; + + cmdq_run(cmdq1, cmdlist); cmd_list_free(cmdlist); } +void +cmd_if_shell_done(struct cmd_q *cmdq1) +{ + struct cmd_if_shell_data *cdata = cmdq1->data; + struct cmd_q *cmdq = cdata->cmdq; + + if (!cmdq_free(cmdq) && !cdata->bflag) + cmdq_continue(cmdq); + + cmdq_free(cmdq1); + + free(cdata->cmd_else); + free(cdata->cmd_if); + free(cdata); +} + void cmd_if_shell_free(void *data) { struct cmd_if_shell_data *cdata = data; - struct cmd_ctx *ctx = cdata->ctx; + struct cmd_q *cmdq = cdata->cmdq; - if (ctx->cmdclient != NULL) - ctx->cmdclient->flags |= CLIENT_EXIT; - cmd_free_ctx(ctx); + if (cdata->started) + return; + + if (!cmdq_free(cmdq) && !cdata->bflag) + cmdq_continue(cmdq); free(cdata->cmd_else); free(cdata->cmd_if); diff --git a/cmd-join-pane.c b/cmd-join-pane.c index c792948c..2e7a59cd 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -30,9 +30,9 @@ */ void cmd_join_pane_key_binding(struct cmd *, int); -enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_q *); -enum cmd_retval join_pane(struct cmd *, struct cmd_ctx *, int); +enum cmd_retval join_pane(struct cmd *, struct cmd_q *, int); const struct cmd_entry cmd_join_pane_entry = { "join-pane", "joinp", @@ -69,13 +69,13 @@ cmd_join_pane_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq) { - return (join_pane(self, ctx, self->entry == &cmd_join_pane_entry)); + return (join_pane(self, cmdq, self->entry == &cmd_join_pane_entry)); } enum cmd_retval -join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) +join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window) { struct args *args = self->args; struct session *dst_s; @@ -87,23 +87,23 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) enum layout_type type; struct layout_cell *lc; - dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp); + dst_wl = cmd_find_pane(cmdq, args_get(args, 't'), &dst_s, &dst_wp); if (dst_wl == NULL) return (CMD_RETURN_ERROR); dst_w = dst_wl->window; dst_idx = dst_wl->idx; - src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp); + src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp); if (src_wl == NULL) return (CMD_RETURN_ERROR); src_w = src_wl->window; if (not_same_window && src_w == dst_w) { - ctx->error(ctx, "can't join a pane to its own window"); + cmdq_error(cmdq, "can't join a pane to its own window"); return (CMD_RETURN_ERROR); } if (!not_same_window && src_wp == dst_wp) { - ctx->error(ctx, "source and target panes must be different"); + cmdq_error(cmdq, "source and target panes must be different"); return (CMD_RETURN_ERROR); } @@ -115,14 +115,14 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) if (args_has(args, 'l')) { size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "size %s", cause); + cmdq_error(cmdq, "size %s", cause); free(cause); return (CMD_RETURN_ERROR); } } else if (args_has(args, 'p')) { percentage = args_strtonum(args, 'p', 0, 100, &cause); if (cause != NULL) { - ctx->error(ctx, "percentage %s", cause); + cmdq_error(cmdq, "percentage %s", cause); free(cause); return (CMD_RETURN_ERROR); } @@ -133,7 +133,7 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window) } lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b')); if (lc == NULL) { - ctx->error(ctx, "create pane failed: pane too small"); + cmdq_error(cmdq, "create pane failed: pane too small"); return (CMD_RETURN_ERROR); } diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index 51989768..1aa776d9 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -26,7 +26,7 @@ * Kill pane. */ -enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_kill_pane_entry = { "kill-pane", "killp", @@ -39,13 +39,13 @@ const struct cmd_entry cmd_kill_pane_entry = { }; enum cmd_retval -cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_kill_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; struct window_pane *loopwp, *tmpwp, *wp; - if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) + if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); if (window_count_panes(wl->window) == 1) { diff --git a/cmd-kill-server.c b/cmd-kill-server.c index fcf1e25c..808dca59 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -27,7 +27,7 @@ * Kill the server and do nothing else. */ -enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_kill_server_entry = { "kill-server", NULL, @@ -40,7 +40,7 @@ const struct cmd_entry cmd_kill_server_entry = { }; enum cmd_retval -cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) +cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_q *cmdq) { kill(getpid(), SIGTERM); diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 9ee6a928..095fb9bb 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -27,7 +27,7 @@ * Note this deliberately has no alias to make it hard to hit by accident. */ -enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_kill_session_entry = { "kill-session", NULL, @@ -40,12 +40,12 @@ const struct cmd_entry cmd_kill_session_entry = { }; enum cmd_retval -cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s, *s2, *s3; - if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); if (args_has(args, 'a')) { diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 01587fc8..dcb1fd28 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -24,7 +24,7 @@ * Destroy window. */ -enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_kill_window_entry = { "kill-window", "killw", @@ -37,13 +37,13 @@ const struct cmd_entry cmd_kill_window_entry = { }; enum cmd_retval -cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl, *wl2, *wl3; struct session *s; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL) return (CMD_RETURN_ERROR); if (args_has(args, 'a')) { diff --git a/cmd-link-window.c b/cmd-link-window.c index 5c050904..c7dfa5aa 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -26,7 +26,7 @@ * Link a window into another session. */ -enum cmd_retval cmd_link_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_link_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_link_window_entry = { "link-window", "linkw", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_link_window_entry = { }; enum cmd_retval -cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_link_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *src, *dst; @@ -47,15 +47,15 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx) char *cause; int idx, kflag, dflag; - if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 's'), &src)) == NULL) return (CMD_RETURN_ERROR); - if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2) + if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &dst)) == -2) return (CMD_RETURN_ERROR); kflag = args_has(self->args, 'k'); dflag = args_has(self->args, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { - ctx->error(ctx, "can't link window: %s", cause); + cmdq_error(cmdq, "can't link window: %s", cause); free(cause); return (CMD_RETURN_ERROR); } diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index b1d59f2f..54284d55 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -27,7 +27,7 @@ * List paste buffers. */ -enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_list_buffers_entry = { "list-buffers", "lsb", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_list_buffers_entry = { }; enum cmd_retval -cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) +cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct paste_buffer *pb; @@ -59,7 +59,7 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx) format_paste_buffer(ft, pb); line = format_expand(ft, template); - ctx->print(ctx, "%s", line); + cmdq_print(cmdq, "%s", line); free(line); format_free(ft); diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 70f6c809..e0f8558e 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -28,7 +28,7 @@ * List all clients. */ -enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_list_clients_entry = { "list-clients", "lsc", @@ -41,7 +41,7 @@ const struct cmd_entry cmd_list_clients_entry = { }; enum cmd_retval -cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -52,7 +52,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) char *line; if (args_has(args, 't')) { - s = cmd_find_session(ctx, args_get(args, 't'), 0); + s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); } else @@ -75,7 +75,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx) format_client(ft, c); line = format_expand(ft, template); - ctx->print(ctx, "%s", line); + cmdq_print(cmdq, "%s", line); free(line); format_free(ft); diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 05a31ec5..7073d5f8 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -24,7 +24,7 @@ * List all commands with usages. */ -enum cmd_retval cmd_list_commands_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_commands_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_list_commands_entry = { "list-commands", "lscm", @@ -37,16 +37,16 @@ const struct cmd_entry cmd_list_commands_entry = { }; enum cmd_retval -cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx) +cmd_list_commands_exec(unused struct cmd *self, struct cmd_q *cmdq) { const struct cmd_entry **entryp; for (entryp = cmd_table; *entryp != NULL; entryp++) { if ((*entryp)->alias != NULL) { - ctx->print(ctx, "%s (%s) %s", (*entryp)->name, + cmdq_print(cmdq, "%s (%s) %s", (*entryp)->name, (*entryp)->alias, (*entryp)->usage); } else { - ctx->print(ctx, "%s %s", (*entryp)->name, + cmdq_print(cmdq, "%s %s", (*entryp)->name, (*entryp)->usage); } } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index dab6d545..1f568909 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -26,8 +26,8 @@ * List key bindings. */ -enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_ctx *); -enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *); +enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_list_keys_entry = { "list-keys", "lsk", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_list_keys_entry = { }; enum cmd_retval -cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct key_binding *bd; @@ -50,7 +50,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) int width, keywidth; if (args_has(args, 't')) - return (cmd_list_keys_table(self, ctx)); + return (cmd_list_keys_table(self, cmdq)); width = 0; @@ -91,14 +91,14 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx) continue; cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); - ctx->print(ctx, "bind-key %s", tmp); + cmdq_print(cmdq, "bind-key %s", tmp); } return (CMD_RETURN_NORMAL); } enum cmd_retval -cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; const char *tablename; @@ -109,7 +109,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { - ctx->error(ctx, "unknown key table: %s", tablename); + cmdq_error(cmdq, "unknown key table: %s", tablename); return (CMD_RETURN_ERROR); } @@ -138,7 +138,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx) mode = "c"; cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd); if (cmdstr != NULL) { - ctx->print(ctx, "bind-key -%st %s%s %*s %s%s%s%s", + cmdq_print(cmdq, "bind-key -%st %s%s %*s %s%s%s%s", mode, any_mode && *mode == '\0' ? " " : "", mtab->name, (int) width, key, cmdstr, mbind->arg != NULL ? " \"" : "", diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 717562a4..910c19bc 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -27,13 +27,13 @@ * List panes on given window. */ -enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_q *); -void cmd_list_panes_server(struct cmd *, struct cmd_ctx *); +void cmd_list_panes_server(struct cmd *, struct cmd_q *); void cmd_list_panes_session( - struct cmd *, struct session *, struct cmd_ctx *, int); + struct cmd *, struct session *, struct cmd_q *, int); void cmd_list_panes_window(struct cmd *, - struct session *, struct winlink *, struct cmd_ctx *, int); + struct session *, struct winlink *, struct cmd_q *, int); const struct cmd_entry cmd_list_panes_entry = { "list-panes", "lsp", @@ -46,51 +46,51 @@ const struct cmd_entry cmd_list_panes_entry = { }; enum cmd_retval -cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; struct winlink *wl; if (args_has(args, 'a')) - cmd_list_panes_server(self, ctx); + cmd_list_panes_server(self, cmdq); else if (args_has(args, 's')) { - s = cmd_find_session(ctx, args_get(args, 't'), 0); + s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); - cmd_list_panes_session(self, s, ctx, 1); + cmd_list_panes_session(self, s, cmdq, 1); } else { - wl = cmd_find_window(ctx, args_get(args, 't'), &s); + wl = cmd_find_window(cmdq, args_get(args, 't'), &s); if (wl == NULL) return (CMD_RETURN_ERROR); - cmd_list_panes_window(self, s, wl, ctx, 0); + cmd_list_panes_window(self, s, wl, cmdq, 0); } return (CMD_RETURN_NORMAL); } void -cmd_list_panes_server(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_panes_server(struct cmd *self, struct cmd_q *cmdq) { struct session *s; RB_FOREACH(s, sessions, &sessions) - cmd_list_panes_session(self, s, ctx, 2); + cmd_list_panes_session(self, s, cmdq, 2); } void cmd_list_panes_session( - struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type) + struct cmd *self, struct session *s, struct cmd_q *cmdq, int type) { struct winlink *wl; RB_FOREACH(wl, winlinks, &s->windows) - cmd_list_panes_window(self, s, wl, ctx, type); + cmd_list_panes_window(self, s, wl, cmdq, type); } void cmd_list_panes_window(struct cmd *self, - struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type) + struct session *s, struct winlink *wl, struct cmd_q *cmdq, int type) { struct args *args = self->args; struct window_pane *wp; @@ -135,7 +135,7 @@ cmd_list_panes_window(struct cmd *self, format_window_pane(ft, wp); line = format_expand(ft, template); - ctx->print(ctx, "%s", line); + cmdq_print(cmdq, "%s", line); free(line); format_free(ft); diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 81cc51cc..14ac4808 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -28,7 +28,7 @@ * List all sessions. */ -enum cmd_retval cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_sessions_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_list_sessions_entry = { "list-sessions", "ls", @@ -41,7 +41,7 @@ const struct cmd_entry cmd_list_sessions_entry = { }; enum cmd_retval -cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_sessions_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -60,7 +60,7 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) format_session(ft, s); line = format_expand(ft, template); - ctx->print(ctx, "%s", line); + cmdq_print(cmdq, "%s", line); free(line); format_free(ft); diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 0485e4a3..c709e471 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -27,11 +27,11 @@ * List windows on given session. */ -enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_q *); -void cmd_list_windows_server(struct cmd *, struct cmd_ctx *); +void cmd_list_windows_server(struct cmd *, struct cmd_q *); void cmd_list_windows_session( - struct cmd *, struct session *, struct cmd_ctx *, int); + struct cmd *, struct session *, struct cmd_q *, int); const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", @@ -44,35 +44,35 @@ const struct cmd_entry cmd_list_windows_entry = { }; enum cmd_retval -cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; if (args_has(args, 'a')) - cmd_list_windows_server(self, ctx); + cmd_list_windows_server(self, cmdq); else { - s = cmd_find_session(ctx, args_get(args, 't'), 0); + s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); - cmd_list_windows_session(self, s, ctx, 0); + cmd_list_windows_session(self, s, cmdq, 0); } return (CMD_RETURN_NORMAL); } void -cmd_list_windows_server(struct cmd *self, struct cmd_ctx *ctx) +cmd_list_windows_server(struct cmd *self, struct cmd_q *cmdq) { struct session *s; RB_FOREACH(s, sessions, &sessions) - cmd_list_windows_session(self, s, ctx, 1); + cmd_list_windows_session(self, s, cmdq, 1); } void cmd_list_windows_session( - struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type) + struct cmd *self, struct session *s, struct cmd_q *cmdq, int type) { struct args *args = self->args; struct winlink *wl; @@ -102,7 +102,7 @@ cmd_list_windows_session( format_window_pane(ft, wl->window->active); line = format_expand(ft, template); - ctx->print(ctx, "%s", line); + cmdq_print(cmdq, "%s", line); free(line); format_free(ft); diff --git a/cmd-list.c b/cmd-list.c index d1e72e93..82ae7480 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -24,7 +24,8 @@ #include "tmux.h" struct cmd_list * -cmd_list_parse(int argc, char **argv, char **cause) +cmd_list_parse(int argc, char **argv, const char* file, u_int line, + char **cause) { struct cmd_list *cmdlist; struct cmd *cmd; @@ -34,7 +35,7 @@ cmd_list_parse(int argc, char **argv, char **cause) copy_argv = cmd_copy_argv(argc, argv); - cmdlist = xmalloc(sizeof *cmdlist); + cmdlist = xcalloc(1, sizeof *cmdlist); cmdlist->references = 1; TAILQ_INIT(&cmdlist->list); @@ -55,7 +56,7 @@ cmd_list_parse(int argc, char **argv, char **cause) if (arglen != 1) new_argc++; - cmd = cmd_parse(new_argc, new_argv, cause); + cmd = cmd_parse(new_argc, new_argv, file, line, cause); if (cmd == NULL) goto bad; TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); @@ -64,7 +65,8 @@ cmd_list_parse(int argc, char **argv, char **cause) } if (lastsplit != argc) { - cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause); + cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, + file, line, cause); if (cmd == NULL) goto bad; TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); @@ -79,76 +81,21 @@ bad: return (NULL); } -enum cmd_retval -cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx) -{ - struct client *c = ctx->curclient; - struct cmd *cmd; - enum cmd_retval retval; - int guards, n; - - guards = 0; - if (c != NULL && c->session != NULL) - guards = c->flags & CLIENT_CONTROL; - - notify_disable(); - - retval = 0; - TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { - if (guards) - ctx->print(ctx, "%%begin"); - n = cmd->entry->exec(cmd, ctx); - if (guards) - ctx->print(ctx, "%%end"); - - switch (n) - { - case CMD_RETURN_ERROR: - return (CMD_RETURN_ERROR); - case CMD_RETURN_ATTACH: - /* Client is being attached (send MSG_READY). */ - retval = CMD_RETURN_ATTACH; - - /* - * Mangle the context to treat any following commands - * as if they were called from inside. - */ - if (ctx->curclient == NULL) { - ctx->curclient = ctx->cmdclient; - ctx->cmdclient = NULL; - - ctx->error = key_bindings_error; - ctx->print = key_bindings_print; - ctx->info = key_bindings_info; - } - break; - case CMD_RETURN_YIELD: - if (retval == CMD_RETURN_NORMAL) - retval = CMD_RETURN_YIELD; - break; - case CMD_RETURN_NORMAL: - break; - } - } - - notify_enable(); - return (retval); -} - void cmd_list_free(struct cmd_list *cmdlist) { - struct cmd *cmd; + struct cmd *cmd, *cmd1; if (--cmdlist->references != 0) return; - while (!TAILQ_EMPTY(&cmdlist->list)) { - cmd = TAILQ_FIRST(&cmdlist->list); + TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) { TAILQ_REMOVE(&cmdlist->list, cmd, qentry); args_free(cmd->args); + free(cmd->file); free(cmd); } + free(cmdlist); } diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index bfb06842..698210d8 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -30,7 +30,7 @@ * Loads a paste buffer from a file. */ -enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_q *); void cmd_load_buffer_callback(struct client *, int, void *); const struct cmd_entry cmd_load_buffer_entry = { @@ -44,10 +44,10 @@ const struct cmd_entry cmd_load_buffer_entry = { }; enum cmd_retval -cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - struct client *c = ctx->cmdclient; + struct client *c = cmdq->client; struct session *s; FILE *f; const char *path, *newpath, *wd; @@ -61,7 +61,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) else { buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "buffer %s", cause); + cmdq_error(cmdq, "buffer %s", cause); free(cause); return (CMD_RETURN_ERROR); } @@ -75,16 +75,16 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) error = server_set_stdin_callback (c, cmd_load_buffer_callback, buffer_ptr, &cause); if (error != 0) { - ctx->error(ctx, "%s: %s", path, cause); + cmdq_error(cmdq, "%s: %s", path, cause); free(cause); return (CMD_RETURN_ERROR); } - return (CMD_RETURN_YIELD); + return (CMD_RETURN_WAIT); } if (c != NULL) wd = c->cwd; - else if ((s = cmd_current_session(ctx, 0)) != NULL) { + else if ((s = cmd_current_session(cmdq, 0)) != NULL) { wd = options_get_string(&s->options, "default-path"); if (*wd == '\0') wd = s->cwd; @@ -96,7 +96,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) path = newpath; } if ((f = fopen(path, "rb")) == NULL) { - ctx->error(ctx, "%s: %s", path, strerror(errno)); + cmdq_error(cmdq, "%s: %s", path, strerror(errno)); return (CMD_RETURN_ERROR); } @@ -105,14 +105,14 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) while ((ch = getc(f)) != EOF) { /* Do not let the server die due to memory exhaustion. */ if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { - ctx->error(ctx, "realloc error: %s", strerror(errno)); + cmdq_error(cmdq, "realloc error: %s", strerror(errno)); goto error; } pdata = new_pdata; pdata[psize++] = ch; } if (ferror(f)) { - ctx->error(ctx, "%s: read error", path); + cmdq_error(cmdq, "%s: read error", path); goto error; } if (pdata != NULL) @@ -126,7 +126,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_NORMAL); } if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { - ctx->error(ctx, "no buffer %d", buffer); + cmdq_error(cmdq, "no buffer %d", buffer); free(pdata); return (CMD_RETURN_ERROR); } @@ -153,12 +153,13 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data) c->stdin_callback = NULL; c->references--; - c->flags |= CLIENT_EXIT; + if (c->flags & CLIENT_DEAD) + return; psize = EVBUFFER_LENGTH(c->stdin_data); if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) { free(data); - return; + goto out; } memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); pdata[psize] = '\0'; @@ -174,4 +175,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data) } free(data); + +out: + cmdq_continue(c->cmdq); } diff --git a/cmd-lock-server.c b/cmd-lock-server.c index c95379ac..8491c8b1 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -28,7 +28,7 @@ * Lock commands. */ -enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_lock_server_entry = { "lock-server", "lock", @@ -61,7 +61,7 @@ const struct cmd_entry cmd_lock_client_entry = { }; enum cmd_retval -cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx) +cmd_lock_server_exec(struct cmd *self, unused struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -70,11 +70,13 @@ cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx) if (self->entry == &cmd_lock_server_entry) server_lock(); else if (self->entry == &cmd_lock_session_entry) { - if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) + s = cmd_find_session(cmdq, args_get(args, 't'), 0); + if (s == NULL) return (CMD_RETURN_ERROR); server_lock_session(s); } else { - if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) + c = cmd_find_client(cmdq, args_get(args, 't'), 0); + if (c == NULL) return (CMD_RETURN_ERROR); server_lock_client(c); } diff --git a/cmd-move-window.c b/cmd-move-window.c index 03d42a8d..945e9daa 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -26,7 +26,7 @@ * Move a window. */ -enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_move_window_entry = { "move-window", "movew", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_move_window_entry = { }; enum cmd_retval -cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *src, *dst, *s; @@ -48,7 +48,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) int idx, kflag, dflag; if (args_has(args, 'r')) { - if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); session_renumber_windows(s); @@ -57,15 +57,15 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_NORMAL); } - if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 's'), &src)) == NULL) return (CMD_RETURN_ERROR); - if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2) + if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &dst)) == -2) return (CMD_RETURN_ERROR); kflag = args_has(self->args, 'k'); dflag = args_has(self->args, 'd'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { - ctx->error(ctx, "can't move window: %s", cause); + cmdq_error(cmdq, "can't move window: %s", cause); free(cause); return (CMD_RETURN_ERROR); } diff --git a/cmd-new-session.c b/cmd-new-session.c index ee161808..13ab667e 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -31,7 +31,7 @@ */ enum cmd_retval cmd_new_session_check(struct args *); -enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", @@ -53,62 +53,52 @@ cmd_new_session_check(struct args *args) } enum cmd_retval -cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) { - struct args *args = self->args; - struct session *s, *old_s, *groupwith; - struct window *w; - struct environ env; - struct termios tio, *tiop; - struct passwd *pw; - const char *newname, *target, *update, *cwd, *errstr; - char *cmd, *cause; - int detached, idx; - u_int sx, sy; + struct args *args = self->args; + struct client *c = cmdq->client; + struct session *s, *groupwith; + struct window *w; + struct environ env; + struct termios tio, *tiop; + struct passwd *pw; + const char *newname, *target, *update, *cwd, *errstr; + char *cmd, *cause; + int detached, idx; + u_int sx, sy; + int already_attached; + newname = args_get(args, 's'); if (newname != NULL) { if (!session_check_name(newname)) { - ctx->error(ctx, "bad session name: %s", newname); + cmdq_error(cmdq, "bad session name: %s", newname); return (CMD_RETURN_ERROR); } if (session_find(newname) != NULL) { - ctx->error(ctx, "duplicate session: %s", newname); + cmdq_error(cmdq, "duplicate session: %s", newname); return (CMD_RETURN_ERROR); } } target = args_get(args, 't'); if (target != NULL) { - groupwith = cmd_find_session(ctx, target, 0); + groupwith = cmd_find_session(cmdq, target, 0); if (groupwith == NULL) return (CMD_RETURN_ERROR); } else groupwith = NULL; - /* - * There are three cases: - * - * 1. If cmdclient is non-NULL, new-session has been called from the - * command-line - cmdclient is to become a new attached, interactive - * client. Unless -d is given, the terminal must be opened and then - * the client sent MSG_READY. - * - * 2. If cmdclient is NULL, new-session has been called from an - * existing client (such as a key binding). - * - * 3. Both are NULL, the command was in the configuration file. Treat - * this as if -d was given even if it was not. - * - * In all cases, a new additional session needs to be created and - * (unless -d) set as the current session for the client. - */ - /* Set -d if no client. */ detached = args_has(args, 'd'); - if (ctx->cmdclient == NULL && ctx->curclient == NULL) + if (c == NULL) detached = 1; + /* Is this client already attached? */ + already_attached = 0; + if (c != NULL && c->session != NULL) + already_attached = 1; + /* * Save the termios settings, part of which is used for new windows in * this session. @@ -118,25 +108,25 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) * before opening the terminal as that calls tcsetattr() to prepare for * tmux taking over. */ - if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) { - if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0) + if (!detached && !already_attached && c->tty.fd != -1) { + if (tcgetattr(c->tty.fd, &tio) != 0) fatal("tcgetattr failed"); tiop = &tio; } else tiop = NULL; /* Open the terminal if necessary. */ - if (!detached && ctx->cmdclient != NULL) { - if (server_client_open(ctx->cmdclient, NULL, &cause) != 0) { - ctx->error(ctx, "open terminal failed: %s", cause); + if (!detached && !already_attached) { + if (server_client_open(c, NULL, &cause) != 0) { + cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } } /* Get the new session working directory. */ - if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) - cwd = ctx->cmdclient->cwd; + if (c != NULL && c->cwd != NULL) + cwd = c->cwd; else { pw = getpwuid(getuid()); if (pw->pw_dir != NULL && *pw->pw_dir != '\0') @@ -146,32 +136,25 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) } /* Find new session size. */ - if (ctx->cmdclient != NULL) { - sx = ctx->cmdclient->tty.sx; - sy = ctx->cmdclient->tty.sy; - } else if (ctx->curclient != NULL) { - sx = ctx->curclient->tty.sx; - sy = ctx->curclient->tty.sy; + if (c != NULL) { + sx = c->tty.sx; + sy = c->tty.sy; } else { sx = 80; sy = 24; } - if (detached) { - if (args_has(args, 'x')) { - sx = strtonum( - args_get(args, 'x'), 1, USHRT_MAX, &errstr); - if (errstr != NULL) { - ctx->error(ctx, "width %s", errstr); - return (CMD_RETURN_ERROR); - } + if (detached && args_has(args, 'x')) { + sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr); + if (errstr != NULL) { + cmdq_error(cmdq, "width %s", errstr); + return (CMD_RETURN_ERROR); } - if (args_has(args, 'y')) { - sy = strtonum( - args_get(args, 'y'), 1, USHRT_MAX, &errstr); - if (errstr != NULL) { - ctx->error(ctx, "height %s", errstr); - return (CMD_RETURN_ERROR); - } + } + if (detached && args_has(args, 'y')) { + sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr); + if (errstr != NULL) { + cmdq_error(cmdq, "height %s", errstr); + return (CMD_RETURN_ERROR); } } if (sy > 0 && options_get_number(&global_s_options, "status")) @@ -192,14 +175,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) /* Construct the environment. */ environ_init(&env); update = options_get_string(&global_s_options, "update-environment"); - if (ctx->cmdclient != NULL) - environ_update(update, &ctx->cmdclient->environ, &env); + if (c != NULL) + environ_update(update, &c->environ, &env); /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause); if (s == NULL) { - ctx->error(ctx, "create session failed: %s", cause); + cmdq_error(cmdq, "create session failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } @@ -208,9 +191,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) /* Set the initial window name if one given. */ if (cmd != NULL && args_has(args, 'n')) { w = s->curw->window; - window_set_name(w, args_get(args, 'n')); - options_set_number(&w->options, "automatic-rename", 0); } @@ -229,25 +210,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) * taking this session and needs to get MSG_READY and stay around. */ if (!detached) { - if (ctx->cmdclient != NULL) { - server_write_ready(ctx->cmdclient); - - old_s = ctx->cmdclient->session; - if (old_s != NULL) - ctx->cmdclient->last_session = old_s; - ctx->cmdclient->session = s; - notify_attached_session_changed(ctx->cmdclient); - session_update_activity(s); - server_redraw_client(ctx->cmdclient); - } else { - old_s = ctx->curclient->session; - if (old_s != NULL) - ctx->curclient->last_session = old_s; - ctx->curclient->session = s; - notify_attached_session_changed(ctx->curclient); - session_update_activity(s); - server_redraw_client(ctx->curclient); - } + if (!already_attached) + server_write_ready(c); + else if (c->session != NULL) + c->last_session = c->session; + c->session = s; + notify_attached_session_changed(c); + session_update_activity(s); + server_redraw_client(c); } recalculate_sizes(); server_update_socket(); @@ -257,7 +227,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx) * session's current window into more mode and display them now. */ if (cfg_finished) - show_cfg_causes(s); + cfg_show_causes(s); - return (detached ? CMD_RETURN_NORMAL : CMD_RETURN_ATTACH); + if (!detached) + cmdq->client_exit = 0; + return (CMD_RETURN_NORMAL); } diff --git a/cmd-new-window.c b/cmd-new-window.c index 0ab05e26..161dc549 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -26,7 +26,7 @@ * Create a new window. */ -enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_new_window_entry = { }; enum cmd_retval -cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -54,7 +54,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) char *cp; if (args_has(args, 'a')) { - wl = cmd_find_window(ctx, args_get(args, 't'), &s); + wl = cmd_find_window(cmdq, args_get(args, 't'), &s); if (wl == NULL) return (CMD_RETURN_ERROR); idx = wl->idx + 1; @@ -65,7 +65,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) break; } if (last == INT_MAX) { - ctx->error(ctx, "no free window indexes"); + cmdq_error(cmdq, "no free window indexes"); return (CMD_RETURN_ERROR); } @@ -76,7 +76,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) server_unlink_window(s, wl); } } else { - if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2) + if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &s)) == -2) return (CMD_RETURN_ERROR); } detached = args_has(args, 'd'); @@ -105,13 +105,13 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = cmd_get_default_path(ctx, args_get(args, 'c')); + cwd = cmd_get_default_path(cmdq, args_get(args, 'c')); if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause); if (wl == NULL) { - ctx->error(ctx, "create window failed: %s", cause); + cmdq_error(cmdq, "create window failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } @@ -126,14 +126,14 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx) template = NEW_WINDOW_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(ctx, NULL, 1)) != NULL) - format_client(ft, c); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); format_window_pane(ft, wl->window->active); cp = format_expand(ft, template); - ctx->print(ctx, "%s", cp); + cmdq_print(cmdq, "%s", cp); free(cp); format_free(ft); diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index c957ba2f..1cfc17c8 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -28,7 +28,7 @@ * Paste paste buffer if present. */ -enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmd_q *); void cmd_paste_buffer_filter(struct window_pane *, const char *, size_t, const char *, int); @@ -44,7 +44,7 @@ const struct cmd_entry cmd_paste_buffer_entry = { }; enum cmd_retval -cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct window_pane *wp; @@ -55,7 +55,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) int buffer; int pflag; - if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) + if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL) return (CMD_RETURN_ERROR); if (!args_has(args, 'b')) @@ -63,7 +63,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) else { buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "buffer %s", cause); + cmdq_error(cmdq, "buffer %s", cause); free(cause); return (CMD_RETURN_ERROR); } @@ -74,7 +74,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) else { pb = paste_get_index(&global_buffers, buffer); if (pb == NULL) { - ctx->error(ctx, "no buffer %d", buffer); + cmdq_error(cmdq, "no buffer %d", buffer); return (CMD_RETURN_ERROR); } } diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index bb17c6be..5de675df 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -32,7 +32,7 @@ * Open pipe to redirect pane output. If already open, close first. */ -enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_q *); void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *); @@ -47,7 +47,7 @@ const struct cmd_entry cmd_pipe_pane_entry = { }; enum cmd_retval -cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -55,9 +55,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) char *command; int old_fd, pipe_fd[2], null_fd; - if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) + if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); - c = cmd_find_client(ctx, NULL, 1); + c = cmd_find_client(cmdq, NULL, 1); /* Destroy the old pipe. */ old_fd = wp->pipe_fd; @@ -82,14 +82,14 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { - ctx->error(ctx, "socketpair error: %s", strerror(errno)); + cmdq_error(cmdq, "socketpair error: %s", strerror(errno)); return (CMD_RETURN_ERROR); } /* Fork the child. */ switch (fork()) { case -1: - ctx->error(ctx, "fork error: %s", strerror(errno)); + cmdq_error(cmdq, "fork error: %s", strerror(errno)); return (CMD_RETURN_ERROR); case 0: /* Child process. */ diff --git a/cmd-queue.c b/cmd-queue.c new file mode 100644 index 00000000..07884df2 --- /dev/null +++ b/cmd-queue.c @@ -0,0 +1,258 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2013 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "tmux.h" + +/* Create new command queue. */ +struct cmd_q * +cmdq_new(struct client *c) +{ + struct cmd_q *cmdq; + + cmdq = xcalloc(1, sizeof *cmdq); + cmdq->references = 1; + cmdq->dead = 0; + + cmdq->client = c; + cmdq->client_exit = 0; + + TAILQ_INIT(&cmdq->queue); + cmdq->item = NULL; + cmdq->cmd = NULL; + + return (cmdq); +} + +/* Free command queue */ +int +cmdq_free(struct cmd_q *cmdq) +{ + if (--cmdq->references != 0) + return (cmdq->dead); + + cmdq_flush(cmdq); + free(cmdq); + return (1); +} + +/* Show message from command. */ +void printflike2 +cmdq_print(struct cmd_q *cmdq, const char *fmt, ...) +{ + struct client *c = cmdq->client; + struct window *w; + va_list ap; + + va_start(ap, fmt); + + if (c == NULL) + /* nothing */; + else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { + va_start(ap, fmt); + evbuffer_add_vprintf(c->stdout_data, fmt, ap); + va_end(ap); + + evbuffer_add(c->stdout_data, "\n", 1); + server_push_stdout(c); + } else { + w = c->session->curw->window; + if (w->active->mode != &window_copy_mode) { + window_pane_reset_mode(w->active); + window_pane_set_mode(w->active, &window_copy_mode); + window_copy_init_for_output(w->active); + } + window_copy_vadd(w->active, fmt, ap); + } + + va_end(ap); +} + +/* Show info from command. */ +void printflike2 +cmdq_info(struct cmd_q *cmdq, const char *fmt, ...) +{ + struct client *c = cmdq->client; + va_list ap; + char *msg; + + if (options_get_number(&global_options, "quiet")) + return; + + va_start(ap, fmt); + + if (c == NULL) + /* nothing */; + else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { + va_start(ap, fmt); + evbuffer_add_vprintf(c->stdout_data, fmt, ap); + va_end(ap); + + evbuffer_add(c->stdout_data, "\n", 1); + server_push_stdout(c); + } else { + xvasprintf(&msg, fmt, ap); + *msg = toupper((u_char) *msg); + status_message_set(c, "%s", msg); + free(msg); + } + + va_end(ap); + +} + +/* Show error from command. */ +void printflike2 +cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) +{ + struct client *c = cmdq->client; + struct cmd *cmd = cmdq->cmd; + va_list ap; + char *msg, *cause; + size_t msglen; + + va_start(ap, fmt); + msglen = xvasprintf(&msg, fmt, ap); + va_end(ap); + + if (c == NULL) { + xasprintf(&cause, "%s:%u: %s", cmd->file, cmd->line, msg); + ARRAY_ADD(&cfg_causes, cause); + } else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { + evbuffer_add(c->stderr_data, msg, msglen); + evbuffer_add(c->stderr_data, "\n", 1); + + server_push_stderr(c); + c->retcode = 1; + } else { + *msg = toupper((u_char) *msg); + status_message_set(c, "%s", msg); + } + + free(msg); +} + +/* Add command list to queue and begin processing if needed. */ +void +cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist) +{ + cmdq_append(cmdq, cmdlist); + + if (cmdq->item == NULL) { + cmdq->cmd = NULL; + cmdq_continue(cmdq); + } +} + +/* Add command list to queue. */ +void +cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist) +{ + struct cmd_q_item *item; + + item = xcalloc(1, sizeof *item); + item->cmdlist = cmdlist; + TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry); + cmdlist->references++; +} + +/* Continue processing command queue. Returns 1 if finishes empty. */ +int +cmdq_continue(struct cmd_q *cmdq) +{ + struct client *c = cmdq->client; + struct cmd_q_item *next; + enum cmd_retval retval; + int guards, empty; + + guards = 0; + if (c != NULL && c->session != NULL) + guards = c->flags & CLIENT_CONTROL; + + notify_disable(); + + empty = TAILQ_EMPTY(&cmdq->queue); + if (empty) + goto empty; + + if (cmdq->item == NULL) { + cmdq->item = TAILQ_FIRST(&cmdq->queue); + cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list); + } else + cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry); + + do { + next = TAILQ_NEXT(cmdq->item, qentry); + + while (cmdq->cmd != NULL) { + if (guards) + cmdq_print(cmdq, "%%begin"); + retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq); + if (guards) + cmdq_print(cmdq, "%%end"); + + if (retval == CMD_RETURN_ERROR) + break; + if (retval == CMD_RETURN_WAIT) + goto out; + if (retval == CMD_RETURN_STOP) { + cmdq_flush(cmdq); + goto empty; + } + + cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry); + } + + TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry); + cmd_list_free(cmdq->item->cmdlist); + free(cmdq->item); + + cmdq->item = next; + if (cmdq->item != NULL) + cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list); + } while (cmdq->item != NULL); + +empty: + if (cmdq->client_exit) + cmdq->client->flags |= CLIENT_EXIT; + if (cmdq->emptyfn != NULL) + cmdq->emptyfn(cmdq); /* may free cmdq */ + empty = 1; + +out: + notify_enable(); + return (empty); +} + +/* Flush command queue. */ +void +cmdq_flush(struct cmd_q *cmdq) +{ + struct cmd_q_item *item, *item1; + + TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) { + TAILQ_REMOVE(&cmdq->queue, item, qentry); + cmd_list_free(item->cmdlist); + free(item); + } + cmdq->item = NULL; +} diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 25df230f..eff692dd 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -24,7 +24,7 @@ * Refresh client. */ -enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", @@ -37,32 +37,32 @@ const struct cmd_entry cmd_refresh_client_entry = { }; enum cmd_retval -cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; const char *size; u_int w, h; - if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) + if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); if (args_has(args, 'C')) { if ((size = args_get(args, 'C')) == NULL) { - ctx->error(ctx, "missing size"); + cmdq_error(cmdq, "missing size"); return (CMD_RETURN_ERROR); } if (sscanf(size, "%u,%u", &w, &h) != 2) { - ctx->error(ctx, "bad size argument"); + cmdq_error(cmdq, "bad size argument"); return (CMD_RETURN_ERROR); } if (w < PANE_MINIMUM || w > 5000 || h < PANE_MINIMUM || h > 5000) { - ctx->error(ctx, "size too small or too big"); + cmdq_error(cmdq, "size too small or too big"); return (CMD_RETURN_ERROR); } if (!(c->flags & CLIENT_CONTROL)) { - ctx->error(ctx, "not a control client"); + cmdq_error(cmdq, "not a control client"); return (CMD_RETURN_ERROR); } if (tty_set_size(&c->tty, w, h)) diff --git a/cmd-rename-session.c b/cmd-rename-session.c index fb8dd4ed..c94b460b 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -26,7 +26,7 @@ * Change session name. */ -enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_rename_session_entry = { "rename-session", "rename", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_rename_session_entry = { }; enum cmd_retval -cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -47,15 +47,15 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx) newname = args->argv[0]; if (!session_check_name(newname)) { - ctx->error(ctx, "bad session name: %s", newname); + cmdq_error(cmdq, "bad session name: %s", newname); return (CMD_RETURN_ERROR); } if (session_find(newname) != NULL) { - ctx->error(ctx, "duplicate session: %s", newname); + cmdq_error(cmdq, "duplicate session: %s", newname); return (CMD_RETURN_ERROR); } - if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); RB_REMOVE(sessions, &sessions, s); diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 099ab3b7..34b03f98 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -26,7 +26,7 @@ * Rename a window. */ -enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_rename_window_entry = { "rename-window", "renamew", @@ -39,13 +39,13 @@ const struct cmd_entry cmd_rename_window_entry = { }; enum cmd_retval -cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_rename_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; struct winlink *wl; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL) return (CMD_RETURN_ERROR); window_set_name(wl->window, args->argv[0]); diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index dbcebbcf..f31e3258 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -27,7 +27,7 @@ */ void cmd_resize_pane_key_binding(struct cmd *, int); -enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", @@ -82,7 +82,7 @@ cmd_resize_pane_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; @@ -92,7 +92,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) u_int adjust; int x, y; - if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) + if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); if (args->argc == 0) @@ -100,7 +100,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) else { adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr); if (errstr != NULL) { - ctx->error(ctx, "adjustment %s", errstr); + cmdq_error(cmdq, "adjustment %s", errstr); return (CMD_RETURN_ERROR); } } @@ -109,7 +109,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "width %s", cause); + cmdq_error(cmdq, "width %s", cause); free(cause); return (CMD_RETURN_ERROR); } @@ -119,7 +119,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "height %s", cause); + cmdq_error(cmdq, "height %s", cause); free(cause); return (CMD_RETURN_ERROR); } diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 3860dc93..0aae0331 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -28,7 +28,7 @@ * Respawn a pane (restart the command). Kill existing if -k given. */ -enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_respawn_pane_entry = { "respawn-pane", "respawnp", @@ -41,7 +41,7 @@ const struct cmd_entry cmd_respawn_pane_entry = { }; enum cmd_retval -cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; @@ -53,14 +53,14 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) char *cause; u_int idx; - if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) + if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) return (CMD_RETURN_ERROR); w = wl->window; if (!args_has(self->args, 'k') && wp->fd != -1) { if (window_pane_index(wp, &idx) != 0) fatalx("index not found"); - ctx->error(ctx, "pane still active: %s:%u.%u", + cmdq_error(cmdq, "pane still active: %s:%u.%u", s->name, wl->idx, idx); return (CMD_RETURN_ERROR); } @@ -79,7 +79,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx) else cmd = NULL; if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { - ctx->error(ctx, "respawn pane failed: %s", cause); + cmdq_error(cmdq, "respawn pane failed: %s", cause); free(cause); environ_free(&env); return (CMD_RETURN_ERROR); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index a178a2ba..646882b0 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -27,7 +27,7 @@ * Respawn a window (restart the command). Kill existing if -k given. */ -enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_respawn_window_entry = { "respawn-window", "respawnw", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_respawn_window_entry = { }; enum cmd_retval -cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; @@ -51,7 +51,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) const char *cmd; char *cause; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL) return (CMD_RETURN_ERROR); w = wl->window; @@ -59,7 +59,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->fd == -1) continue; - ctx->error(ctx, + cmdq_error(cmdq, "window still active: %s:%d", s->name, wl->idx); return (CMD_RETURN_ERROR); } @@ -81,7 +81,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) else cmd = NULL; if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { - ctx->error(ctx, "respawn window failed: %s", cause); + cmdq_error(cmdq, "respawn window failed: %s", cause); free(cause); environ_free(&env); server_destroy_pane(wp); diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 7a6c60b3..7af592b3 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -25,7 +25,7 @@ */ void cmd_rotate_window_key_binding(struct cmd *, int); -enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_rotate_window_entry = { "rotate-window", "rotatew", @@ -46,7 +46,7 @@ cmd_rotate_window_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; @@ -55,7 +55,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct layout_cell *lc; u_int sx, sy, xoff, yoff; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); w = wl->window; diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 3942fa11..5452ceff 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -29,7 +29,7 @@ * Runs a command without a window. */ -enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_q *); void cmd_run_shell_callback(struct job *); void cmd_run_shell_free(void *); @@ -37,8 +37,8 @@ void cmd_run_shell_print(struct job *, const char *); const struct cmd_entry cmd_run_shell_entry = { "run-shell", "run", - "t:", 1, 1, - CMD_TARGET_PANE_USAGE " command", + "bt:", 1, 1, + "[-b] " CMD_TARGET_PANE_USAGE " shell-command", 0, NULL, NULL, @@ -47,7 +47,8 @@ const struct cmd_entry cmd_run_shell_entry = { struct cmd_run_shell_data { char *cmd; - struct cmd_ctx *ctx; + struct cmd_q *cmdq; + int bflag; u_int wp_id; }; @@ -55,12 +56,11 @@ void cmd_run_shell_print(struct job *job, const char *msg) { struct cmd_run_shell_data *cdata = job->data; - struct cmd_ctx *ctx = cdata->ctx; struct window_pane *wp; wp = window_pane_find_by_id(cdata->wp_id); if (wp == NULL) { - ctx->print(ctx, "%s", msg); + cmdq_print(cdata->cmdq, "%s", msg); return; } @@ -71,7 +71,7 @@ cmd_run_shell_print(struct job *job, const char *msg) } enum cmd_retval -cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct cmd_run_shell_data *cdata; @@ -81,7 +81,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; struct format_tree *ft; - wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp); + wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); if (wl == NULL) return (CMD_RETURN_ERROR); @@ -94,35 +94,37 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) cdata = xmalloc(sizeof *cdata); cdata->cmd = shellcmd; + cdata->bflag = args_has(args, 'b'); cdata->wp_id = wp->id; - cdata->ctx = ctx; - cmd_ref_ctx(ctx); + cdata->cmdq = cmdq; + cmdq->references++; job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata); - return (CMD_RETURN_YIELD); /* don't let client exit */ + if (cdata->bflag) + return (CMD_RETURN_NORMAL); + return (CMD_RETURN_WAIT); } void cmd_run_shell_callback(struct job *job) { struct cmd_run_shell_data *cdata = job->data; - struct cmd_ctx *ctx = cdata->ctx; + struct cmd_q *cmdq = cdata->cmdq; char *cmd, *msg, *line; size_t size; int retcode; u_int lines; - if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD) - return; - if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD) + if (cmdq->dead) return; + cmd = cdata->cmd; lines = 0; do { if ((line = evbuffer_readline(job->event->input)) != NULL) { - cmd_run_shell_print (job, line); + cmd_run_shell_print(job, line); free(line); lines++; } @@ -140,8 +142,6 @@ cmd_run_shell_callback(struct job *job) free(line); } - cmd = cdata->cmd; - msg = NULL; if (WIFEXITED(job->status)) { if ((retcode = WEXITSTATUS(job->status)) != 0) @@ -152,7 +152,7 @@ cmd_run_shell_callback(struct job *job) } if (msg != NULL) { if (lines == 0) - ctx->info(ctx, "%s", msg); + cmdq_info(cmdq, "%s", msg); else cmd_run_shell_print(job, msg); free(msg); @@ -163,11 +163,10 @@ void cmd_run_shell_free(void *data) { struct cmd_run_shell_data *cdata = data; - struct cmd_ctx *ctx = cdata->ctx; + struct cmd_q *cmdq = cdata->cmdq; - if (ctx->cmdclient != NULL) - ctx->cmdclient->flags |= CLIENT_EXIT; - cmd_free_ctx(ctx); + if (!cmdq_free(cmdq) && !cdata->bflag) + cmdq_continue(cmdq); free(cdata->cmd); free(cdata); diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 6031a562..29f71837 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "tmux.h" @@ -29,7 +30,7 @@ * Saves a paste buffer to a file. */ -enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_save_buffer_entry = { "save-buffer", "saveb", @@ -41,83 +42,132 @@ const struct cmd_entry cmd_save_buffer_entry = { cmd_save_buffer_exec }; +const struct cmd_entry cmd_show_buffer_entry = { + "show-buffer", "showb", + "b:", 0, 0, + CMD_BUFFER_USAGE, + 0, + NULL, + NULL, + cmd_save_buffer_exec +}; + enum cmd_retval -cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; struct session *s; struct paste_buffer *pb; const char *path, *newpath, *wd; - char *cause; + char *cause, *start, *end; + size_t size, used; int buffer; mode_t mask; FILE *f; + char *msg; + size_t msglen; if (!args_has(args, 'b')) { if ((pb = paste_get_top(&global_buffers)) == NULL) { - ctx->error(ctx, "no buffers"); + cmdq_error(cmdq, "no buffers"); return (CMD_RETURN_ERROR); } } else { buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "buffer %s", cause); + cmdq_error(cmdq, "buffer %s", cause); free(cause); return (CMD_RETURN_ERROR); } pb = paste_get_index(&global_buffers, buffer); if (pb == NULL) { - ctx->error(ctx, "no buffer %d", buffer); + cmdq_error(cmdq, "no buffer %d", buffer); return (CMD_RETURN_ERROR); } } - path = args->argv[0]; + if (self->entry == &cmd_show_buffer_entry) + path = "-"; + else + path = args->argv[0]; if (strcmp(path, "-") == 0) { - c = ctx->curclient; - if (c == NULL || !(c->flags & CLIENT_CONTROL)) - c = ctx->cmdclient; + c = cmdq->client; if (c == NULL) { - ctx->error(ctx, "can't write to stdout"); + cmdq_error(cmdq, "can't write to stdout"); return (CMD_RETURN_ERROR); } - evbuffer_add(c->stdout_data, pb->data, pb->size); - server_push_stdout(c); - } else { - c = ctx->cmdclient; - if (c != NULL) - wd = c->cwd; - else if ((s = cmd_current_session(ctx, 0)) != NULL) { - wd = options_get_string(&s->options, "default-path"); - if (*wd == '\0') - wd = s->cwd; - } else - wd = NULL; - if (wd != NULL && *wd != '\0') { - newpath = get_full_path(wd, path); - if (newpath != NULL) - path = newpath; - } - - mask = umask(S_IRWXG | S_IRWXO); - if (args_has(self->args, 'a')) - f = fopen(path, "ab"); - else - f = fopen(path, "wb"); - umask(mask); - if (f == NULL) { - ctx->error(ctx, "%s: %s", path, strerror(errno)); - return (CMD_RETURN_ERROR); - } - if (fwrite(pb->data, 1, pb->size, f) != pb->size) { - ctx->error(ctx, "%s: fwrite error", path); - fclose(f); - return (CMD_RETURN_ERROR); - } - fclose(f); + if (c->session == NULL || (c->flags & CLIENT_CONTROL)) + goto do_stdout; + goto do_print; } + c = cmdq->client; + if (c != NULL) + wd = c->cwd; + else if ((s = cmd_current_session(cmdq, 0)) != NULL) { + wd = options_get_string(&s->options, "default-path"); + if (*wd == '\0') + wd = s->cwd; + } else + wd = NULL; + if (wd != NULL && *wd != '\0') { + newpath = get_full_path(wd, path); + if (newpath != NULL) + path = newpath; + } + + mask = umask(S_IRWXG | S_IRWXO); + if (args_has(self->args, 'a')) + f = fopen(path, "ab"); + else + f = fopen(path, "wb"); + umask(mask); + if (f == NULL) { + cmdq_error(cmdq, "%s: %s", path, strerror(errno)); + return (CMD_RETURN_ERROR); + } + if (fwrite(pb->data, 1, pb->size, f) != pb->size) { + cmdq_error(cmdq, "%s: fwrite error", path); + fclose(f); + return (CMD_RETURN_ERROR); + } + fclose(f); + + return (CMD_RETURN_NORMAL); + +do_stdout: + evbuffer_add(c->stdout_data, pb->data, pb->size); + server_push_stdout(c); + return (CMD_RETURN_NORMAL); + +do_print: + if (pb->size > (INT_MAX / 4) - 1) { + cmdq_error(cmdq, "buffer too big"); + return (CMD_RETURN_ERROR); + } + msg = NULL; + msglen = 0; + + used = 0; + while (used != pb->size) { + start = pb->data + used; + end = memchr(start, '\n', pb->size - used); + if (end != NULL) + size = end - start; + else + size = pb->size - used; + + msglen = size * 4 + 1; + msg = xrealloc(msg, 1, msglen); + + strvisx(msg, start, size, VIS_OCTAL|VIS_TAB); + cmdq_print(cmdq, "%s", msg); + + used += size + (end != NULL); + } + + free(msg); return (CMD_RETURN_NORMAL); } diff --git a/cmd-select-layout.c b/cmd-select-layout.c index c5f64a07..4b01a69d 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -25,7 +25,7 @@ */ void cmd_select_layout_key_binding(struct cmd *, int); -enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", @@ -83,14 +83,14 @@ cmd_select_layout_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; const char *layoutname; int next, previous, layout; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); next = self->entry == &cmd_next_layout_entry; @@ -106,7 +106,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) else layout = layout_set_previous(wl->window); server_redraw_window(wl->window); - ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); + cmdq_info(cmdq, "arranging in: %s", layout_set_name(layout)); return (CMD_RETURN_NORMAL); } @@ -117,18 +117,18 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) if (layout != -1) { layout = layout_set_select(wl->window, layout); server_redraw_window(wl->window); - ctx->info(ctx, "arranging in: %s", layout_set_name(layout)); + cmdq_info(cmdq, "arranging in: %s", layout_set_name(layout)); return (CMD_RETURN_NORMAL); } if (args->argc != 0) { layoutname = args->argv[0]; if (layout_parse(wl->window, layoutname) == -1) { - ctx->error(ctx, "can't set layout: %s", layoutname); + cmdq_error(cmdq, "can't set layout: %s", layoutname); return (CMD_RETURN_ERROR); } server_redraw_window(wl->window); - ctx->info(ctx, "arranging in: %s", layoutname); + cmdq_info(cmdq, "arranging in: %s", layoutname); } return (CMD_RETURN_NORMAL); } diff --git a/cmd-select-pane.c b/cmd-select-pane.c index fce34784..459e98cf 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -25,7 +25,7 @@ */ void cmd_select_pane_key_binding(struct cmd *, int); -enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_select_pane_entry = { "select-pane", "selectp", @@ -64,19 +64,19 @@ cmd_select_pane_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; struct window_pane *wp; if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) { - wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); if (wl == NULL) return (CMD_RETURN_ERROR); if (wl->window->last == NULL) { - ctx->error(ctx, "no last pane"); + cmdq_error(cmdq, "no last pane"); return (CMD_RETURN_ERROR); } @@ -87,11 +87,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_NORMAL); } - if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL) + if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); if (!window_pane_visible(wp)) { - ctx->error(ctx, "pane not visible"); + cmdq_error(cmdq, "pane not visible"); return (CMD_RETURN_ERROR); } @@ -104,7 +104,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx) else if (args_has(self->args, 'D')) wp = window_pane_find_down(wp); if (wp == NULL) { - ctx->error(ctx, "pane not found"); + cmdq_error(cmdq, "pane not found"); return (CMD_RETURN_ERROR); } diff --git a/cmd-select-window.c b/cmd-select-window.c index 70d60bed..6206ae4b 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -27,7 +27,7 @@ */ void cmd_select_window_key_binding(struct cmd *, int); -enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_select_window_entry = { "select-window", "selectw", @@ -84,7 +84,7 @@ cmd_select_window_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; @@ -102,31 +102,31 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) last = 1; if (next || previous || last) { - s = cmd_find_session(ctx, args_get(args, 't'), 0); + s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); activity = args_has(self->args, 'a'); if (next) { if (session_next(s, activity) != 0) { - ctx->error(ctx, "no next window"); + cmdq_error(cmdq, "no next window"); return (CMD_RETURN_ERROR); } } else if (previous) { if (session_previous(s, activity) != 0) { - ctx->error(ctx, "no previous window"); + cmdq_error(cmdq, "no previous window"); return (CMD_RETURN_ERROR); } } else { if (session_last(s) != 0) { - ctx->error(ctx, "no last window"); + cmdq_error(cmdq, "no last window"); return (CMD_RETURN_ERROR); } } server_redraw_session(s); } else { - wl = cmd_find_window(ctx, args_get(args, 't'), &s); + wl = cmd_find_window(cmdq, args_get(args, 't'), &s); if (wl == NULL) return (CMD_RETURN_ERROR); @@ -136,7 +136,7 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx) */ if (args_has(self->args, 'T') && wl == s->curw) { if (session_last(s) != 0) { - ctx->error(ctx, "no last window"); + cmdq_error(cmdq, "no last window"); return (-1); } server_redraw_session(s); diff --git a/cmd-send-keys.c b/cmd-send-keys.c index f6124d3a..3ee3dbe6 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -27,7 +27,7 @@ * Send keys to client. */ -enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_send_keys_entry = { "send-keys", "send", @@ -39,8 +39,18 @@ const struct cmd_entry cmd_send_keys_entry = { cmd_send_keys_exec }; +const struct cmd_entry cmd_send_prefix_entry = { + "send-prefix", NULL, + "2t:", 0, 0, + "[-2] " CMD_TARGET_PANE_USAGE, + 0, + NULL, + NULL, + cmd_send_keys_exec +}; + enum cmd_retval -cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct window_pane *wp; @@ -49,9 +59,18 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx) const char *str; int i, key; - if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL) + if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL) return (CMD_RETURN_ERROR); + if (self->entry == &cmd_send_prefix_entry) { + if (args_has(args, '2')) + key = options_get_number(&s->options, "prefix2"); + else + key = options_get_number(&s->options, "prefix"); + window_pane_key(wp, s, key); + return (CMD_RETURN_NORMAL); + } + if (args_has(args, 'R')) { ictx = &wp->ictx; diff --git a/cmd-server-info.c b/cmd-server-info.c index cefb70f4..a26fe705 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -31,7 +31,7 @@ * Show various information about server. */ -enum cmd_retval cmd_server_info_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_server_info_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_server_info_entry = { "server-info", "info", @@ -44,7 +44,7 @@ const struct cmd_entry cmd_server_info_entry = { }; enum cmd_retval -cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) +cmd_server_info_exec(unused struct cmd *self, struct cmd_q *cmdq) { struct tty_term *term; struct client *c; @@ -66,47 +66,47 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) tim = ctime(&start_time); *strchr(tim, '\n') = '\0'; - ctx->print(ctx, "pid %ld, started %s", (long) getpid(), tim); - ctx->print( - ctx, "socket path %s, debug level %d", socket_path, debug_level); + cmdq_print(cmdq, "pid %ld, started %s", (long) getpid(), tim); + cmdq_print(cmdq, "socket path %s, debug level %d", socket_path, + debug_level); if (uname(&un) >= 0) { - ctx->print(ctx, "system is %s %s %s %s", + cmdq_print(cmdq, "system is %s %s %s %s", un.sysname, un.release, un.version, un.machine); } if (cfg_file != NULL) - ctx->print(ctx, "configuration file is %s", cfg_file); + cmdq_print(cmdq, "configuration file is %s", cfg_file); else - ctx->print(ctx, "configuration file not specified"); - ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION); - ctx->print(ctx, "%s", ""); + cmdq_print(cmdq, "configuration file not specified"); + cmdq_print(cmdq, "protocol version is %d", PROTOCOL_VERSION); + cmdq_print(cmdq, "%s", ""); - ctx->print(ctx, "Clients:"); + cmdq_print(cmdq, "Clients:"); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; - ctx->print(ctx,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho " + cmdq_print(cmdq,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho " "class=%u] [flags=0x%x/0x%x, references=%u]", i, c->tty.path, c->ibuf.fd, c->tty.fd, c->session->name, c->tty.sx, c->tty.sy, c->tty.termname, c->tty.tio.c_cc[VERASE], c->tty.class, c->flags, c->tty.flags, c->references); } - ctx->print(ctx, "%s", ""); + cmdq_print(cmdq, "%s", ""); - ctx->print(ctx, "Sessions: [%zu]", sizeof (struct grid_cell)); + cmdq_print(cmdq, "Sessions: [%zu]", sizeof (struct grid_cell)); RB_FOREACH(s, sessions, &sessions) { t = s->creation_time.tv_sec; tim = ctime(&t); *strchr(tim, '\n') = '\0'; - ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] " + cmdq_print(cmdq, "%2u: %s: %u windows (created %s) [%ux%u] " "[flags=0x%x]", s->idx, s->name, winlink_count(&s->windows), tim, s->sx, s->sy, s->flags); RB_FOREACH(wl, winlinks, &s->windows) { w = wl->window; - ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, " + cmdq_print(cmdq, "%4u: %s [%ux%u] [flags=0x%x, " "references=%u, last layout=%d]", wl->idx, w->name, w->sx, w->sy, w->flags, w->references, w->lastlayout); @@ -122,7 +122,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) size += gl->cellsize * sizeof *gl->celldata; } - ctx->print(ctx, + cmdq_print(cmdq, "%6u: %s %lu %d %u/%u, %zu bytes", j, wp->tty, (u_long) wp->pid, wp->fd, lines, gd->hsize + gd->sy, size); @@ -130,43 +130,43 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx) } } } - ctx->print(ctx, "%s", ""); + cmdq_print(cmdq, "%s", ""); - ctx->print(ctx, "Terminals:"); + cmdq_print(cmdq, "Terminals:"); LIST_FOREACH(term, &tty_terms, entry) { - ctx->print(ctx, "%s [references=%u, flags=0x%x]:", + cmdq_print(cmdq, "%s [references=%u, flags=0x%x]:", term->name, term->references, term->flags); for (i = 0; i < NTTYCODE; i++) { ent = &tty_term_codes[i]; code = &term->codes[ent->code]; switch (code->type) { case TTYCODE_NONE: - ctx->print(ctx, "%2u: %s: [missing]", + cmdq_print(cmdq, "%2u: %s: [missing]", ent->code, ent->name); break; case TTYCODE_STRING: strnvis(out, code->value.string, sizeof out, VIS_OCTAL|VIS_TAB|VIS_NL); - ctx->print(ctx, "%2u: %s: (string) %s", + cmdq_print(cmdq, "%2u: %s: (string) %s", ent->code, ent->name, out); break; case TTYCODE_NUMBER: - ctx->print(ctx, "%2u: %s: (number) %d", + cmdq_print(cmdq, "%2u: %s: (number) %d", ent->code, ent->name, code->value.number); break; case TTYCODE_FLAG: - ctx->print(ctx, "%2u: %s: (flag) %s", + cmdq_print(cmdq, "%2u: %s: (flag) %s", ent->code, ent->name, code->value.flag ? "true" : "false"); break; } } } - ctx->print(ctx, "%s", ""); + cmdq_print(cmdq, "%s", ""); - ctx->print(ctx, "Jobs:"); + cmdq_print(cmdq, "Jobs:"); LIST_FOREACH(job, &all_jobs, lentry) { - ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d]", + cmdq_print(cmdq, "%s [fd=%d, pid=%d, status=%d]", job->cmd, job->fd, job->pid, job->status); } diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index e3b1656b..46450e21 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -27,7 +27,7 @@ * Add or set a paste buffer. */ -enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_set_buffer_entry = { "set-buffer", "setb", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_set_buffer_entry = { }; enum cmd_retval -cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; u_int limit; @@ -60,14 +60,14 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx) buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (cause != NULL) { - ctx->error(ctx, "buffer %s", cause); + cmdq_error(cmdq, "buffer %s", cause); free(cause); free(pdata); return (CMD_RETURN_ERROR); } if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) { - ctx->error(ctx, "no buffer %d", buffer); + cmdq_error(cmdq, "no buffer %d", buffer); free(pdata); return (CMD_RETURN_ERROR); } diff --git a/cmd-set-environment.c b/cmd-set-environment.c index 9cebc951..6e75a294 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -27,7 +27,7 @@ * Set an environment variable. */ -enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_set_environment_entry = { "set-environment", "setenv", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_set_environment_entry = { }; enum cmd_retval -cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -49,11 +49,11 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) name = args->argv[0]; if (*name == '\0') { - ctx->error(ctx, "empty variable name"); + cmdq_error(cmdq, "empty variable name"); return (CMD_RETURN_ERROR); } if (strchr(name, '=') != NULL) { - ctx->error(ctx, "variable name contains ="); + cmdq_error(cmdq, "variable name contains ="); return (CMD_RETURN_ERROR); } @@ -65,26 +65,26 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) env = &global_environ; else { - if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); env = &s->environ; } if (args_has(self->args, 'u')) { if (value != NULL) { - ctx->error(ctx, "can't specify a value with -u"); + cmdq_error(cmdq, "can't specify a value with -u"); return (CMD_RETURN_ERROR); } environ_unset(env, name); } else if (args_has(self->args, 'r')) { if (value != NULL) { - ctx->error(ctx, "can't specify a value with -r"); + cmdq_error(cmdq, "can't specify a value with -r"); return (CMD_RETURN_ERROR); } environ_set(env, name, NULL); } else { if (value == NULL) { - ctx->error(ctx, "no value specified"); + cmdq_error(cmdq, "no value specified"); return (CMD_RETURN_ERROR); } environ_set(env, name, value); diff --git a/cmd-show-environment.c b/cmd-show-environment.c index e7b9f7c9..cb53e84c 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -27,7 +27,7 @@ * Show environment. */ -enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_show_environment_entry = { "show-environment", "showenv", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_show_environment_entry = { }; enum cmd_retval -cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -50,7 +50,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) env = &global_environ; else { - if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL) + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); env = &s->environ; } @@ -58,21 +58,21 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx) if (args->argc != 0) { envent = environ_find(env, args->argv[0]); if (envent == NULL) { - ctx->error(ctx, "unknown variable: %s", args->argv[0]); + cmdq_error(cmdq, "unknown variable: %s", args->argv[0]); return (CMD_RETURN_ERROR); } if (envent->value != NULL) - ctx->print(ctx, "%s=%s", envent->name, envent->value); + cmdq_print(cmdq, "%s=%s", envent->name, envent->value); else - ctx->print(ctx, "-%s", envent->name); + cmdq_print(cmdq, "-%s", envent->name); return (CMD_RETURN_NORMAL); } RB_FOREACH(envent, environ, env) { if (envent->value != NULL) - ctx->print(ctx, "%s=%s", envent->name, envent->value); + cmdq_print(cmdq, "%s=%s", envent->name, envent->value); else - ctx->print(ctx, "-%s", envent->name); + cmdq_print(cmdq, "-%s", envent->name); } return (CMD_RETURN_NORMAL); diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 8394e3de..cbf083a7 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -27,7 +27,7 @@ * Show client message log. */ -enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_show_messages_entry = { "show-messages", "showmsgs", @@ -40,7 +40,7 @@ const struct cmd_entry cmd_show_messages_entry = { }; enum cmd_retval -cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; @@ -48,7 +48,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) char *tim; u_int i; - if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) + if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { @@ -57,7 +57,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) tim = ctime(&msg->msg_time); *strchr(tim, '\n') = '\0'; - ctx->print(ctx, "%s %s", tim, msg->msg); + cmdq_print(cmdq, "%s %s", tim, msg->msg); } return (CMD_RETURN_NORMAL); diff --git a/cmd-show-options.c b/cmd-show-options.c index b42c65cb..9b42ed46 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -27,11 +27,11 @@ * Show options. */ -enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_q *); -enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_ctx *, +enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_q *, struct options *); -enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_ctx *, +enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *); const struct cmd_entry cmd_show_options_entry = { @@ -55,7 +55,7 @@ const struct cmd_entry cmd_show_window_options_entry = { }; enum cmd_retval -cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -72,7 +72,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) oo = &global_w_options; else { - wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); if (wl == NULL) return (CMD_RETURN_ERROR); oo = &wl->window->options; @@ -82,7 +82,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) oo = &global_s_options; else { - s = cmd_find_session(ctx, args_get(args, 't'), 0); + s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); oo = &s->options; @@ -90,13 +90,13 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx) } if (args->argc != 0) - return (cmd_show_options_one(self, ctx, oo)); + return (cmd_show_options_one(self, cmdq, oo)); else - return (cmd_show_options_all(self, ctx, table, oo)); + return (cmd_show_options_all(self, cmdq, table, oo)); } enum cmd_retval -cmd_show_options_one(struct cmd *self, struct cmd_ctx *ctx, +cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq, struct options *oo) { struct args *args = self->args; @@ -106,37 +106,37 @@ cmd_show_options_one(struct cmd *self, struct cmd_ctx *ctx, if (*args->argv[0] == '@') { if ((o = options_find1(oo, args->argv[0])) == NULL) { - ctx->error(ctx, "unknown option: %s", args->argv[0]); + cmdq_error(cmdq, "unknown option: %s", args->argv[0]); return (CMD_RETURN_ERROR); } if (args_has(self->args, 'v')) - ctx->print(ctx, "%s", o->str); + cmdq_print(cmdq, "%s", o->str); else - ctx->print(ctx, "%s \"%s\"", o->name, o->str); + cmdq_print(cmdq, "%s \"%s\"", o->name, o->str); return (CMD_RETURN_NORMAL); } table = oe = NULL; if (options_table_find(args->argv[0], &table, &oe) != 0) { - ctx->error(ctx, "ambiguous option: %s", args->argv[0]); + cmdq_error(cmdq, "ambiguous option: %s", args->argv[0]); return (CMD_RETURN_ERROR); } if (oe == NULL) { - ctx->error(ctx, "unknown option: %s", args->argv[0]); + cmdq_error(cmdq, "unknown option: %s", args->argv[0]); return (CMD_RETURN_ERROR); } if ((o = options_find1(oo, oe->name)) == NULL) return (CMD_RETURN_NORMAL); optval = options_table_print_entry(oe, o, args_has(self->args, 'v')); if (args_has(self->args, 'v')) - ctx->print(ctx, "%s", optval); + cmdq_print(cmdq, "%s", optval); else - ctx->print(ctx, "%s %s", oe->name, optval); + cmdq_print(cmdq, "%s %s", oe->name, optval); return (CMD_RETURN_NORMAL); } enum cmd_retval -cmd_show_options_all(struct cmd *self, struct cmd_ctx *ctx, +cmd_show_options_all(struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *table, struct options *oo) { const struct options_table_entry *oe; @@ -146,9 +146,9 @@ cmd_show_options_all(struct cmd *self, struct cmd_ctx *ctx, RB_FOREACH(o, options_tree, &oo->tree) { if (*o->name == '@') { if (args_has(self->args, 'v')) - ctx->print(ctx, "%s", o->str); + cmdq_print(cmdq, "%s", o->str); else - ctx->print(ctx, "%s \"%s\"", o->name, o->str); + cmdq_print(cmdq, "%s \"%s\"", o->name, o->str); } } @@ -158,9 +158,9 @@ cmd_show_options_all(struct cmd *self, struct cmd_ctx *ctx, optval = options_table_print_entry(oe, o, args_has(self->args, 'v')); if (args_has(self->args, 'v')) - ctx->print(ctx, "%s", optval); + cmdq_print(cmdq, "%s", optval); else - ctx->print(ctx, "%s %s", oe->name, optval); + cmdq_print(cmdq, "%s %s", oe->name, optval); } return (CMD_RETURN_NORMAL); diff --git a/cmd-source-file.c b/cmd-source-file.c index 0a180d89..3d69a544 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -26,7 +26,10 @@ * Sources a configuration file. */ -enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *); + +void cmd_source_file_show(struct cmd_q *); +void cmd_source_file_done(struct cmd_q *); const struct cmd_entry cmd_source_file_entry = { "source-file", "source", @@ -39,35 +42,66 @@ const struct cmd_entry cmd_source_file_entry = { }; enum cmd_retval -cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq) { - struct args *args = self->args; - int retval; - u_int i; - char *cause; + struct args *args = self->args; + struct cmd_q *cmdq1; + char *cause; - retval = load_cfg(args->argv[0], ctx, &cfg_causes); + cmdq1 = cmdq_new(NULL); + cmdq1->emptyfn = cmd_source_file_done; + cmdq1->data = cmdq; - /* - * If the context for the cmdclient came from tmux's configuration - * file, then return the status of this command now, regardless of the - * error condition. Any errors from parsing a configuration file at - * startup will be handled for us by the server. - */ - if (cfg_references > 0 || - (ctx->curclient == NULL && ctx->cmdclient == NULL)) - return (retval); + switch (load_cfg(args->argv[0], cmdq1, &cause)) { + case -1: + if (cfg_references == 0) { + cmdq_free(cmdq1); + cmdq_error(cmdq, "%s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + ARRAY_ADD(&cfg_causes, cause); + /* FALLTHROUGH */ + case 0: + if (cfg_references == 0) + cmd_source_file_show(cmdq); + cmdq_free(cmdq1); + return (CMD_RETURN_NORMAL); + } + + cmdq->references++; + cfg_references++; + + cmdq_continue(cmdq1); + return (CMD_RETURN_WAIT); +} + +void +cmd_source_file_show(struct cmd_q *cmdq) +{ + u_int i; + char *cause; - /* - * We were called from the command-line in which case print the errors - * gathered here directly. - */ for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { cause = ARRAY_ITEM(&cfg_causes, i); - ctx->print(ctx, "%s", cause); + cmdq_print(cmdq, "%s", cause); free(cause); } ARRAY_FREE(&cfg_causes); - - return (retval); +} + +void +cmd_source_file_done(struct cmd_q *cmdq1) +{ + struct cmd_q *cmdq = cmdq1->data; + + cmdq_free(cmdq1); + + cfg_references--; + if (cmdq_free(cmdq) || cfg_references != 0) + return; + + cmd_source_file_show(cmdq); + + cmdq_continue(cmdq); } diff --git a/cmd-split-window.c b/cmd-split-window.c index b9eb92e3..87c0e6bc 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -29,7 +29,7 @@ */ void cmd_split_window_key_binding(struct cmd *, int); -enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", @@ -51,7 +51,7 @@ cmd_split_window_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -70,7 +70,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct format_tree *ft; char *cp; - if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) + if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) return (CMD_RETURN_ERROR); w = wl->window; @@ -83,7 +83,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = cmd_get_default_path(ctx, args_get(args, 'c')); + cwd = cmd_get_default_path(cmdq, args_get(args, 'c')); type = LAYOUT_TOPBOTTOM; if (args_has(args, 'h')) @@ -152,14 +152,14 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) template = SPLIT_WINDOW_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(ctx, NULL, 1)) != NULL) - format_client(ft, c); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); format_window_pane(ft, new_wp); cp = format_expand(ft, template); - ctx->print(ctx, "%s", cp); + cmdq_print(cmdq, "%s", cp); free(cp); format_free(ft); @@ -171,7 +171,7 @@ error: environ_free(&env); if (new_wp != NULL) window_remove_pane(w, new_wp); - ctx->error(ctx, "create pane failed: %s", cause); + cmdq_error(cmdq, "create pane failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } diff --git a/cmd-start-server.c b/cmd-start-server.c index ae425a73..c926b5fe 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -24,7 +24,7 @@ * Start the server and do nothing else. */ -enum cmd_retval cmd_start_server_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_start_server_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_start_server_entry = { "start-server", "start", @@ -37,7 +37,7 @@ const struct cmd_entry cmd_start_server_entry = { }; enum cmd_retval -cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx) +cmd_start_server_exec(unused struct cmd *self, unused struct cmd_q *cmdq) { return (CMD_RETURN_NORMAL); } diff --git a/cmd-string.c b/cmd-string.c index 5a27c5bd..f785b842 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -59,7 +59,8 @@ cmd_string_ungetc(size_t *p) * string, or NULL for empty command. */ int -cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) +cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file, + u_int line, char **cause) { size_t p; int ch, i, argc, rval; @@ -131,7 +132,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause) if (argc == 0) goto out; - *cmdlist = cmd_list_parse(argc, argv, cause); + *cmdlist = cmd_list_parse(argc, argv, file, line, cause); if (*cmdlist == NULL) goto out; diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index c3806c6f..dda0f977 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -27,7 +27,7 @@ * Suspend client with SIGTSTP. */ -enum cmd_retval cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_suspend_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_suspend_client_entry = { "suspend-client", "suspendc", @@ -40,12 +40,12 @@ const struct cmd_entry cmd_suspend_client_entry = { }; enum cmd_retval -cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_suspend_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; - if ((c = cmd_find_client(ctx, args_get(args, 't'), 0)) == NULL) + if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); tty_stop_tty(&c->tty); diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 6d9fcfeb..ae875946 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -27,7 +27,7 @@ */ void cmd_swap_pane_key_binding(struct cmd *, int); -enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_swap_pane_entry = { "swap-pane", "swapp", @@ -50,7 +50,7 @@ cmd_swap_pane_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *src_wl, *dst_wl; @@ -59,7 +59,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) struct layout_cell *src_lc, *dst_lc; u_int sx, sy, xoff, yoff; - dst_wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &dst_wp); + dst_wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &dst_wp); if (dst_wl == NULL) return (CMD_RETURN_ERROR); dst_w = dst_wl->window; @@ -77,7 +77,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } else return (CMD_RETURN_NORMAL); } else { - src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp); + src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp); if (src_wl == NULL) return (CMD_RETURN_ERROR); src_w = src_wl->window; diff --git a/cmd-swap-window.c b/cmd-swap-window.c index b2e2c119..ed175480 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -26,7 +26,7 @@ * Swap one window with another. */ -enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_swap_window_entry = { "swap-window", "swapw", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_swap_window_entry = { }; enum cmd_retval -cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; const char *target_src, *target_dst; @@ -49,17 +49,17 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window *w; target_src = args_get(args, 's'); - if ((wl_src = cmd_find_window(ctx, target_src, &src)) == NULL) + if ((wl_src = cmd_find_window(cmdq, target_src, &src)) == NULL) return (CMD_RETURN_ERROR); target_dst = args_get(args, 't'); - if ((wl_dst = cmd_find_window(ctx, target_dst, &dst)) == NULL) + if ((wl_dst = cmd_find_window(cmdq, target_dst, &dst)) == NULL) return (CMD_RETURN_ERROR); sg_src = session_group_find(src); sg_dst = session_group_find(dst); if (src != dst && sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) { - ctx->error(ctx, "can't move window, sessions are grouped"); + cmdq_error(cmdq, "can't move window, sessions are grouped"); return (CMD_RETURN_ERROR); } diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 0fcf0146..ea5012ed 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -28,7 +28,7 @@ */ void cmd_switch_client_key_binding(struct cmd *, int); -enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", @@ -58,45 +58,45 @@ cmd_switch_client_key_binding(struct cmd *self, int key) } enum cmd_retval -cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; struct session *s; - if ((c = cmd_find_client(ctx, args_get(args, 'c'), 0)) == NULL) + if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL) return (CMD_RETURN_ERROR); if (args_has(args, 'r')) { if (c->flags & CLIENT_READONLY) { c->flags &= ~CLIENT_READONLY; - ctx->info(ctx, "made client writable"); + cmdq_info(cmdq, "made client writable"); } else { c->flags |= CLIENT_READONLY; - ctx->info(ctx, "made client read-only"); + cmdq_info(cmdq, "made client read-only"); } } s = NULL; if (args_has(args, 'n')) { if ((s = session_next_session(c->session)) == NULL) { - ctx->error(ctx, "can't find next session"); + cmdq_error(cmdq, "can't find next session"); return (CMD_RETURN_ERROR); } } else if (args_has(args, 'p')) { if ((s = session_previous_session(c->session)) == NULL) { - ctx->error(ctx, "can't find previous session"); + cmdq_error(cmdq, "can't find previous session"); return (CMD_RETURN_ERROR); } } else if (args_has(args, 'l')) { if (c->last_session != NULL && session_alive(c->last_session)) s = c->last_session; if (s == NULL) { - ctx->error(ctx, "can't find last session"); + cmdq_error(cmdq, "can't find last session"); return (CMD_RETURN_ERROR); } } else - s = cmd_find_session(ctx, args_get(args, 't'), 0); + s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 4a39f51b..88c81270 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -27,8 +27,8 @@ */ enum cmd_retval cmd_unbind_key_check(struct args *); -enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *); -enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int); +enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); +enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_q *, int); const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", @@ -51,7 +51,7 @@ cmd_unbind_key_check(struct args *args) } enum cmd_retval -cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) +cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct key_binding *bd; @@ -60,14 +60,14 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) if (!args_has(args, 'a')) { key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { - ctx->error(ctx, "unknown key: %s", args->argv[0]); + cmdq_error(cmdq, "unknown key: %s", args->argv[0]); return (CMD_RETURN_ERROR); } } else key = KEYC_NONE; if (args_has(args, 't')) - return (cmd_unbind_key_table(self, ctx, key)); + return (cmd_unbind_key_table(self, cmdq, key)); if (key == KEYC_NONE) { while (!RB_EMPTY(&key_bindings)) { @@ -84,7 +84,7 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx) } enum cmd_retval -cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) +cmd_unbind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) { struct args *args = self->args; const char *tablename; @@ -93,7 +93,7 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { - ctx->error(ctx, "unknown key table: %s", tablename); + cmdq_error(cmdq, "unknown key table: %s", tablename); return (CMD_RETURN_ERROR); } diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index c3d3c2ee..78c4b390 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -24,7 +24,7 @@ * Unlink a window, unless it would be destroyed by doing so (only one link). */ -enum cmd_retval cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_unlink_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_unlink_window_entry = { "unlink-window", "unlinkw", @@ -37,7 +37,7 @@ const struct cmd_entry cmd_unlink_window_entry = { }; enum cmd_retval -cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_unlink_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; @@ -46,7 +46,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct session_group *sg; u_int references; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) + if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL) return (CMD_RETURN_ERROR); w = wl->window; @@ -59,7 +59,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx) references = 1; if (!args_has(self->args, 'k') && w->references == references) { - ctx->error(ctx, "window is only linked to one session"); + cmdq_error(cmdq, "window is only linked to one session"); return (CMD_RETURN_ERROR); } diff --git a/cmd.c b/cmd.c index 6fe4d565..5f530299 100644 --- a/cmd.c +++ b/cmd.c @@ -127,48 +127,12 @@ int cmd_lookup_index(struct session *, const char *, int *); struct window_pane *cmd_lookup_paneid(const char *); struct winlink *cmd_lookup_winlink_windowid(struct session *, const char *); struct window *cmd_lookup_windowid(const char *); -struct session *cmd_window_session(struct cmd_ctx *, - struct window *, struct winlink **); +struct session *cmd_window_session(struct cmd_q *, struct window *, + struct winlink **); struct winlink *cmd_find_window_offset(const char *, struct session *, int *); int cmd_find_index_offset(const char *, struct session *, int *); struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); -struct cmd_ctx * -cmd_get_ctx(struct client *cmdclient, struct client *curclient) -{ - struct cmd_ctx *ctx; - - ctx = xcalloc(1, sizeof *ctx); - ctx->references = 0; - - ctx->cmdclient = cmdclient; - ctx->curclient = curclient; - - cmd_ref_ctx(ctx); - return (ctx); -} - -void -cmd_free_ctx(struct cmd_ctx *ctx) -{ - if (ctx->cmdclient != NULL) - ctx->cmdclient->references--; - if (ctx->curclient != NULL) - ctx->curclient->references--; - if (--ctx->references == 0) - free(ctx); -} - -void -cmd_ref_ctx(struct cmd_ctx *ctx) -{ - ctx->references++; - if (ctx->cmdclient != NULL) - ctx->cmdclient->references++; - if (ctx->curclient != NULL) - ctx->curclient->references++; -} - int cmd_pack_argv(int argc, char **argv, char *buf, size_t len) { @@ -242,7 +206,7 @@ cmd_free_argv(int argc, char **argv) } struct cmd * -cmd_parse(int argc, char **argv, char **cause) +cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) { const struct cmd_entry **entryp, *entry; struct cmd *cmd; @@ -292,9 +256,14 @@ cmd_parse(int argc, char **argv, char **cause) if (entry->check != NULL && entry->check(args) != 0) goto usage; - cmd = xmalloc(sizeof *cmd); + cmd = xcalloc(1, sizeof *cmd); cmd->entry = entry; cmd->args = args; + + if (file != NULL) + cmd->file = xstrdup(file); + cmd->line = line; + return (cmd); ambiguous: @@ -343,31 +312,33 @@ cmd_print(struct cmd *cmd, char *buf, size_t len) * session from all sessions. */ struct session * -cmd_current_session(struct cmd_ctx *ctx, int prefer_unattached) +cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) { - struct msg_command_data *data = ctx->msgdata; - struct client *c = ctx->cmdclient; + struct msg_command_data *data = cmdq->msgdata; + struct client *c = cmdq->client; struct session *s; struct sessionslist ss; struct winlink *wl; struct window_pane *wp; + const char *path; int found; - if (ctx->curclient != NULL && ctx->curclient->session != NULL) - return (ctx->curclient->session); + if (c != NULL && c->session != NULL) + return (c->session); /* * If the name of the calling client's pty is know, build a list of the * sessions that contain it and if any choose either the first or the * newest. */ - if (c != NULL && c->tty.path != NULL) { + path = c == NULL ? NULL : c->tty.path; + if (path != NULL) { ARRAY_INIT(&ss); RB_FOREACH(s, sessions, &sessions) { found = 0; RB_FOREACH(wl, winlinks, &s->windows) { TAILQ_FOREACH(wp, &wl->window->panes, entry) { - if (strcmp(wp->tty, c->tty.path) == 0) { + if (strcmp(wp->tty, path) == 0) { found = 1; break; } @@ -458,21 +429,21 @@ cmd_choose_session_list(struct sessionslist *ss) * then of all clients. */ struct client * -cmd_current_client(struct cmd_ctx *ctx) +cmd_current_client(struct cmd_q *cmdq) { struct session *s; struct client *c; struct clients cc; u_int i; - if (ctx->curclient != NULL) - return (ctx->curclient); + if (cmdq->client != NULL && cmdq->client->session != NULL) + return (cmdq->client); /* * No current client set. Find the current session and return the * newest of its clients. */ - s = cmd_current_session(ctx, 0); + s = cmd_current_session(cmdq, 0); if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { ARRAY_INIT(&cc); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { @@ -517,7 +488,7 @@ cmd_choose_client(struct clients *cc) /* Find the target client or report an error and return NULL. */ struct client * -cmd_find_client(struct cmd_ctx *ctx, const char *arg, int quiet) +cmd_find_client(struct cmd_q *cmdq, const char *arg, int quiet) { struct client *c; char *tmparg; @@ -525,9 +496,9 @@ cmd_find_client(struct cmd_ctx *ctx, const char *arg, int quiet) /* A NULL argument means the current client. */ if (arg == NULL) { - c = cmd_current_client(ctx); + c = cmd_current_client(cmdq); if (c == NULL && !quiet) - ctx->error(ctx, "no clients"); + cmdq_error(cmdq, "no clients"); return (c); } tmparg = xstrdup(arg); @@ -542,7 +513,7 @@ cmd_find_client(struct cmd_ctx *ctx, const char *arg, int quiet) /* If no client found, report an error. */ if (c == NULL && !quiet) - ctx->error(ctx, "client not found: %s", tmparg); + cmdq_error(cmdq, "client not found: %s", tmparg); free(tmparg); return (c); @@ -744,14 +715,14 @@ cmd_lookup_windowid(const char *arg) /* Find session and winlink for window. */ struct session * -cmd_window_session(struct cmd_ctx *ctx, struct window *w, struct winlink **wlp) +cmd_window_session(struct cmd_q *cmdq, struct window *w, struct winlink **wlp) { struct session *s; struct sessionslist ss; struct winlink *wl; /* If this window is in the current session, return that winlink. */ - s = cmd_current_session(ctx, 0); + s = cmd_current_session(cmdq, 0); if (s != NULL) { wl = winlink_find_by_window(&s->windows, w); if (wl != NULL) { @@ -776,7 +747,7 @@ cmd_window_session(struct cmd_ctx *ctx, struct window *w, struct winlink **wlp) /* Find the target session or report an error and return NULL. */ struct session * -cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) +cmd_find_session(struct cmd_q *cmdq, const char *arg, int prefer_unattached) { struct session *s; struct window_pane *wp; @@ -788,13 +759,13 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) /* A NULL argument means the current session. */ if (arg == NULL) - return (cmd_current_session(ctx, prefer_unattached)); + return (cmd_current_session(cmdq, prefer_unattached)); /* Lookup as pane id or window id. */ if ((wp = cmd_lookup_paneid(arg)) != NULL) - return (cmd_window_session(ctx, wp->window, NULL)); + return (cmd_window_session(cmdq, wp->window, NULL)); if ((w = cmd_lookup_windowid(arg)) != NULL) - return (cmd_window_session(ctx, w, NULL)); + return (cmd_window_session(cmdq, w, NULL)); /* Trim a single trailing colon if any. */ tmparg = xstrdup(arg); @@ -805,7 +776,7 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) /* An empty session name is the current session. */ if (*tmparg == '\0') { free(tmparg); - return (cmd_current_session(ctx, prefer_unattached)); + return (cmd_current_session(cmdq, prefer_unattached)); } /* Find the session, if any. */ @@ -818,9 +789,9 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) /* If no session found, report an error. */ if (s == NULL) { if (ambiguous) - ctx->error(ctx, "more than one session: %s", tmparg); + cmdq_error(cmdq, "more than one session: %s", tmparg); else - ctx->error(ctx, "session not found: %s", tmparg); + cmdq_error(cmdq, "session not found: %s", tmparg); } free(tmparg); @@ -829,7 +800,7 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached) /* Find the target session and window or report an error and return NULL. */ struct winlink * -cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) +cmd_find_window(struct cmd_q *cmdq, const char *arg, struct session **sp) { struct session *s; struct winlink *wl; @@ -842,8 +813,8 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) * Find the current session. There must always be a current session, if * it can't be found, report an error. */ - if ((s = cmd_current_session(ctx, 0)) == NULL) { - ctx->error(ctx, "can't establish current session"); + if ((s = cmd_current_session(cmdq, 0)) == NULL) { + cmdq_error(cmdq, "can't establish current session"); return (NULL); } @@ -856,7 +827,7 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) /* Lookup as pane id. */ if ((wp = cmd_lookup_paneid(arg)) != NULL) { - s = cmd_window_session(ctx, wp->window, &wl); + s = cmd_window_session(cmdq, wp->window, &wl); if (sp != NULL) *sp = s; return (wl); @@ -937,17 +908,17 @@ lookup_session: no_session: if (ambiguous) - ctx->error(ctx, "multiple sessions: %s", arg); + cmdq_error(cmdq, "multiple sessions: %s", arg); else - ctx->error(ctx, "session not found: %s", arg); + cmdq_error(cmdq, "session not found: %s", arg); free(sessptr); return (NULL); not_found: if (ambiguous) - ctx->error(ctx, "multiple windows: %s", arg); + cmdq_error(cmdq, "multiple windows: %s", arg); else - ctx->error(ctx, "window not found: %s", arg); + cmdq_error(cmdq, "window not found: %s", arg); free(sessptr); return (NULL); } @@ -979,7 +950,7 @@ cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous) * example if it is going to be created). */ int -cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) +cmd_find_index(struct cmd_q *cmdq, const char *arg, struct session **sp) { struct session *s; struct winlink *wl; @@ -991,8 +962,8 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp) * Find the current session. There must always be a current session, if * it can't be found, report an error. */ - if ((s = cmd_current_session(ctx, 0)) == NULL) { - ctx->error(ctx, "can't establish current session"); + if ((s = cmd_current_session(cmdq, 0)) == NULL) { + cmdq_error(cmdq, "can't establish current session"); return (-2); } @@ -1075,25 +1046,25 @@ lookup_session: no_session: if (ambiguous) - ctx->error(ctx, "multiple sessions: %s", arg); + cmdq_error(cmdq, "multiple sessions: %s", arg); else - ctx->error(ctx, "session not found: %s", arg); + cmdq_error(cmdq, "session not found: %s", arg); free(sessptr); return (-2); invalid_index: if (ambiguous) goto not_found; - ctx->error(ctx, "invalid index: %s", arg); + cmdq_error(cmdq, "invalid index: %s", arg); free(sessptr); return (-2); not_found: if (ambiguous) - ctx->error(ctx, "multiple windows: %s", arg); + cmdq_error(cmdq, "multiple windows: %s", arg); else - ctx->error(ctx, "window not found: %s", arg); + cmdq_error(cmdq, "window not found: %s", arg); free(sessptr); return (-2); } @@ -1130,7 +1101,7 @@ cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous) * such as mysession:mywindow.0. */ struct winlink * -cmd_find_pane(struct cmd_ctx *ctx, +cmd_find_pane(struct cmd_q *cmdq, const char *arg, struct session **sp, struct window_pane **wpp) { struct session *s; @@ -1140,8 +1111,8 @@ cmd_find_pane(struct cmd_ctx *ctx, u_int idx; /* Get the current session. */ - if ((s = cmd_current_session(ctx, 0)) == NULL) { - ctx->error(ctx, "can't establish current session"); + if ((s = cmd_current_session(cmdq, 0)) == NULL) { + cmdq_error(cmdq, "can't establish current session"); return (NULL); } if (sp != NULL) @@ -1155,7 +1126,7 @@ cmd_find_pane(struct cmd_ctx *ctx, /* Lookup as pane id. */ if ((*wpp = cmd_lookup_paneid(arg)) != NULL) { - s = cmd_window_session(ctx, (*wpp)->window, &wl); + s = cmd_window_session(cmdq, (*wpp)->window, &wl); if (sp != NULL) *sp = s; return (wl); @@ -1170,7 +1141,7 @@ cmd_find_pane(struct cmd_ctx *ctx, winptr[period - arg] = '\0'; if (*winptr == '\0') wl = s->curw; - else if ((wl = cmd_find_window(ctx, winptr, sp)) == NULL) + else if ((wl = cmd_find_window(cmdq, winptr, sp)) == NULL) goto error; /* Find the pane section and look it up. */ @@ -1194,7 +1165,7 @@ cmd_find_pane(struct cmd_ctx *ctx, lookup_string: /* Try pane string description. */ if ((*wpp = window_find_string(wl->window, paneptr)) == NULL) { - ctx->error(ctx, "can't find pane: %s", paneptr); + cmdq_error(cmdq, "can't find pane: %s", paneptr); goto error; } @@ -1219,7 +1190,7 @@ lookup_window: return (s->curw); /* Try as a window and use the active pane. */ - if ((wl = cmd_find_window(ctx, arg, sp)) != NULL) + if ((wl = cmd_find_window(cmdq, arg, sp)) != NULL) *wpp = wl->window->active; return (wl); @@ -1297,8 +1268,9 @@ cmd_template_replace(const char *template, const char *s, int idx) * directory. */ const char * -cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd) +cmd_get_default_path(struct cmd_q *cmdq, const char *cwd) { + struct client *c = cmdq->client; struct session *s; struct environ_entry *envent; const char *root; @@ -1308,7 +1280,7 @@ cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd) size_t skip; static char path[MAXPATHLEN]; - if ((s = cmd_current_session(ctx, 0)) == NULL) + if ((s = cmd_current_session(cmdq, 0)) == NULL) return (NULL); if (cwd == NULL) @@ -1338,9 +1310,9 @@ cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd) return (cwd); } else { /* Empty or relative path. */ - if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL) - root = ctx->cmdclient->cwd; - else if (ctx->curclient != NULL && s->curw != NULL) + if (c != NULL && c->session == NULL && c->cwd != NULL) + root = c->cwd; + else if (s->curw != NULL) root = get_proc_cwd(s->curw->window->active->fd); else return (s->cwd); diff --git a/control.c b/control.c index a248e91f..fc2d6e43 100644 --- a/control.c +++ b/control.c @@ -25,46 +25,6 @@ #include "tmux.h" -void printflike2 control_msg_error(struct cmd_ctx *, const char *, ...); -void printflike2 control_msg_print(struct cmd_ctx *, const char *, ...); -void printflike2 control_msg_info(struct cmd_ctx *, const char *, ...); - -/* Command error callback. */ -void printflike2 -control_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct client *c = ctx->curclient; - va_list ap; - - va_start(ap, fmt); - evbuffer_add_vprintf(c->stdout_data, fmt, ap); - va_end(ap); - - evbuffer_add(c->stdout_data, "\n", 1); - server_push_stdout(c); -} - -/* Command print callback. */ -void printflike2 -control_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct client *c = ctx->curclient; - va_list ap; - - va_start(ap, fmt); - evbuffer_add_vprintf(c->stdout_data, fmt, ap); - va_end(ap); - - evbuffer_add(c->stdout_data, "\n", 1); - server_push_stdout(c); -} - -/* Command info callback. */ -void printflike2 -control_msg_info(unused struct cmd_ctx *ctx, unused const char *fmt, ...) -{ -} - /* Write a line. */ void printflike2 control_write(struct client *c, const char *fmt, ...) @@ -93,7 +53,6 @@ void control_callback(struct client *c, int closed, unused void *data) { char *line, *cause; - struct cmd_ctx *ctx; struct cmd_list *cmdlist; if (closed) @@ -108,20 +67,14 @@ control_callback(struct client *c, int closed, unused void *data) break; } - ctx = cmd_get_ctx(NULL, c); - ctx->error = control_msg_error; - ctx->print = control_msg_print; - ctx->info = control_msg_info; - - if (cmd_string_parse(line, &cmdlist, &cause) != 0) { + if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) { control_write(c, "%%error in line \"%s\": %s", line, cause); free(cause); } else { - cmd_list_exec(cmdlist, ctx); + cmdq_run(c->cmdq, cmdlist); cmd_list_free(cmdlist); } - cmd_free_ctx(ctx); free(line); } diff --git a/format.c b/format.c index 4c93c766..af2c128b 100644 --- a/format.c +++ b/format.c @@ -397,10 +397,8 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) struct grid *gd = wp->base.grid; struct grid_line *gl; unsigned long long size; - u_int i; - u_int idx; - const char *cwd; - const char *cmd; + u_int i, idx; + const char *cwd, *cmd; size = 0; for (i = 0; i < gd->hsize; i++) { diff --git a/key-bindings.c b/key-bindings.c index 0f944c4c..4e889b7e 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -182,11 +182,11 @@ key_bindings_init(void) RB_INIT(&key_bindings); for (i = 0; i < nitems(table); i++) { - cmdlist = xmalloc(sizeof *cmdlist); - TAILQ_INIT(&cmdlist->list); + cmdlist = xcalloc(1, sizeof *cmdlist); cmdlist->references = 1; + TAILQ_INIT(&cmdlist->list); - cmd = xmalloc(sizeof *cmd); + cmd = xcalloc(1, sizeof *cmd); cmd->entry = table[i].entry; if (cmd->entry->key_binding != NULL) cmd->entry->key_binding(cmd, table[i].key); @@ -199,88 +199,21 @@ key_bindings_init(void) } } -void printflike2 -key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) -{ - va_list ap; - char *msg; - - if (ctx->curclient->session == NULL) - return; - - va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); - va_end(ap); - - *msg = toupper((u_char) *msg); - status_message_set(ctx->curclient, "%s", msg); - free(msg); -} - -void printflike2 -key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...) -{ - struct winlink *wl; - va_list ap; - - if (ctx->curclient->session == NULL) - return; - - wl = ctx->curclient->session->curw; - if (wl->window->active->mode != &window_copy_mode) { - window_pane_reset_mode(wl->window->active); - window_pane_set_mode(wl->window->active, &window_copy_mode); - window_copy_init_for_output(wl->window->active); - } - - va_start(ap, fmt); - window_copy_vadd(wl->window->active, fmt, ap); - va_end(ap); -} - -void printflike2 -key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...) -{ - va_list ap; - char *msg; - - if (ctx->curclient->session == NULL) - return; - - if (options_get_number(&global_options, "quiet")) - return; - - va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); - va_end(ap); - - *msg = toupper((u_char) *msg); - status_message_set(ctx->curclient, "%s", msg); - free(msg); -} - void key_bindings_dispatch(struct key_binding *bd, struct client *c) { - struct cmd_ctx *ctx; struct cmd *cmd; int readonly; - ctx = cmd_get_ctx(NULL, c); - ctx->error = key_bindings_error; - ctx->print = key_bindings_print; - ctx->info = key_bindings_info; - readonly = 1; TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) { if (!(cmd->entry->flags & CMD_READONLY)) readonly = 0; } - if (!readonly && c->flags & CLIENT_READONLY) { - key_bindings_info(ctx, "client is read-only"); + if (!readonly && (c->flags & CLIENT_READONLY)) { + cmdq_info(c->cmdq, "client is read-only"); return; } - cmd_list_exec(bd->cmdlist, ctx); - cmd_free_ctx(ctx); + cmdq_run(c->cmdq, bd->cmdlist); } diff --git a/server-client.c b/server-client.c index ef4936fc..6f29000b 100644 --- a/server-client.c +++ b/server-client.c @@ -45,10 +45,6 @@ void server_client_msg_identify( struct client *, struct msg_identify_data *, int); void server_client_msg_shell(struct client *); -void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...); -void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...); -void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...); - /* Create a new client. */ void server_client_create(int fd) @@ -67,6 +63,9 @@ server_client_create(int fd) fatal("gettimeofday failed"); memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); + c->cmdq = cmdq_new(c); + c->cmdq->client_exit = 1; + c->stdin_data = evbuffer_new (); c->stdout_data = evbuffer_new (); c->stderr_data = evbuffer_new (); @@ -181,6 +180,10 @@ server_client_lost(struct client *c) free(c->prompt_buffer); free(c->cwd); + c->cmdq->dead = 1; + cmdq_free(c->cmdq); + c->cmdq = NULL; + environ_free(&c->environ); close(c->ibuf.fd); @@ -901,71 +904,18 @@ server_client_msg_dispatch(struct client *c) } } -/* Callback to send error message to client. */ -void printflike2 -server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - evbuffer_add_vprintf(ctx->cmdclient->stderr_data, fmt, ap); - va_end(ap); - - evbuffer_add(ctx->cmdclient->stderr_data, "\n", 1); - server_push_stderr(ctx->cmdclient); - ctx->cmdclient->retcode = 1; -} - -/* Callback to send print message to client. */ -void printflike2 -server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap); - va_end(ap); - - evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1); - server_push_stdout(ctx->cmdclient); -} - -/* Callback to send print message to client, if not quiet. */ -void printflike2 -server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) -{ - va_list ap; - - if (options_get_number(&global_options, "quiet")) - return; - - va_start(ap, fmt); - evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap); - va_end(ap); - - evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1); - server_push_stdout(ctx->cmdclient); -} - /* Handle command message. */ void server_client_msg_command(struct client *c, struct msg_command_data *data) { - struct cmd_ctx *ctx; struct cmd_list *cmdlist = NULL; int argc; char **argv, *cause; - ctx = cmd_get_ctx(c, NULL); - ctx->msgdata = data; - ctx->error = server_client_msg_error; - ctx->print = server_client_msg_print; - ctx->info = server_client_msg_info; - argc = data->argc; data->argv[(sizeof data->argv) - 1] = '\0'; if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { - server_client_msg_error(ctx, "command too long"); + cmdq_error(c->cmdq, "command too long"); goto error; } @@ -975,31 +925,20 @@ server_client_msg_command(struct client *c, struct msg_command_data *data) *argv = xstrdup("new-session"); } - if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { - server_client_msg_error(ctx, "%s", cause); + if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) { + cmdq_error(c->cmdq, "%s", cause); cmd_free_argv(argc, argv); goto error; } cmd_free_argv(argc, argv); - switch (cmd_list_exec(cmdlist, ctx)) - { - case CMD_RETURN_ERROR: - case CMD_RETURN_NORMAL: - c->flags |= CLIENT_EXIT; - break; - case CMD_RETURN_ATTACH: - case CMD_RETURN_YIELD: - break; - } + cmdq_run(c->cmdq, cmdlist); cmd_list_free(cmdlist); - cmd_free_ctx(ctx); return; error: if (cmdlist != NULL) cmd_list_free(cmdlist); - cmd_free_ctx(ctx); c->flags |= CLIENT_EXIT; } diff --git a/server-fn.c b/server-fn.c index 6d66a9f0..b9217ef2 100644 --- a/server-fn.c +++ b/server-fn.c @@ -194,7 +194,7 @@ server_status_window(struct window *w) /* * This is slightly different. We want to redraw the status line of any - * clients containing this window rather than any where it is the + * clients containing this window rather than anywhere it is the * current window. */ @@ -563,7 +563,7 @@ int server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int, void *), void *cb_data, char **cause) { - if (c == NULL) { + if (c == NULL || c->session != NULL) { *cause = xstrdup("no client with stdin"); return (-1); } diff --git a/server.c b/server.c index 994f3968..a07fa1fd 100644 --- a/server.c +++ b/server.c @@ -106,8 +106,9 @@ server_create_socket(void) int server_start(int lockfd, char *lockfile) { - int pair[2]; - struct timeval tv; + int pair[2]; + struct timeval tv; + char *cause; /* The first client is special and gets a socketpair; create it. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) @@ -162,23 +163,28 @@ server_start(int lockfd, char *lockfile) free(lockfile); close(lockfd); - if (access(SYSTEM_CFG, R_OK) == 0) - load_cfg(SYSTEM_CFG, NULL, &cfg_causes); - else if (errno != ENOENT) { - cfg_add_cause( - &cfg_causes, "%s: %s", SYSTEM_CFG, strerror(errno)); + cfg_cmd_q = cmdq_new(NULL); + cfg_cmd_q->emptyfn = cfg_default_done; + cfg_finished = 0; + cfg_references = 1; + ARRAY_INIT(&cfg_causes); + + if (access(SYSTEM_CFG, R_OK) == 0) { + if (load_cfg(SYSTEM_CFG, cfg_cmd_q, &cause) == -1) { + xasprintf(&cause, "%s: %s", SYSTEM_CFG, cause); + ARRAY_ADD(&cfg_causes, cause); + } + } else if (errno != ENOENT) { + xasprintf(&cause, "%s: %s", SYSTEM_CFG, strerror(errno)); + ARRAY_ADD(&cfg_causes, cause); } - if (cfg_file != NULL) - load_cfg(cfg_file, NULL, &cfg_causes); - - /* - * If there is a session already, put the current window and pane into - * more mode. - */ - if (!RB_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) - show_cfg_causes(RB_MIN(sessions, &sessions)); - - cfg_finished = 1; + if (cfg_file != NULL) { + if (load_cfg(cfg_file, cfg_cmd_q, &cause) == -1) { + xasprintf(&cause, "%s: %s", cfg_file, cause); + ARRAY_ADD(&cfg_causes, cause); + } + } + cmdq_continue(cfg_cmd_q); server_add_accept(0); diff --git a/tmux.c b/tmux.c index 2428a404..7bce10ec 100644 --- a/tmux.c +++ b/tmux.c @@ -330,8 +330,6 @@ main(int argc, char **argv) options_init(&global_w_options, NULL); options_table_populate_tree(window_options_table, &global_w_options); - ARRAY_INIT(&cfg_causes); - /* Enable UTF-8 if the first client is on UTF-8 terminal. */ if (flags & IDENTIFY_UTF8) { options_set_number(&global_s_options, "status-utf8", 1); diff --git a/tmux.h b/tmux.h index b71df280..2674a178 100644 --- a/tmux.h +++ b/tmux.h @@ -432,6 +432,9 @@ struct tty_term_code_entry { const char *name; }; +/* List of error causes. */ +ARRAY_DECL(causelist, char *); + /* Message codes. */ enum msgtype { MSG_COMMAND, @@ -777,6 +780,9 @@ struct job { int fd; struct bufferevent *event; + struct bufferevent *out; + int outdone; + void (*callbackfn)(struct job *); void (*freefn)(void *); void *data; @@ -1350,6 +1356,7 @@ struct client { int wlmouse; + struct cmd_q *cmdq; int references; }; ARRAY_DECL(clients, struct client *); @@ -1363,41 +1370,14 @@ struct args { char **argv; }; -/* Key/command line command. */ -struct cmd_ctx { - /* - * curclient is the client where this command was executed if inside - * tmux. This is NULL if the command came from the command-line. - * - * cmdclient is the client which sent the MSG_COMMAND to the server, if - * any. This is NULL unless the command came from the command-line. - * - * cmdclient and curclient may both be NULL if the command is in the - * configuration file. - */ - struct client *curclient; - struct client *cmdclient; - - int references; - - struct msg_command_data *msgdata; - - /* gcc2 doesn't understand attributes on function pointers... */ -#if defined(__GNUC__) && __GNUC__ >= 3 - void printflike2 (*print)(struct cmd_ctx *, const char *, ...); - void printflike2 (*info)(struct cmd_ctx *, const char *, ...); - void printflike2 (*error)(struct cmd_ctx *, const char *, ...); -#else - void (*print)(struct cmd_ctx *, const char *, ...); - void (*info)(struct cmd_ctx *, const char *, ...); - void (*error)(struct cmd_ctx *, const char *, ...); -#endif -}; - +/* Command and list of commands. */ struct cmd { const struct cmd_entry *entry; struct args *args; + char *file; + u_int line; + TAILQ_ENTRY(cmd) qentry; }; struct cmd_list { @@ -1405,13 +1385,40 @@ struct cmd_list { TAILQ_HEAD(, cmd) list; }; +/* Command return values. */ enum cmd_retval { CMD_RETURN_ERROR = -1, CMD_RETURN_NORMAL = 0, - CMD_RETURN_YIELD, - CMD_RETURN_ATTACH + CMD_RETURN_WAIT, + CMD_RETURN_STOP }; +/* Command queue entry. */ +struct cmd_q_item { + struct cmd_list *cmdlist; + TAILQ_ENTRY(cmd_q_item) qentry; +}; +TAILQ_HEAD(cmd_q_items, cmd_q_item); + +/* Command queue. */ +struct cmd_q { + int references; + int dead; + + struct client *client; + int client_exit; + + struct cmd_q_items queue; + struct cmd_q_item *item; + struct cmd *cmd; + + void (*emptyfn)(struct cmd_q *); + void *data; + + struct msg_command_data *msgdata; +}; + +/* Command definition. */ struct cmd_entry { const char *name; const char *alias; @@ -1430,7 +1437,7 @@ struct cmd_entry { void (*key_binding)(struct cmd *, int); int (*check)(struct args *); - enum cmd_retval (*exec)(struct cmd *, struct cmd_ctx *); + enum cmd_retval (*exec)(struct cmd *, struct cmd_q *); }; /* Key binding. */ @@ -1479,9 +1486,6 @@ struct format_entry { }; RB_HEAD(format_tree, format_entry); -/* List of configuration causes. */ -ARRAY_DECL(causelist, char *); - /* Common command usages. */ #define CMD_TARGET_PANE_USAGE "[-t target-pane]" #define CMD_TARGET_WINDOW_USAGE "[-t target-window]" @@ -1517,12 +1521,13 @@ void setblocking(int, int); __dead void shell_exec(const char *, const char *); /* cfg.c */ -extern int cfg_finished; -extern int cfg_references; +extern struct cmd_q *cfg_cmd_q; +extern int cfg_finished; +extern int cfg_references; extern struct causelist cfg_causes; -void printflike2 cfg_add_cause(struct causelist *, const char *, ...); -enum cmd_retval load_cfg(const char *, struct cmd_ctx *, struct causelist *); -void show_cfg_causes(struct session *); +int load_cfg(const char *, struct cmd_q *, char **); +void cfg_default_done(struct cmd_q *); +void cfg_show_causes(struct session *); /* format.c */ int format_cmp(struct format_entry *, struct format_entry *); @@ -1725,27 +1730,24 @@ long long args_strtonum( struct args *, u_char, long long, long long, char **); /* cmd.c */ -struct cmd_ctx *cmd_get_ctx(struct client *, struct client *); -void cmd_free_ctx(struct cmd_ctx *); -void cmd_ref_ctx(struct cmd_ctx *); int cmd_pack_argv(int, char **, char *, size_t); int cmd_unpack_argv(char *, size_t, int, char ***); char **cmd_copy_argv(int, char *const *); void cmd_free_argv(int, char **); -struct cmd *cmd_parse(int, char **, char **); +struct cmd *cmd_parse(int, char **, const char *, u_int, char **); size_t cmd_print(struct cmd *, char *, size_t); -struct session *cmd_current_session(struct cmd_ctx *, int); -struct client *cmd_current_client(struct cmd_ctx *); -struct client *cmd_find_client(struct cmd_ctx *, const char *, int); -struct session *cmd_find_session(struct cmd_ctx *, const char *, int); -struct winlink *cmd_find_window( - struct cmd_ctx *, const char *, struct session **); -int cmd_find_index( - struct cmd_ctx *, const char *, struct session **); -struct winlink *cmd_find_pane(struct cmd_ctx *, - const char *, struct session **, struct window_pane **); +struct session *cmd_current_session(struct cmd_q *, int); +struct client *cmd_current_client(struct cmd_q *); +struct client *cmd_find_client(struct cmd_q *, const char *, int); +struct session *cmd_find_session(struct cmd_q *, const char *, int); +struct winlink *cmd_find_window(struct cmd_q *, const char *, + struct session **); +int cmd_find_index(struct cmd_q *, const char *, + struct session **); +struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **, + struct window_pane **); char *cmd_template_replace(const char *, const char *, int); -const char *cmd_get_default_path(struct cmd_ctx *, const char *); +const char *cmd_get_default_path(struct cmd_q *, const char *); extern const struct cmd_entry *cmd_table[]; extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_bind_key_entry; @@ -1835,13 +1837,24 @@ extern const struct cmd_entry cmd_unlink_window_entry; extern const struct cmd_entry cmd_up_pane_entry; /* cmd-list.c */ -struct cmd_list *cmd_list_parse(int, char **, char **); -enum cmd_retval cmd_list_exec(struct cmd_list *, struct cmd_ctx *); +struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **); void cmd_list_free(struct cmd_list *); size_t cmd_list_print(struct cmd_list *, char *, size_t); +/* cmd-queue.c */ +struct cmd_q *cmdq_new(struct client *); +int cmdq_free(struct cmd_q *); +void printflike2 cmdq_print(struct cmd_q *, const char *, ...); +void printflike2 cmdq_info(struct cmd_q *, const char *, ...); +void printflike2 cmdq_error(struct cmd_q *, const char *, ...); +void cmdq_run(struct cmd_q *, struct cmd_list *); +void cmdq_append(struct cmd_q *, struct cmd_list *); +int cmdq_continue(struct cmd_q *); +void cmdq_flush(struct cmd_q *); + /* cmd-string.c */ -int cmd_string_parse(const char *, struct cmd_list **, char **); +int cmd_string_parse(const char *, struct cmd_list **, const char *, + u_int, char **); /* client.c */ int client_main(int, char **, int); @@ -1856,9 +1869,6 @@ void key_bindings_remove(int); void key_bindings_clean(void); void key_bindings_init(void); void key_bindings_dispatch(struct key_binding *, struct client *); -void printflike2 key_bindings_error(struct cmd_ctx *, const char *, ...); -void printflike2 key_bindings_print(struct cmd_ctx *, const char *, ...); -void printflike2 key_bindings_info(struct cmd_ctx *, const char *, ...); /* key-string.c */ int key_string_lookup_string(const char *); diff --git a/window-choose.c b/window-choose.c index 4443e1a5..2671c781 100644 --- a/window-choose.c +++ b/window-choose.c @@ -200,9 +200,8 @@ window_choose_data_free(struct window_choose_data *wcd) void window_choose_data_run(struct window_choose_data *cdata) { - struct cmd_ctx *ctx; - struct cmd_list *cmdlist; - char *cause; + struct cmd_list *cmdlist; + char *cause; /* * The command template will have already been replaced. But if it's @@ -211,7 +210,7 @@ window_choose_data_run(struct window_choose_data *cdata) if (cdata->command == NULL) return; - if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) { + if (cmd_string_parse(cdata->command, &cmdlist, NULL, 0, &cause) != 0) { if (cause != NULL) { *cause = toupper((u_char) *cause); status_message_set(cdata->start_client, "%s", cause); @@ -220,14 +219,8 @@ window_choose_data_run(struct window_choose_data *cdata) return; } - ctx = cmd_get_ctx(NULL, cdata->start_client); - ctx->error = key_bindings_error; - ctx->print = key_bindings_print; - ctx->info = key_bindings_info; - - cmd_list_exec(cmdlist, ctx); + cmdq_run(cdata->start_client->cmdq, cmdlist); cmd_list_free(cmdlist); - cmd_free_ctx(ctx); } void From a05b8c41437409f83cb1df2adc0998791d7a2038 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:55:02 +0000 Subject: [PATCH 58/91] Add a -o option to set-option to prevent setting an option already set, from Thiago Padilha. --- cmd-set-option.c | 139 ++++++++++++++++++++++++++--------------------- tmux.1 | 15 ++++- 2 files changed, 90 insertions(+), 64 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index 55b2c929..6c0fefbf 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -27,44 +27,44 @@ * Set an option. */ -enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_q *); -enum cmd_retval cmd_set_option_user(struct cmd *, struct cmd_ctx *, - const char *, const char *); +enum cmd_retval cmd_set_option_user(struct cmd *, struct cmd_q *, + const char *, const char *); -int cmd_set_option_unset(struct cmd *, struct cmd_ctx *, +int cmd_set_option_unset(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); -int cmd_set_option_set(struct cmd *, struct cmd_ctx *, +int cmd_set_option_set(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); -struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *, +struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); -struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *, +struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); -struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_ctx *, +struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); -struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *, +struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); -struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_ctx *, +struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); -struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_ctx *, +struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); -struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *, +struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", - "agqst:uw", 1, 2, - "[-agsquw] [-t target-session|target-window] option [value]", + "agoqst:uw", 1, 2, + "[-agosquw] [-t target-session|target-window] option [value]", 0, NULL, NULL, @@ -73,8 +73,8 @@ const struct cmd_entry cmd_set_option_entry = { const struct cmd_entry cmd_set_window_option_entry = { "set-window-option", "setw", - "agqt:u", 1, 2, - "[-agqu] " CMD_TARGET_WINDOW_USAGE " option [value]", + "agoqt:u", 1, 2, + "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", 0, NULL, NULL, @@ -82,7 +82,7 @@ const struct cmd_entry cmd_set_window_option_entry = { }; enum cmd_retval -cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; const struct options_table_entry *table, *oe; @@ -97,7 +97,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) /* Get the option name and value. */ optstr = args->argv[0]; if (*optstr == '\0') { - ctx->error(ctx, "invalid option"); + cmdq_error(cmdq, "invalid option"); return (CMD_RETURN_ERROR); } if (args->argc < 2) @@ -107,16 +107,16 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) /* Is this a user option? */ if (*optstr == '@') - return (cmd_set_option_user(self, ctx, optstr, valstr)); + return (cmd_set_option_user(self, cmdq, optstr, valstr)); /* Find the option entry, try each table. */ table = oe = NULL; if (options_table_find(optstr, &table, &oe) != 0) { - ctx->error(ctx, "ambiguous option: %s", optstr); + cmdq_error(cmdq, "ambiguous option: %s", optstr); return (CMD_RETURN_ERROR); } if (oe == NULL) { - ctx->error(ctx, "unknown option: %s", optstr); + cmdq_error(cmdq, "unknown option: %s", optstr); return (CMD_RETURN_ERROR); } @@ -127,7 +127,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) oo = &global_w_options; else { - wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); if (wl == NULL) return (CMD_RETURN_ERROR); oo = &wl->window->options; @@ -136,22 +136,27 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'g')) oo = &global_s_options; else { - s = cmd_find_session(ctx, args_get(args, 't'), 0); + s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); oo = &s->options; } } else { - ctx->error(ctx, "unknown table"); + cmdq_error(cmdq, "unknown table"); return (CMD_RETURN_ERROR); } /* Unset or set the option. */ if (args_has(args, 'u')) { - if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0) + if (cmd_set_option_unset(self, cmdq, oe, oo, valstr) != 0) return (CMD_RETURN_ERROR); } else { - if (cmd_set_option_set(self, ctx, oe, oo, valstr) != 0) + if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) { + if (!args_has(args, 'q')) + cmdq_print(cmdq, "already set: %s", optstr); + return (CMD_RETURN_NORMAL); + } + if (cmd_set_option_set(self, cmdq, oe, oo, valstr) != 0) return (CMD_RETURN_ERROR); } @@ -180,7 +185,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx) /* Set user option. */ enum cmd_retval -cmd_set_option_user(struct cmd *self, struct cmd_ctx *ctx, const char* optstr, +cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char* optstr, const char *valstr) { struct args *args = self->args; @@ -195,7 +200,7 @@ cmd_set_option_user(struct cmd *self, struct cmd_ctx *ctx, const char* optstr, if (args_has(self->args, 'g')) oo = &global_w_options; else { - wl = cmd_find_window(ctx, args_get(args, 't'), NULL); + wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); if (wl == NULL) return (CMD_RETURN_ERROR); oo = &wl->window->options; @@ -204,7 +209,7 @@ cmd_set_option_user(struct cmd *self, struct cmd_ctx *ctx, const char* optstr, if (args_has(self->args, 'g')) oo = &global_s_options; else { - s = cmd_find_session(ctx, args_get(args, 't'), 0); + s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); oo = &s->options; @@ -213,23 +218,30 @@ cmd_set_option_user(struct cmd *self, struct cmd_ctx *ctx, const char* optstr, if (args_has(args, 'u')) { if (options_find1(oo, optstr) == NULL) { - ctx->error(ctx, "unknown option: %s", optstr); + cmdq_error(cmdq, "unknown option: %s", optstr); return (CMD_RETURN_ERROR); } if (valstr != NULL) { - ctx->error(ctx, "value passed to unset option: %s", + cmdq_error(cmdq, "value passed to unset option: %s", optstr); return (CMD_RETURN_ERROR); } options_remove(oo, optstr); } else { if (valstr == NULL) { - ctx->error(ctx, "empty value"); + cmdq_error(cmdq, "empty value"); return (CMD_RETURN_ERROR); } + if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) { + if (!args_has(args, 'q')) + cmdq_print(cmdq, "already set: %s", optstr); + return (CMD_RETURN_NORMAL); + } options_set_string(oo, optstr, "%s", valstr); - if (!args_has(args, 'q')) - ctx->info(ctx, "set option: %s -> %s", optstr, valstr); + if (!args_has(args, 'q')) { + cmdq_info(cmdq, "set option: %s -> %s", optstr, + valstr); + } } return (CMD_RETURN_NORMAL); } @@ -237,29 +249,29 @@ cmd_set_option_user(struct cmd *self, struct cmd_ctx *ctx, const char* optstr, /* Unset an option. */ int -cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx, +cmd_set_option_unset(struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { struct args *args = self->args; if (args_has(args, 'g')) { - ctx->error(ctx, "can't unset global option: %s", oe->name); + cmdq_error(cmdq, "can't unset global option: %s", oe->name); return (-1); } if (value != NULL) { - ctx->error(ctx, "value passed to unset option: %s", oe->name); + cmdq_error(cmdq, "value passed to unset option: %s", oe->name); return (-1); } options_remove(oo, oe->name); if (!args_has(args, 'q')) - ctx->info(ctx, "unset option: %s", oe->name); + cmdq_info(cmdq, "unset option: %s", oe->name); return (0); } /* Set an option. */ int -cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, +cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { struct args *args = self->args; @@ -267,32 +279,32 @@ cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, const char *s; if (oe->type != OPTIONS_TABLE_FLAG && value == NULL) { - ctx->error(ctx, "empty value"); + cmdq_error(cmdq, "empty value"); return (-1); } o = NULL; switch (oe->type) { case OPTIONS_TABLE_STRING: - o = cmd_set_option_string(self, ctx, oe, oo, value); + o = cmd_set_option_string(self, cmdq, oe, oo, value); break; case OPTIONS_TABLE_NUMBER: - o = cmd_set_option_number(self, ctx, oe, oo, value); + o = cmd_set_option_number(self, cmdq, oe, oo, value); break; case OPTIONS_TABLE_KEY: - o = cmd_set_option_key(self, ctx, oe, oo, value); + o = cmd_set_option_key(self, cmdq, oe, oo, value); break; case OPTIONS_TABLE_COLOUR: - o = cmd_set_option_colour(self, ctx, oe, oo, value); + o = cmd_set_option_colour(self, cmdq, oe, oo, value); break; case OPTIONS_TABLE_ATTRIBUTES: - o = cmd_set_option_attributes(self, ctx, oe, oo, value); + o = cmd_set_option_attributes(self, cmdq, oe, oo, value); break; case OPTIONS_TABLE_FLAG: - o = cmd_set_option_flag(self, ctx, oe, oo, value); + o = cmd_set_option_flag(self, cmdq, oe, oo, value); break; case OPTIONS_TABLE_CHOICE: - o = cmd_set_option_choice(self, ctx, oe, oo, value); + o = cmd_set_option_choice(self, cmdq, oe, oo, value); break; } if (o == NULL) @@ -300,13 +312,13 @@ cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx, s = options_table_print_entry(oe, o, 0); if (!args_has(args, 'q')) - ctx->info(ctx, "set option: %s -> %s", oe->name, s); + cmdq_info(cmdq, "set option: %s -> %s", oe->name, s); return (0); } /* Set a string option. */ struct options_entry * -cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx, +cmd_set_option_string(struct cmd *self, unused struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { struct args *args = self->args; @@ -327,7 +339,7 @@ cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx, /* Set a number option. */ struct options_entry * -cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx, +cmd_set_option_number(unused struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { long long ll; @@ -335,7 +347,7 @@ cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx, ll = strtonum(value, oe->minimum, oe->maximum, &errstr); if (errstr != NULL) { - ctx->error(ctx, "value is %s: %s", errstr, value); + cmdq_error(cmdq, "value is %s: %s", errstr, value); return (NULL); } @@ -344,13 +356,13 @@ cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx, /* Set a key option. */ struct options_entry * -cmd_set_option_key(unused struct cmd *self, struct cmd_ctx *ctx, +cmd_set_option_key(unused struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { int key; if ((key = key_string_lookup_string(value)) == KEYC_NONE) { - ctx->error(ctx, "bad key: %s", value); + cmdq_error(cmdq, "bad key: %s", value); return (NULL); } @@ -359,13 +371,13 @@ cmd_set_option_key(unused struct cmd *self, struct cmd_ctx *ctx, /* Set a colour option. */ struct options_entry * -cmd_set_option_colour(unused struct cmd *self, struct cmd_ctx *ctx, +cmd_set_option_colour(unused struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { int colour; if ((colour = colour_fromstring(value)) == -1) { - ctx->error(ctx, "bad colour: %s", value); + cmdq_error(cmdq, "bad colour: %s", value); return (NULL); } @@ -374,13 +386,13 @@ cmd_set_option_colour(unused struct cmd *self, struct cmd_ctx *ctx, /* Set an attributes option. */ struct options_entry * -cmd_set_option_attributes(unused struct cmd *self, struct cmd_ctx *ctx, +cmd_set_option_attributes(unused struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { int attr; if ((attr = attributes_fromstring(value)) == -1) { - ctx->error(ctx, "bad attributes: %s", value); + cmdq_error(cmdq, "bad attributes: %s", value); return (NULL); } @@ -389,7 +401,7 @@ cmd_set_option_attributes(unused struct cmd *self, struct cmd_ctx *ctx, /* Set a flag option. */ struct options_entry * -cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx, +cmd_set_option_flag(unused struct cmd *self, struct cmd_q *cmdq, const struct options_table_entry *oe, struct options *oo, const char *value) { int flag; @@ -406,7 +418,7 @@ cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx, strcasecmp(value, "no") == 0) flag = 0; else { - ctx->error(ctx, "bad value: %s", value); + cmdq_error(cmdq, "bad value: %s", value); return (NULL); } } @@ -416,8 +428,9 @@ cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx, /* Set a choice option. */ struct options_entry * -cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx, - const struct options_table_entry *oe, struct options *oo, const char *value) +cmd_set_option_choice(unused struct cmd *self, struct cmd_q *cmdq, + const struct options_table_entry *oe, struct options *oo, + const char *value) { const char **choicep; int n, choice = -1; @@ -429,13 +442,13 @@ cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx, continue; if (choice != -1) { - ctx->error(ctx, "ambiguous value: %s", value); + cmdq_error(cmdq, "ambiguous value: %s", value); return (NULL); } choice = n - 1; } if (choice == -1) { - ctx->error(ctx, "unknown value: %s", value); + cmdq_error(cmdq, "unknown value: %s", value); return (NULL); } diff --git a/tmux.1 b/tmux.1 index d708aace..33902d1b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1992,7 +1992,7 @@ abc123 Commands which set options are as follows: .Bl -tag -width Ds .It Xo Ic set-option -.Op Fl agqsuw +.Op Fl agoqsuw .Op Fl t Ar target-session | Ar target-window .Ar option Ar value .Xc @@ -2021,6 +2021,10 @@ options. It is not possible to unset a global option. .Pp The +.Fl o +flag prevents setting an option that is already set. +.Pp +The .Fl q flag suppresses the informational message (as if the .Ic quiet @@ -3466,6 +3470,7 @@ Miscellaneous commands are as follows: Display a large clock. .It Xo Ic if-shell .Op Fl t Ar target-pane +.Op Fl b .Ar shell-command command .Op Ar command .Xc @@ -3481,12 +3486,17 @@ Before being executed, shell-command is expanded using the rules specified in th .Sx FORMATS section, including those relevant to .Ar target-pane . +With +.Fl b , +.Ar shell-command +is run in the background. .It Ic lock-server .D1 (alias: Ic lock ) Lock each client individually by running the command specified by the .Ic lock-command option. .It Xo Ic run-shell +.Fl b .Op Fl t Ar target-pane .Ar shell-command .Xc @@ -3498,6 +3508,9 @@ Before being executed, shell-command is expanded using the rules specified in the .Sx FORMATS section. +With +.Fl b , +the command is run in the background. After it finishes, any output to stdout is displayed in copy mode (in the pane specified by .Fl t From c71844de631186f3df7ff5a6e3aab613da1e4853 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:57:59 +0000 Subject: [PATCH 59/91] Add resize-pane -Z to temporary zoom the active pane to occupy the full window or unzoom (restored to the normal layout) if it already zoomed, bound to C-b z by default. The pane is unzoomed on pretty much any excuse whatsoever. We considered making this a new layout but the requirements are quite different from layouts so decided it is better as a special case. Each current layout cell is saved, a temporary one-cell layout generated and all except the active pane set to NULL. Prompted by suggestions and scripts from several. Thanks to Aaron Jensen and Thiago Padilha for testing an earlier version. --- cmd-break-pane.c | 4 +++- cmd-join-pane.c | 2 ++ cmd-kill-pane.c | 1 + cmd-resize-pane.c | 21 +++++++++++++++-- cmd-respawn-window.c | 2 +- cmd-select-layout.c | 1 + cmd-select-pane.c | 2 ++ cmd-split-window.c | 1 + cmd-swap-pane.c | 2 ++ input-keys.c | 3 ++- key-bindings.c | 1 + layout.c | 4 ++-- resize.c | 8 +++++-- server-client.c | 1 + server-fn.c | 9 +++++++ window.c | 56 +++++++++++++++++++++++++++++++++++++++++++- 16 files changed, 108 insertions(+), 10 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 27ae1624..bac332a2 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -63,6 +63,8 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq) } w = wl->window; + server_unzoom_window(w); + TAILQ_REMOVE(&w->panes, wp, entry); if (wp == w->active) { w->active = w->last; @@ -82,7 +84,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq) name = default_window_name(w); window_set_name(w, name); free(name); - layout_init(w); + layout_init(w, wp); base_idx = options_get_number(&s->options, "base-index"); wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */ diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 2e7a59cd..cf17e7d9 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -92,11 +92,13 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window) return (CMD_RETURN_ERROR); dst_w = dst_wl->window; dst_idx = dst_wl->idx; + server_unzoom_window(dst_w); src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp); if (src_wl == NULL) return (CMD_RETURN_ERROR); src_w = src_wl->window; + server_unzoom_window(src_w); if (not_same_window && src_w == dst_w) { cmdq_error(cmdq, "can't join a pane to its own window"); diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index 1aa776d9..ba3bfd20 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -47,6 +47,7 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_q *cmdq) if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); + server_unzoom_window(wl->window); if (window_count_panes(wl->window) == 1) { /* Only one pane, kill the window. */ diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index f31e3258..41c15269 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_resize_pane_entry = { "resize-pane", "resizep", - "DLRt:Ux:y:", 0, 1, - "[-DLRU] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]", + "DLRt:Ux:y:Z", 0, 1, + "[-DLRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]", 0, cmd_resize_pane_key_binding, NULL, @@ -75,6 +75,10 @@ cmd_resize_pane_key_binding(struct cmd *self, int key) self->args = args_create(1, "5"); args_set(self->args, 'R', NULL); break; + case 'z': + self->args = args_create(0); + args_set(self->args, 'Z', NULL); + break; default: self->args = args_create(0); break; @@ -86,6 +90,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; + struct window *w; const char *errstr; char *cause; struct window_pane *wp; @@ -94,6 +99,18 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); + w = wl->window; + + if (args_has(args, 'Z')) { + if (w->flags & WINDOW_ZOOMED) + window_unzoom(w); + else + window_zoom(wp); + server_redraw_window(w); + server_status_window(w); + return (CMD_RETURN_NORMAL); + } + server_unzoom_window(w); if (args->argc == 0) adjust = 1; diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 646882b0..a446794b 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -87,7 +87,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) server_destroy_pane(wp); return (CMD_RETURN_ERROR); } - layout_init(w); + layout_init(w, wp); window_pane_reset_mode(wp); screen_reinit(&wp->base); input_init(wp); diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 4b01a69d..aa73e500 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -92,6 +92,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq) if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); + server_unzoom_window(wl->window); next = self->entry == &cmd_next_layout_entry; if (args_has(self->args, 'n')) diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 459e98cf..77be368f 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -80,6 +80,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } + server_unzoom_window(wl->window); window_set_active_pane(wl->window, wl->window->last); server_status_window(wl->window); server_redraw_window_borders(wl->window); @@ -90,6 +91,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq) if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL) return (CMD_RETURN_ERROR); + server_unzoom_window(wp->window); if (!window_pane_visible(wp)) { cmdq_error(cmdq, "pane not visible"); return (CMD_RETURN_ERROR); diff --git a/cmd-split-window.c b/cmd-split-window.c index 87c0e6bc..e3d6f6ea 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -73,6 +73,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) return (CMD_RETURN_ERROR); w = wl->window; + server_unzoom_window(w); environ_init(&env); environ_copy(&global_environ, &env); diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index ae875946..e7ea6242 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -63,6 +63,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq) if (dst_wl == NULL) return (CMD_RETURN_ERROR); dst_w = dst_wl->window; + server_unzoom_window(dst_w); if (!args_has(args, 's')) { src_w = dst_w; @@ -82,6 +83,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); src_w = src_wl->window; } + server_unzoom_window(src_w); if (src_wp == dst_wp) return (CMD_RETURN_NORMAL); diff --git a/input-keys.c b/input-keys.c index 23549e32..d7e8513d 100644 --- a/input-keys.c +++ b/input-keys.c @@ -219,7 +219,8 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m) */ if (m->sgr && (wp->screen->mode & MODE_MOUSE_SGR)) { len = xsnprintf(buf, sizeof buf, "\033[<%d;%d;%d%c", - m->sgr_xb, m->x + 1, m->y + 1, m->sgr_rel ? 'm' : 'M'); + m->sgr_xb, m->x + 1, m->y + 1, + m->sgr_rel ? 'm' : 'M'); } else if (wp->screen->mode & MODE_MOUSE_UTF8) { len = xsnprintf(buf, sizeof buf, "\033[M"); len += utf8_split2(m->xb + 32, &buf[len]); diff --git a/key-bindings.c b/key-bindings.c index 4e889b7e..625ffddf 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -150,6 +150,7 @@ key_bindings_init(void) { 't', 0, &cmd_clock_mode_entry }, { 'w', 0, &cmd_choose_window_entry }, { 'x', 0, &cmd_confirm_before_entry }, + { 'z', 0, &cmd_resize_pane_entry }, { '{', 0, &cmd_swap_pane_entry }, { '}', 0, &cmd_swap_pane_entry }, { '~', 0, &cmd_show_messages_entry }, diff --git a/layout.c b/layout.c index f08580b7..4dd3756c 100644 --- a/layout.c +++ b/layout.c @@ -374,13 +374,13 @@ layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot) } void -layout_init(struct window *w) +layout_init(struct window *w, struct window_pane *wp) { struct layout_cell *lc; lc = w->layout_root = layout_create_cell(NULL); layout_set_size(lc, w->sx, w->sy, 0, 0); - layout_make_leaf(lc, TAILQ_FIRST(&w->panes)); + layout_make_leaf(lc, wp); layout_fix_panes(w, w->sx, w->sy); } diff --git a/resize.c b/resize.c index d398ab37..b5196c1c 100644 --- a/resize.c +++ b/resize.c @@ -50,7 +50,7 @@ recalculate_sizes(void) struct window *w; struct window_pane *wp; u_int i, j, ssx, ssy, has, limit; - int flag, has_status; + int flag, has_status, is_zoomed; RB_FOREACH(s, sessions, &sessions) { has_status = options_get_number(&s->options, "status"); @@ -123,12 +123,16 @@ recalculate_sizes(void) if (w->sx == ssx && w->sy == ssy) continue; - log_debug("window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy); + is_zoomed = w->flags & WINDOW_ZOOMED; + if (is_zoomed) + window_unzoom(w); layout_resize(w, ssx, ssy); window_resize(w, ssx, ssy); + if (is_zoomed && window_pane_visible(w->active)) + window_zoom(w->active); /* * If the current pane is now not visible, move to the next diff --git a/server-client.c b/server-client.c index 6f29000b..64af442a 100644 --- a/server-client.c +++ b/server-client.c @@ -384,6 +384,7 @@ server_client_handle_key(struct client *c, int key) if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { if (c->flags & CLIENT_READONLY) return; + window_unzoom(w); wp = window_pane_at_index(w, key - '0'); if (wp != NULL && window_pane_visible(wp)) window_set_active_pane(w, wp); diff --git a/server-fn.c b/server-fn.c index b9217ef2..874afffb 100644 --- a/server-fn.c +++ b/server-fn.c @@ -377,6 +377,7 @@ server_destroy_pane(struct window_pane *wp) return; } + server_unzoom_window(w); layout_close_pane(wp); window_remove_pane(w, wp); @@ -588,3 +589,11 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int, return (0); } + +void +server_unzoom_window(struct window *w) +{ + window_unzoom(w); + server_redraw_window(w); + server_status_window(w); +} diff --git a/window.c b/window.c index dfece2ee..38af88f9 100644 --- a/window.c +++ b/window.c @@ -319,7 +319,7 @@ window_create(const char *name, const char *cmd, const char *shell, w = window_create1(sx, sy); wp = window_add_pane(w, hlimit); - layout_init(w); + layout_init(w, wp); if (*cmd != '\0') { prefix = options_get_string(&w->options, "command-prefix"); @@ -348,6 +348,8 @@ window_destroy(struct window *w) { u_int i; + window_unzoom(w); + if (window_index(w, &i) != 0) fatalx("index not found"); ARRAY_SET(&windows, i, NULL); @@ -470,6 +472,54 @@ window_find_string(struct window *w, const char *s) return (window_get_active_at(w, x, y)); } +int +window_zoom(struct window_pane *wp) +{ + struct window *w = wp->window; + struct window_pane *wp1; + + if (w->flags & WINDOW_ZOOMED) + return (-1); + + if (!window_pane_visible(wp)) + return (-1); + if (w->active != wp) + window_set_active_pane(w, wp); + + TAILQ_FOREACH(wp1, &w->panes, entry) { + wp1->saved_layout_cell = wp1->layout_cell; + wp1->layout_cell = NULL; + } + + w->saved_layout_root = w->layout_root; + layout_init(w, wp); + w->flags |= WINDOW_ZOOMED; + + return (0); +} + +int +window_unzoom(struct window *w) +{ + struct window_pane *wp, *wp1; + + if (!(w->flags & WINDOW_ZOOMED)) + return (-1); + wp = w->active; + + w->flags &= ~WINDOW_ZOOMED; + layout_free(w); + w->layout_root = w->saved_layout_root; + + TAILQ_FOREACH(wp1, &w->panes, entry) { + wp1->layout_cell = wp1->saved_layout_cell; + wp1->saved_layout_cell = NULL; + } + layout_fix_panes(w, w->sx, w->sy); + + return (0); +} + struct window_pane * window_add_pane(struct window *w, u_int hlimit) { @@ -600,6 +650,8 @@ window_printable_flags(struct session *s, struct winlink *wl) flags[pos++] = '*'; if (wl == TAILQ_FIRST(&s->lastw)) flags[pos++] = '-'; + if (wl->window->flags & WINDOW_ZOOMED) + flags[pos++] = 'Z'; if (pos == 0) flags[pos++] = ' '; flags[pos] = '\0'; @@ -1027,6 +1079,8 @@ window_pane_visible(struct window_pane *wp) { struct window *w = wp->window; + if (wp->layout_cell == NULL) + return (0); if (wp->xoff >= w->sx || wp->yoff >= w->sy) return (0); if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy) From 14fad6a5ccd6d5f2b9e372975e0062219853f891 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 24 Mar 2013 09:58:40 +0000 Subject: [PATCH 60/91] Add -A flag to new-session to make it behave like attach-session if the session exists. If -A is used, -D behaves like -d to attach-session. --- cmd-attach-session.c | 20 ++++++++++++++------ cmd-new-session.c | 8 ++++++-- tmux.1 | 24 ++++++++++++++++++++++-- tmux.h | 12 +++++++++++- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 0298dda1..f5f2778d 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -39,9 +39,8 @@ const struct cmd_entry cmd_attach_session_entry = { }; enum cmd_retval -cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) +cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) { - struct args *args = self->args; struct session *s; struct client *c; const char *update; @@ -53,14 +52,14 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } - if ((s = cmd_find_session(cmdq, args_get(args, 't'), 1)) == NULL) + if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) return (CMD_RETURN_ERROR); if (cmdq->client == NULL) return (CMD_RETURN_NORMAL); if (cmdq->client->session != NULL) { - if (args_has(self->args, 'd')) { + if (dflag) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. @@ -87,10 +86,10 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } - if (args_has(self->args, 'r')) + if (rflag) cmdq->client->flags |= CLIENT_READONLY; - if (args_has(self->args, 'd')) + if (dflag) server_write_session(s, MSG_DETACH, NULL, 0); update = options_get_string(&s->options, "update-environment"); @@ -110,3 +109,12 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_NORMAL); } + +enum cmd_retval +cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) +{ + struct args *args = self->args; + + return (cmd_attach_session(cmdq, args_get(args, 't'), + args_has(args, 'd'), args_has(args, 'r'))); +} diff --git a/cmd-new-session.c b/cmd-new-session.c index 13ab667e..1cc6fbab 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -35,8 +35,8 @@ enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "dn:s:t:x:y:", 0, 1, - "[-d] [-n window-name] [-s session-name] " CMD_TARGET_SESSION_USAGE + "AdDn:s:t:x:y:", 0, 1, + "[-AdD] [-n window-name] [-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, NULL, @@ -76,6 +76,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } if (session_find(newname) != NULL) { + if (args_has(args, 'A')) { + return (cmd_attach_session(cmdq, newname, + args_has(args, 'D'), 0)); + } cmdq_error(cmdq, "duplicate session: %s", newname); return (CMD_RETURN_ERROR); } diff --git a/tmux.1 b/tmux.1 index 33902d1b..b0d6b4e7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -666,7 +666,7 @@ command. Lock all clients attached to .Ar target-session . .It Xo Ic new-session -.Op Fl d +.Op Fl AdD .Op Fl n Ar window-name .Op Fl s Ar session-name .Op Fl t Ar target-session @@ -697,6 +697,21 @@ If run from a terminal, any .Xr termios 4 special characters are saved and used for new windows in the new session. .Pp +The +.Fl A +flag makes +.Ic new-session +behave like +.Ic attach-session +if +.Ar session-name +already exists; in the case, +.Fl D +behaves like +.Fl d +to +.Ic attach-session . +.Pp If .Fl t is given, the new session is @@ -1568,7 +1583,7 @@ Rename the current window, or the window at if specified, to .Ar new-name . .It Xo Ic resize-pane -.Op Fl DLRU +.Op Fl DLRUZ .Op Fl t Ar target-pane .Op Fl x Ar width .Op Fl y Ar height @@ -1592,6 +1607,11 @@ or The .Ar adjustment is given in lines or cells (the default is 1). +.Pp +With +.Fl Z , +the active pane is toggled between occupying the whole of the window and its +normal position in the layout. .It Xo Ic respawn-pane .Op Fl k .Op Fl t Ar target-pane diff --git a/tmux.h b/tmux.h index 2674a178..eee1987f 100644 --- a/tmux.h +++ b/tmux.h @@ -929,7 +929,9 @@ struct window_pane { u_int id; struct window *window; + struct layout_cell *layout_cell; + struct layout_cell *saved_layout_cell; u_int sx; u_int sy; @@ -994,6 +996,7 @@ struct window { int lastlayout; struct layout_cell *layout_root; + struct layout_cell *saved_layout_root; u_int sx; u_int sy; @@ -1003,6 +1006,7 @@ struct window { #define WINDOW_ACTIVITY 0x2 #define WINDOW_REDRAW 0x4 #define WINDOW_SILENCE 0x8 +#define WINDOW_ZOOMED 0x10 struct options options; @@ -1836,6 +1840,9 @@ extern const struct cmd_entry cmd_unbind_key_entry; extern const struct cmd_entry cmd_unlink_window_entry; extern const struct cmd_entry cmd_up_pane_entry; +/* cmd-attach-session.c */ +enum cmd_retval cmd_attach_session(struct cmd_q *, const char*, int, int); + /* cmd-list.c */ struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **); void cmd_list_free(struct cmd_list *); @@ -1929,6 +1936,7 @@ void server_push_stdout(struct client *); void server_push_stderr(struct client *); int server_set_stdin_callback(struct client *, void (*)(struct client *, int, void *), void *, char **); +void server_unzoom_window(struct window *); /* status.c */ int status_out_cmp(struct status_out *, struct status_out *); @@ -2132,6 +2140,8 @@ struct window_pane *window_find_string(struct window *, const char *); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int); void window_resize(struct window *, u_int, u_int); +int window_zoom(struct window_pane *); +int window_unzoom(struct window *); void window_remove_pane(struct window *, struct window_pane *); struct window_pane *window_pane_at_index(struct window *, u_int); struct window_pane *window_pane_next_by_number(struct window *, @@ -2188,7 +2198,7 @@ void layout_fix_panes(struct window *, u_int, u_int); u_int layout_resize_check(struct layout_cell *, enum layout_type); void layout_resize_adjust( struct layout_cell *, enum layout_type, int); -void layout_init(struct window *); +void layout_init(struct window *, struct window_pane *); void layout_free(struct window *); void layout_resize(struct window *, u_int, u_int); void layout_resize_pane(struct window_pane *, enum layout_type, From efa06643b02ca7cdc306d7ebcf1e38f04d2edc62 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:03:00 +0000 Subject: [PATCH 61/91] Remove previous. From 62db3c8efe70020e2555e3f34e8c07d0b2106077 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:03:24 +0000 Subject: [PATCH 62/91] Send DSC 1000p at the beginning of a -CC client's lifetime and ST and the end, from George Nachman. --- client.c | 10 +++++++++- server-client.c | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/client.c b/client.c index 8693afeb..1ab42c51 100644 --- a/client.c +++ b/client.c @@ -292,8 +292,16 @@ client_main(int argc, char **argv, int flags) ppid = getppid(); if (client_exittype == MSG_DETACHKILL && ppid > 1) kill(ppid, SIGHUP); - } else if (flags & IDENTIFY_TERMIOS) + } else if (flags & IDENTIFY_TERMIOS) { + if (flags & IDENTIFY_CONTROL) { + if (client_exitreason != CLIENT_EXIT_NONE) + printf("%%exit %s\n", client_exit_message()); + else + printf("%%exit\n"); + printf("\033\\"); + } tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); + } setblocking(STDIN_FILENO, 1); return (client_exitval); } diff --git a/server-client.c b/server-client.c index 64af442a..e590d219 100644 --- a/server-client.c +++ b/server-client.c @@ -957,6 +957,8 @@ server_client_msg_identify( if (data->flags & IDENTIFY_CONTROL) { c->stdin_callback = control_callback; c->flags |= CLIENT_CONTROL; + if (data->flags & IDENTIFY_TERMIOS) + evbuffer_add_printf(c->stdout_data, "\033P1000p"); server_write_client(c, MSG_STDIN, NULL, 0); c->tty.fd = -1; From d39b1a87a5e88444614415398510ff445a0748d6 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:04:04 +0000 Subject: [PATCH 63/91] Add -q flags to shut up errors to capture-pane and show-options, from George Nachman. --- cmd-show-options.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cmd-show-options.c b/cmd-show-options.c index 9b42ed46..57e49a33 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -30,14 +30,14 @@ enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_q *, - struct options *); + struct options *, int); enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *); const struct cmd_entry cmd_show_options_entry = { "show-options", "show", - "gst:vw", 0, 1, - "[-gsvw] [-t target-session|target-window] [option]", + "gqst:vw", 0, 1, + "[-gqsvw] [-t target-session|target-window] [option]", 0, NULL, NULL, @@ -62,6 +62,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) struct winlink *wl; const struct options_table_entry *table; struct options *oo; + int quiet; if (args_has(self->args, 's')) { oo = &global_options; @@ -89,15 +90,16 @@ cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) } } - if (args->argc != 0) - return (cmd_show_options_one(self, cmdq, oo)); - else + quiet = args_has(self->args, 'q'); + if (args->argc == 0) return (cmd_show_options_all(self, cmdq, table, oo)); + else + return (cmd_show_options_one(self, cmdq, oo, quiet)); } enum cmd_retval cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq, - struct options *oo) + struct options *oo, int quiet) { struct args *args = self->args; const struct options_table_entry *table, *oe; @@ -106,6 +108,8 @@ cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq, if (*args->argv[0] == '@') { if ((o = options_find1(oo, args->argv[0])) == NULL) { + if (quiet) + return (CMD_RETURN_NORMAL); cmdq_error(cmdq, "unknown option: %s", args->argv[0]); return (CMD_RETURN_ERROR); } @@ -122,6 +126,8 @@ cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq, return (CMD_RETURN_ERROR); } if (oe == NULL) { + if (quiet) + return (CMD_RETURN_NORMAL); cmdq_error(cmdq, "unknown option: %s", args->argv[0]); return (CMD_RETURN_ERROR); } From 2c14a771a8c399f6a0e24bc619006c1dd85a7ede Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:04:23 +0000 Subject: [PATCH 64/91] Remove some unused/unnecessary control notifications, from George Nachman. --- control-notify.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/control-notify.c b/control-notify.c index 87a25bb1..bb9708c8 100644 --- a/control-notify.c +++ b/control-notify.c @@ -104,10 +104,7 @@ control_notify_window_unlinked(unused struct session *s, struct window *w) continue; cs = c->session; - if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) - control_write(c, "%%window-close %u", w->id); - else - control_write(c, "%%unlinked-window-close %u", w->id); + control_write(c, "%%window-close %u", w->id); } } @@ -144,13 +141,7 @@ control_notify_window_renamed(struct window *w) continue; s = c->session; - if (winlink_find_by_window_id(&s->windows, w->id) != NULL) { - control_write(c, "%%window-renamed %u %s", - w->id, w->name); - } else { - control_write(c, "%%unlinked-window-renamed %u %s", - w->id, w->name); - } + control_write(c, "%%window-renamed %u %s", w->id, w->name); } } From e2e85650ac31a4814394e0bfe57b143de0b93e30 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:04:44 +0000 Subject: [PATCH 65/91] tty.path can be NULL, don't dereference it. From George Nachman. --- cmd-choose-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-choose-client.c b/cmd-choose-client.c index b32703c4..df57f9cf 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -79,7 +79,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq) cur = idx = 0; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c1 = ARRAY_ITEM(&clients, i); - if (c1 == NULL || c1->session == NULL) + if (c1 == NULL || c1->session == NULL || c1->tty.path == NULL) continue; if (c1 == cmdq->client) cur = idx; From e85f764f230c391d072d439cf9e2bea21284c2fe Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:05:35 +0000 Subject: [PATCH 66/91] Preserve trailing spaces with capture-pane -J, from George Nachman. --- cmd-capture-pane.c | 107 ++++++++++++++++++++++++++------------------- grid-view.c | 2 +- 2 files changed, 62 insertions(+), 47 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index aa032ce8..f3814f2f 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", - "b:CeE:JpS:t:", 0, 0, - "[-CeJp] [-b buffer-index] [-E end-line] [-S start-line]" + "ab:CeE:JpqS:t:", 0, 0, + "[-aCeJpq] [-b buffer-index] [-E end-line] [-S start-line]" CMD_TARGET_PANE_USAGE, 0, NULL, @@ -50,67 +50,82 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq) struct screen *s; struct grid *gd; int buffer, n, with_codes, escape_c0, join_lines; - u_int i, limit, top, bottom, tmp; + u_int i, limit, top, bottom, tmp, sx; size_t len, linelen; struct grid_cell *gc; const struct grid_line *gl; if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); - s = &wp->base; - gd = s->grid; + + if (args_has(args, 'a')) { + s = NULL; + gd = wp->saved_grid; + sx = screen_size_x(&wp->base); + if (gd == NULL && !args_has(args, 'q')) { + cmdq_error(cmdq, "no alternate screen"); + return (CMD_RETURN_ERROR); + } + } else { + s = &wp->base; + sx = screen_size_x(s); + gd = s->grid; + } buf = NULL; len = 0; - n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); - if (cause != NULL) { - top = gd->hsize; - free(cause); - } else if (n < 0 && (u_int) -n > gd->hsize) - top = 0; - else - top = gd->hsize + n; - if (top > gd->hsize + gd->sy - 1) - top = gd->hsize + gd->sy - 1; + if (gd != NULL) { + n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); + if (cause != NULL) { + top = gd->hsize; + free(cause); + } else if (n < 0 && (u_int) -n > gd->hsize) + top = 0; + else + top = gd->hsize + n; + if (top > gd->hsize + gd->sy - 1) + top = gd->hsize + gd->sy - 1; - n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause); - if (cause != NULL) { - bottom = gd->hsize + gd->sy - 1; - free(cause); - } else if (n < 0 && (u_int) -n > gd->hsize) - bottom = 0; - else - bottom = gd->hsize + n; - if (bottom > gd->hsize + gd->sy - 1) - bottom = gd->hsize + gd->sy - 1; + n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause); + if (cause != NULL) { + bottom = gd->hsize + gd->sy - 1; + free(cause); + } else if (n < 0 && (u_int) -n > gd->hsize) + bottom = 0; + else + bottom = gd->hsize + n; + if (bottom > gd->hsize + gd->sy - 1) + bottom = gd->hsize + gd->sy - 1; - if (bottom < top) { - tmp = bottom; - bottom = top; - top = tmp; - } + if (bottom < top) { + tmp = bottom; + bottom = top; + top = tmp; + } - with_codes = args_has(args, 'e'); - escape_c0 = args_has(args, 'C'); - join_lines = args_has(args, 'J'); + with_codes = args_has(args, 'e'); + escape_c0 = args_has(args, 'C'); + join_lines = args_has(args, 'J'); - gc = NULL; - for (i = top; i <= bottom; i++) { - line = grid_string_cells(s->grid, 0, i, screen_size_x(s), - &gc, with_codes, escape_c0); - linelen = strlen(line); + gc = NULL; + for (i = top; i <= bottom; i++) { + line = grid_string_cells(gd, 0, i, sx, &gc, with_codes, + escape_c0, !join_lines); + linelen = strlen(line); - buf = xrealloc(buf, 1, len + linelen + 1); - memcpy(buf + len, line, linelen); - len += linelen; + buf = xrealloc(buf, 1, len + linelen + 1); + memcpy(buf + len, line, linelen); + len += linelen; - gl = grid_peek_line(s->grid, i); - if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED)) - buf[len++] = '\n'; + gl = grid_peek_line(gd, i); + if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED)) + buf[len++] = '\n'; - free(line); - } + free(line); + } + } else + buf = xstrdup(""); if (args_has(args, 'p')) { c = cmdq->client; diff --git a/grid-view.c b/grid-view.c index a9a7e189..4fe38fed 100644 --- a/grid-view.c +++ b/grid-view.c @@ -234,5 +234,5 @@ grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) px = grid_view_x(gd, px); py = grid_view_y(gd, py); - return (grid_string_cells(gd, px, py, nx, NULL, 0, 0)); + return (grid_string_cells(gd, px, py, nx, NULL, 0, 0, 0)); } From e9cef8bf305e93d0ec8496c8155e0fa1258b8378 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:05:58 +0000 Subject: [PATCH 67/91] Continue the parent cmdq after sourcing a file. --- cmd-source-file.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd-source-file.c b/cmd-source-file.c index 3d69a544..1bd2bb0a 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -98,10 +98,11 @@ cmd_source_file_done(struct cmd_q *cmdq1) cmdq_free(cmdq1); cfg_references--; - if (cmdq_free(cmdq) || cfg_references != 0) + + if (cmdq_free(cmdq)) return; - cmd_source_file_show(cmdq); - + if (cfg_references == 0) + cmd_source_file_show(cmdq); cmdq_continue(cmdq); } From ebd9c615c8137e68f8831d4dbfd968a2f6a10a72 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:06:13 +0000 Subject: [PATCH 68/91] Add some additional debug logging. --- cfg.c | 1 + cmd-queue.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cfg.c b/cfg.c index e4069d68..c625a2fb 100644 --- a/cfg.c +++ b/cfg.c @@ -41,6 +41,7 @@ load_cfg(const char *path, struct cmd_q *cmdq, char **cause) size_t len, oldlen; struct cmd_list *cmdlist; + log_debug("loading %s", path); if ((f = fopen(path, "rb")) == NULL) { xasprintf(cause, "%s: %s", path, strerror(errno)); return (-1); diff --git a/cmd-queue.c b/cmd-queue.c index 07884df2..fba371dd 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -183,6 +183,7 @@ cmdq_continue(struct cmd_q *cmdq) struct cmd_q_item *next; enum cmd_retval retval; int guards, empty; + char s[1024]; guards = 0; if (c != NULL && c->session != NULL) @@ -204,11 +205,19 @@ cmdq_continue(struct cmd_q *cmdq) next = TAILQ_NEXT(cmdq->item, qentry); while (cmdq->cmd != NULL) { + cmd_print(cmdq->cmd, s, sizeof s); + log_debug("cmdq %p: %s (client %d)", cmdq, s, + cmdq->client != NULL ? cmdq->client->ibuf.fd : -1); + if (guards) cmdq_print(cmdq, "%%begin"); retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq); - if (guards) - cmdq_print(cmdq, "%%end"); + if (guards) { + if (retval == CMD_RETURN_ERROR) + cmdq_print(cmdq, "%%error"); + else + cmdq_print(cmdq, "%%end"); + } if (retval == CMD_RETURN_ERROR) break; From 35452b3e55aeaba7d64f604e32b31c80d3f80fde Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:07:21 +0000 Subject: [PATCH 69/91] Do not leak command in formats, from Romain Francoise. --- format.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/format.c b/format.c index af2c128b..11f003c8 100644 --- a/format.c +++ b/format.c @@ -398,7 +398,8 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) struct grid_line *gl; unsigned long long size; u_int i, idx; - const char *cwd, *cmd; + const char *cwd; + char *cmd; size = 0; for (i = 0; i < gd->hsize; i++) { @@ -432,8 +433,10 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_start_path", "%s", wp->cwd); if ((cwd = get_proc_cwd(wp->fd)) != NULL) format_add(ft, "pane_current_path", "%s", cwd); - if ((cmd = get_proc_name(wp->fd, wp->tty)) != NULL) + if ((cmd = get_proc_name(wp->fd, wp->tty)) != NULL) { format_add(ft, "pane_current_command", "%s", cmd); + free(cmd); + } format_add(ft, "cursor_x", "%d", wp->base.cx); format_add(ft, "cursor_y", "%d", wp->base.cy); From 304336a5917db5778854c71afd4e1f19bb11e476 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:07:40 +0000 Subject: [PATCH 70/91] Allow lastgc to be NULL in grid_string_cells so find-window doesn't crash, problem reported by eugene everson. --- grid.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/grid.c b/grid.c index 35e719b5..529ce154 100644 --- a/grid.c +++ b/grid.c @@ -583,7 +583,7 @@ grid_string_cells_code(const struct grid_cell *lastgc, /* Convert cells into a string. */ char * grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, - struct grid_cell **lastgc, int with_codes, int escape_c0) + struct grid_cell **lastgc, int with_codes, int escape_c0, int trim) { const struct grid_cell *gc; static struct grid_cell lastgc1; @@ -595,7 +595,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); - if (*lastgc == NULL) { + if (lastgc != NULL && *lastgc == NULL) { memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1); *lastgc = &lastgc1; } @@ -621,7 +621,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, data = ud.data; size = ud.size; if (escape_c0 && size == 1 && *data == '\\') { - data = "\\"; + data = "\\\\"; size = 2; } @@ -638,8 +638,10 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, off += size; } - while (off > 0 && buf[off - 1] == ' ') - off--; + if (trim) { + while (off > 0 && buf[off - 1] == ' ') + off--; + } buf[off] = '\0'; return (buf); From 410a3abbefee60750432d4c0ddcf9157e5b6f580 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:09:05 +0000 Subject: [PATCH 71/91] Add a wait-for command which blocks a client on a named channel until it is woken up again (with wait-for -S). From Thiago Padilha. --- Makefile | 1 + cmd.c | 9 +++++---- tmux.h | 5 ++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index f78b1615..9fa55d9b 100644 --- a/Makefile +++ b/Makefile @@ -77,6 +77,7 @@ SRCS= arguments.c \ cmd-switch-client.c \ cmd-unbind-key.c \ cmd-unlink-window.c \ + cmd-wait-for.c \ cmd.c \ cmd-queue.c \ colour.c \ diff --git a/cmd.c b/cmd.c index 5f530299..33ce730f 100644 --- a/cmd.c +++ b/cmd.c @@ -113,6 +113,7 @@ const struct cmd_entry *cmd_table[] = { &cmd_switch_client_entry, &cmd_unbind_key_entry, &cmd_unlink_window_entry, + &cmd_wait_for_entry, NULL }; @@ -327,9 +328,9 @@ cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) return (c->session); /* - * If the name of the calling client's pty is know, build a list of the - * sessions that contain it and if any choose either the first or the - * newest. + * If the name of the calling client's pty is known, build a list of + * the sessions that contain it and if any choose either the first or + * the newest. */ path = c == NULL ? NULL : c->tty.path; if (path != NULL) { @@ -532,7 +533,7 @@ cmd_lookup_client(const char *name) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) + if (c == NULL || c->session == NULL || c->tty.path == NULL) continue; path = c->tty.path; diff --git a/tmux.h b/tmux.h index eee1987f..0da2d0d3 100644 --- a/tmux.h +++ b/tmux.h @@ -1420,6 +1420,8 @@ struct cmd_q { void *data; struct msg_command_data *msgdata; + + TAILQ_ENTRY(cmd_q) waitentry; }; /* Command definition. */ @@ -1839,6 +1841,7 @@ extern const struct cmd_entry cmd_switch_client_entry; extern const struct cmd_entry cmd_unbind_key_entry; extern const struct cmd_entry cmd_unlink_window_entry; extern const struct cmd_entry cmd_up_pane_entry; +extern const struct cmd_entry cmd_wait_for_entry; /* cmd-attach-session.c */ enum cmd_retval cmd_attach_session(struct cmd_q *, const char*, int, int); @@ -2006,7 +2009,7 @@ void grid_clear_lines(struct grid *, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int); void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int); char *grid_string_cells(struct grid *, u_int, u_int, u_int, - struct grid_cell **, int, int); + struct grid_cell **, int, int, int); void grid_duplicate_lines( struct grid *, u_int, struct grid *, u_int, u_int); u_int grid_reflow(struct grid *, struct grid *, u_int); From 748acdc77ca11a09e637324946a6a4f189defc8e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:09:35 +0000 Subject: [PATCH 72/91] Add wait-for -L and -U for lock and unlock, from Thiago Padilha. --- cmd-wait-for.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++++ tmux.1 | 35 ++++++++- 2 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 cmd-wait-for.c diff --git a/cmd-wait-for.c b/cmd-wait-for.c new file mode 100644 index 00000000..3a8d8ea4 --- /dev/null +++ b/cmd-wait-for.c @@ -0,0 +1,197 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2013 Nicholas Marriott + * Copyright (c) 2013 Thiago de Arruda + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "tmux.h" + +/* + * Block or wake a client on a named wait channel. + */ + +enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *); + +const struct cmd_entry cmd_wait_for_entry = { + "wait-for", "wait", + "LSU", 1, 1, + "[-LSU] channel", + 0, + NULL, + NULL, + cmd_wait_for_exec +}; + +struct wait_channel { + const char *name; + int locked; + + TAILQ_HEAD(, cmd_q) waiters; + TAILQ_HEAD(, cmd_q) lockers; + + RB_ENTRY(wait_channel) entry; +}; +RB_HEAD(wait_channels, wait_channel); +struct wait_channels wait_channels = RB_INITIALIZER(wait_channels); + +int wait_channel_cmp(struct wait_channel *, struct wait_channel *); +RB_PROTOTYPE(wait_channels, wait_channel, entry, wait_channel_cmp); +RB_GENERATE(wait_channels, wait_channel, entry, wait_channel_cmp); + +int +wait_channel_cmp(struct wait_channel *wc1, struct wait_channel *wc2) +{ + return (strcmp(wc1->name, wc2->name)); +} + +enum cmd_retval cmd_wait_for_signal(struct cmd_q *, const char *, + struct wait_channel *); +enum cmd_retval cmd_wait_for_wait(struct cmd_q *, const char *, + struct wait_channel *); +enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const char *, + struct wait_channel *); +enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *, + struct wait_channel *); + +enum cmd_retval +cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq) +{ + struct args *args = self->args; + const char *name = args->argv[0]; + struct wait_channel *wc, wc0; + + wc0.name = name; + wc = RB_FIND(wait_channels, &wait_channels, &wc0); + + if (args_has(args, 'S')) + return (cmd_wait_for_signal(cmdq, name, wc)); + if (args_has(args, 'L')) + return (cmd_wait_for_lock(cmdq, name, wc)); + if (args_has(args, 'U')) + return (cmd_wait_for_unlock(cmdq, name, wc)); + return (cmd_wait_for_wait(cmdq, name, wc)); +} + +enum cmd_retval +cmd_wait_for_signal(struct cmd_q *cmdq, const char *name, + struct wait_channel *wc) +{ + struct cmd_q *wq, *wq1; + + if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) { + cmdq_error(cmdq, "no waiting clients on %s", name); + return (CMD_RETURN_ERROR); + } + + TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) { + TAILQ_REMOVE(&wc->waiters, wq, waitentry); + if (!cmdq_free(wq)) + cmdq_continue(wq); + } + + if (!wc->locked) { + RB_REMOVE(wait_channels, &wait_channels, wc); + free((void*) wc->name); + free(wc); + } + + return (CMD_RETURN_NORMAL); +} + +enum cmd_retval +cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, + struct wait_channel *wc) +{ + if (cmdq->client == NULL || cmdq->client->session != NULL) { + cmdq_error(cmdq, "not able to wait"); + return (CMD_RETURN_ERROR); + } + + if (wc == NULL) { + wc = xmalloc(sizeof *wc); + wc->name = xstrdup(name); + wc->locked = 0; + TAILQ_INIT(&wc->waiters); + TAILQ_INIT(&wc->lockers); + RB_INSERT(wait_channels, &wait_channels, wc); + } + + TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry); + cmdq->references++; + + return (CMD_RETURN_WAIT); +} + +enum cmd_retval +cmd_wait_for_lock(struct cmd_q *cmdq, const char *name, + struct wait_channel *wc) +{ + if (cmdq->client == NULL || cmdq->client->session != NULL) { + cmdq_error(cmdq, "not able to lock"); + return (CMD_RETURN_ERROR); + } + + if (wc == NULL) { + wc = xmalloc(sizeof *wc); + wc->name = xstrdup(name); + wc->locked = 0; + TAILQ_INIT(&wc->waiters); + TAILQ_INIT(&wc->lockers); + RB_INSERT(wait_channels, &wait_channels, wc); + } + + if (wc->locked) { + TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry); + cmdq->references++; + return (CMD_RETURN_WAIT); + } + wc->locked = 1; + + return (CMD_RETURN_NORMAL); +} + +enum cmd_retval +cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name, + struct wait_channel *wc) +{ + struct cmd_q *wq; + + if (wc == NULL || !wc->locked) { + cmdq_error(cmdq, "channel %s not locked", name); + return (CMD_RETURN_ERROR); + } + + if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) { + TAILQ_REMOVE(&wc->lockers, wq, waitentry); + if (!cmdq_free(wq)) + cmdq_continue(wq); + } else { + wc->locked = 0; + if (TAILQ_EMPTY(&wc->waiters)) { + RB_REMOVE(wait_channels, &wait_channels, wc); + free((void*) wc->name); + free(wc); + } + } + + return (CMD_RETURN_NORMAL); +} + diff --git a/tmux.1 b/tmux.1 index b0d6b4e7..f6055f11 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1062,8 +1062,7 @@ By default, it uses the format but a different format may be specified with .Fl F . .It Xo Ic capture-pane -.Op Fl e -.Op Fl p +.Op Fl aepq .Op Fl b Ar buffer-index .Op Fl E Ar end-line .Op Fl S Ar start-line @@ -1077,13 +1076,19 @@ is given, the output goes to stdout, otherwise to the buffer specified with .Fl b or a new buffer if omitted. If +.Fl a +is given, the alternate screen is used, and the history is not accessible. +If no alternate screen exists, an error will be returned unless +.Fl q +is given. +If .Fl e is given, the output includes escape sequences for text and background attributes. .Fl C also escapes non-printable characters as octal \exxx. .Fl J -joins wrapped lines. +joins wrapped lines and preserves trailing spaces at each line's end. .Pp .Fl S and @@ -2946,7 +2951,7 @@ If this option is set, searches will wrap around the end of the pane contents. The default is on. .El .It Xo Ic show-options -.Op Fl gsvw +.Op Fl gqsvw .Op Fl t Ar target-session | Ar target-window .Op Ar option .Xc @@ -2964,6 +2969,11 @@ Global session or window options are listed if is used. .Fl v shows only the option value, not the name. +If +.Fl q +is set, no error will be returned if +.Ar option +is unset. .It Xo Ic show-window-options .Op Fl gv .Op Fl t Ar target-window @@ -3539,6 +3549,23 @@ If the command doesn't return success, the exit status is also displayed. .It Ic server-info .D1 (alias: Ic info ) Show server information and terminal details. +.It Xo Ic wait-for +.Fl LSU +.Ar channel +.Xc +.D1 (alias: Ic wait ) +When used without options, prevents the client from exiting until woken using +.Ic wait-for +.Fl S +with the same channel. +When +.Fl L +is used, the channel is locked and any clients that try to lock the same +channel are made to wait until the channel is unlocked with +.Ic wait-for +.Fl U . +This command only works from outside +.Nm . .El .Sh TERMINFO EXTENSIONS .Nm From 6fee3e9e4b4c68c5d3d7f333c779ac865af7bf86 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:11:45 +0000 Subject: [PATCH 73/91] Rename session idx to session id throughout and add $ prefix to targets to use it, extended from a diff from George Nachman. --- client.c | 2 +- cmd-server-info.c | 2 +- cmd.c | 24 ++++++++++++++++++++++-- control-notify.c | 2 +- format.c | 1 + server-fn.c | 2 +- session.c | 14 +++++++------- tmux.1 | 5 +++-- tmux.c | 8 ++++---- tmux.h | 10 +++++----- window-choose.c | 2 +- 11 files changed, 47 insertions(+), 25 deletions(-) diff --git a/client.c b/client.c index 1ab42c51..f3e5dbdc 100644 --- a/client.c +++ b/client.c @@ -266,7 +266,7 @@ client_main(int argc, char **argv, int flags) if (msg == MSG_COMMAND) { /* Fill in command line arguments. */ cmddata.pid = environ_pid; - cmddata.idx = environ_idx; + cmddata.session_id = environ_session_id; /* Prepare command for server. */ cmddata.argc = argc; diff --git a/cmd-server-info.c b/cmd-server-info.c index a26fe705..07b224a1 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -102,7 +102,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_q *cmdq) *strchr(tim, '\n') = '\0'; cmdq_print(cmdq, "%2u: %s: %u windows (created %s) [%ux%u] " - "[flags=0x%x]", s->idx, s->name, + "[flags=0x%x]", s->id, s->name, winlink_count(&s->windows), tim, s->sx, s->sy, s->flags); RB_FOREACH(wl, winlinks, &s->windows) { w = wl->window; diff --git a/cmd.c b/cmd.c index 33ce730f..83edaf64 100644 --- a/cmd.c +++ b/cmd.c @@ -123,6 +123,7 @@ struct session *cmd_choose_session(int); struct client *cmd_choose_client(struct clients *); struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); +struct session *cmd_lookup_session_id(const char *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); int cmd_lookup_index(struct session *, const char *, int *); struct window_pane *cmd_lookup_paneid(const char *); @@ -358,8 +359,8 @@ cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) } /* Use the session from the TMUX environment variable. */ - if (data != NULL && data->pid == getpid() && data->idx != -1) { - s = session_find_by_index(data->idx); + if (data != NULL && data->pid == getpid() && data->session_id != -1) { + s = session_find_by_id(data->session_id); if (s != NULL) return (s); } @@ -551,6 +552,21 @@ cmd_lookup_client(const char *name) return (NULL); } +/* Find the target session or report an error and return NULL. */ +struct session * +cmd_lookup_session_id(const char *arg) +{ + char *endptr; + long id; + + if (arg[0] != '$') + return (NULL); + id = strtol(arg + 1, &endptr, 10); + if (arg[1] != '\0' && *endptr == '\0') + return (session_find_by_id(id)); + return (NULL); +} + /* Lookup a session by name. If no session is found, NULL is returned. */ struct session * cmd_lookup_session(const char *name, int *ambiguous) @@ -559,6 +575,10 @@ cmd_lookup_session(const char *name, int *ambiguous) *ambiguous = 0; + /* Look for $id first. */ + if ((s = cmd_lookup_session_id(name)) != NULL) + return (s); + /* * Look for matches. First look for exact matches - session names must * be unique so an exact match can't be ambigious and can just be diff --git a/control-notify.c b/control-notify.c index bb9708c8..6bc98b6f 100644 --- a/control-notify.c +++ b/control-notify.c @@ -154,7 +154,7 @@ control_notify_attached_session_changed(struct client *c) return; s = c->session; - control_write(c, "%%session-changed %d %s", s->idx, s->name); + control_write(c, "%%session-changed %d %s", s->id, s->name); } void diff --git a/format.c b/format.c index 11f003c8..dc988278 100644 --- a/format.c +++ b/format.c @@ -280,6 +280,7 @@ format_session(struct format_tree *ft, struct session *s) format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); format_add(ft, "session_width", "%u", s->sx); format_add(ft, "session_height", "%u", s->sy); + format_add(ft, "session_id", "%u", s->id); sg = session_group_find(s); format_add(ft, "session_grouped", "%d", sg != NULL); diff --git a/server-fn.c b/server-fn.c index 874afffb..f0c2dd23 100644 --- a/server-fn.c +++ b/server-fn.c @@ -39,7 +39,7 @@ server_fill_environ(struct session *s, struct environ *env) term = options_get_string(&s->options, "default-terminal"); environ_set(env, "TERM", term); - idx = s->idx; + idx = s->id; } else idx = -1; pid = getpid(); diff --git a/session.c b/session.c index b1944bc3..c7b54a2b 100644 --- a/session.c +++ b/session.c @@ -30,7 +30,7 @@ /* Global session list. */ struct sessions sessions; struct sessions dead_sessions; -u_int next_session; +u_int next_session_id; struct session_groups session_groups; struct winlink *session_next_alert(struct winlink *); @@ -70,14 +70,14 @@ session_find(const char *name) return (RB_FIND(sessions, &sessions, &s)); } -/* Find session by index. */ +/* Find session by id. */ struct session * -session_find_by_index(u_int idx) +session_find_by_id(u_int id) { struct session *s; RB_FOREACH(s, sessions, &sessions) { - if (s->idx == idx) + if (s->id == id) return (s); } return (NULL); @@ -121,13 +121,13 @@ session_create(const char *name, const char *cmd, const char *cwd, if (name != NULL) { s->name = xstrdup(name); - s->idx = next_session++; + s->id = next_session_id++; } else { s->name = NULL; do { - s->idx = next_session++; + s->id = next_session_id++; free (s->name); - xasprintf(&s->name, "%u", s->idx); + xasprintf(&s->name, "%u", s->id); } while (RB_FIND(sessions, &sessions, s) != NULL); } RB_INSERT(sessions, &sessions, s); diff --git a/tmux.1 b/tmux.1 index f6055f11..74868fc2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -365,9 +365,9 @@ Clients may be listed with the command. .Pp .Ar target-session -is either the name of a session (as listed by the +is the session id prefixed with a $, the name of a session (as listed by the .Ic list-sessions -command) or the name of a client with the same syntax as +command), or the name of a client with the same syntax as .Ar target-client , in which case the session attached to the client is used. When looking for the session name, @@ -3081,6 +3081,7 @@ The following variables are available, where appropriate: .It Li "session_group" Ta "Number of session group" .It Li "session_grouped" Ta "1 if session in a group" .It Li "session_height" Ta "Height of session" +.It Li "session_id" Ta "Unique session ID" .It Li "session_name" Ta "Name of session" .It Li "session_width" Ta "Width of session" .It Li "session_windows" Ta "Number of windows in session" diff --git a/tmux.c b/tmux.c index 7bce10ec..368562f8 100644 --- a/tmux.c +++ b/tmux.c @@ -49,7 +49,7 @@ char socket_path[MAXPATHLEN]; int login_shell; char *environ_path; pid_t environ_pid = -1; -int environ_idx = -1; +int environ_session_id = -1; __dead void usage(void); void parseenvironment(void); @@ -144,16 +144,16 @@ parseenvironment(void) { char *env, path[256]; long pid; - int idx; + int id; if ((env = getenv("TMUX")) == NULL) return; - if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &idx) != 3) + if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &id) != 3) return; environ_path = xstrdup(path); environ_pid = pid; - environ_idx = idx; + environ_session_id = id; } char * diff --git a/tmux.h b/tmux.h index 0da2d0d3..afba7804 100644 --- a/tmux.h +++ b/tmux.h @@ -466,8 +466,8 @@ enum msgtype { * Don't forget to bump PROTOCOL_VERSION if any of these change! */ struct msg_command_data { - pid_t pid; /* PID from $TMUX or -1 */ - int idx; /* index from $TMUX or -1 */ + pid_t pid; /* from $TMUX or -1 */ + int session_id; /* from $TMUX or -1 */ int argc; char argv[COMMAND_LENGTH]; @@ -1090,7 +1090,7 @@ struct session_group { TAILQ_HEAD(session_groups, session_group); struct session { - u_int idx; + u_int id; char *name; char *cwd; @@ -1517,7 +1517,7 @@ extern char socket_path[MAXPATHLEN]; extern int login_shell; extern char *environ_path; extern pid_t environ_pid; -extern int environ_idx; +extern int environ_session_id; void logfile(const char *); const char *getshell(void); int checkshell(const char *); @@ -2291,7 +2291,7 @@ int session_cmp(struct session *, struct session *); RB_PROTOTYPE(sessions, session, entry, session_cmp); int session_alive(struct session *); struct session *session_find(const char *); -struct session *session_find_by_index(u_int); +struct session *session_find_by_id(u_int); struct session *session_create(const char *, const char *, const char *, struct environ *, struct termios *, int, u_int, u_int, char **); diff --git a/window-choose.c b/window-choose.c index 2671c781..792224c1 100644 --- a/window-choose.c +++ b/window-choose.c @@ -859,7 +859,7 @@ window_choose_add_session(struct window_pane *wp, struct client *c, struct window_choose_data *wcd; wcd = window_choose_data_create(TREE_SESSION, c, c->session); - wcd->idx = s->idx; + wcd->idx = s->id; wcd->tree_session = s; wcd->tree_session->references++; From 446fb0cb9cd8e664639a204023b2e09f5f6aa6fb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 10:12:01 +0000 Subject: [PATCH 74/91] Do not redraw panes if invisible. --- screen-redraw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/screen-redraw.c b/screen-redraw.c index 8cc448a2..0d1d53da 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -273,6 +273,9 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) { u_int i, yoff; + if (!window_pane_visible(wp)) + return; + yoff = wp->yoff; if (status_at_line(c) == 0) yoff++; From e0961dfdf4e0f87d002771144d74a67ffc21945a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:35:30 +0000 Subject: [PATCH 75/91] Fix handling of short (< 4 character) checksums and a bug with parsing old-style custom layouts. Based on fix from Chris Johnsen. --- layout-custom.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/layout-custom.c b/layout-custom.c index dbbb8c14..c9cf49c2 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -63,7 +63,7 @@ layout_dump(struct window *w) if (layout_append(w->layout_root, layout, sizeof layout) != 0) return (NULL); - xasprintf(&out, "%4x,%s", layout_checksum(layout), layout); + xasprintf(&out, "%04x,%s", layout_checksum(layout), layout); return (out); } @@ -206,11 +206,11 @@ layout_construct(struct layout_cell *lcparent, const char **layout) { struct layout_cell *lc, *lcchild; u_int sx, sy, xoff, yoff; + const char *saved; if (!isdigit((u_char) **layout)) return (NULL); - if (sscanf(*layout, "%ux%u,%u,%u,%*u", &sx, &sy, &xoff, &yoff) != 4 && - sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4) + if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4) return (NULL); while (isdigit((u_char) **layout)) @@ -231,9 +231,12 @@ layout_construct(struct layout_cell *lcparent, const char **layout) while (isdigit((u_char) **layout)) (*layout)++; if (**layout == ',') { + saved = *layout; (*layout)++; while (isdigit((u_char) **layout)) (*layout)++; + if (**layout == 'x') + *layout = saved; } lc = layout_create_cell(lcparent); From 8a40e10d55d5ebedb079ef96aa2619ecf9b45988 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:35:55 +0000 Subject: [PATCH 76/91] Add time and a command count to control mode guards, based on code from George Nachman. --- control.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/control.c b/control.c index fc2d6e43..e78186e4 100644 --- a/control.c +++ b/control.c @@ -68,8 +68,13 @@ control_callback(struct client *c, int closed, unused void *data) } if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) { - control_write(c, "%%error in line \"%s\": %s", line, - cause); + c->cmdq->time = time(NULL); + c->cmdq->number++; + + cmdq_guard(c->cmdq, "begin"); + control_write(c, "parse error: %s", cause); + cmdq_guard(c->cmdq, "error"); + free(cause); } else { cmdq_run(c->cmdq, cmdlist); From e4c0730bf1e13ac256a58db7ee7a58c36c8980f4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:36:59 +0000 Subject: [PATCH 77/91] Use single stdout and stderr for control clients. --- server-client.c | 5 ++++- server-fn.c | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index e590d219..13c037d8 100644 --- a/server-client.c +++ b/server-client.c @@ -154,7 +154,8 @@ server_client_lost(struct client *c) evbuffer_free (c->stdin_data); evbuffer_free (c->stdout_data); - evbuffer_free (c->stderr_data); + if (c->stderr_data != c->stdout_data) + evbuffer_free (c->stderr_data); status_free_jobs(&c->status_new); status_free_jobs(&c->status_old); @@ -956,6 +957,8 @@ server_client_msg_identify( if (data->flags & IDENTIFY_CONTROL) { c->stdin_callback = control_callback; + evbuffer_free(c->stderr_data); + c->stderr_data = c->stdout_data; c->flags |= CLIENT_CONTROL; if (data->flags & IDENTIFY_TERMIOS) evbuffer_add_printf(c->stdout_data, "\033P1000p"); diff --git a/server-fn.c b/server-fn.c index f0c2dd23..c0b005e8 100644 --- a/server-fn.c +++ b/server-fn.c @@ -546,6 +546,10 @@ server_push_stderr(struct client *c) struct msg_stderr_data data; size_t size; + if (c->stderr_data == c->stdout_data) { + server_push_stdout(c); + return; + } size = EVBUFFER_LENGTH(c->stderr_data); if (size == 0) return; From 88b92df8492092fbbab37a3ddd2390e0eee2cb24 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:38:57 +0000 Subject: [PATCH 78/91] We ignore SIGWINCH until ready, so send a MSG_RESIZE immediately when becoming ready. --- client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client.c b/client.c index f3e5dbdc..70e7f1ec 100644 --- a/client.c +++ b/client.c @@ -520,6 +520,7 @@ client_dispatch_wait(void *data) event_del(&client_stdin); client_attached = 1; + client_write_server(MSG_RESIZE, NULL, 0); break; case MSG_STDIN: if (datalen != 0) From 114d822d27b2d4d20d707361629aaab6ba5a1a9f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:39:11 +0000 Subject: [PATCH 79/91] Don't zoom windows with one pane, from Romain Francoise. --- window.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/window.c b/window.c index 38af88f9..99d87ed6 100644 --- a/window.c +++ b/window.c @@ -483,6 +483,10 @@ window_zoom(struct window_pane *wp) if (!window_pane_visible(wp)) return (-1); + + if (window_count_panes(w) == 1) + return (-1); + if (w->active != wp) window_set_active_pane(w, wp); From 87fe1c0b0e47298de2cee7914d173cc18c4cd345 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:40:54 +0000 Subject: [PATCH 80/91] Include prefix on ids, from George Nachman. --- control-notify.c | 26 +++++++++++++++----------- format.c | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/control-notify.c b/control-notify.c index 6bc98b6f..0931c23a 100644 --- a/control-notify.c +++ b/control-notify.c @@ -46,8 +46,12 @@ control_notify_input(struct client *c, struct window_pane *wp, if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) { message = evbuffer_new(); evbuffer_add_printf(message, "%%output %%%u ", wp->id); - for (i = 0; i < len; i++) - evbuffer_add_printf(message, "%02hhx", buf[i]); + for (i = 0; i < len; i++) { + if (buf[i] < ' ' || buf[i] == '\\') + evbuffer_add_printf(message, "\\%03o", buf[i]); + else + evbuffer_add_printf(message, "%c", buf[i]); + } control_write_buffer(c, message); evbuffer_free(message); } @@ -104,7 +108,7 @@ control_notify_window_unlinked(unused struct session *s, struct window *w) continue; cs = c->session; - control_write(c, "%%window-close %u", w->id); + control_write(c, "%%window-close @%u", w->id); } } @@ -122,9 +126,9 @@ control_notify_window_linked(unused struct session *s, struct window *w) cs = c->session; if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) - control_write(c, "%%window-add %u", w->id); + control_write(c, "%%window-add @%u", w->id); else - control_write(c, "%%unlinked-window-add %u", w->id); + control_write(c, "%%unlinked-window-add @%u", w->id); } } @@ -141,7 +145,7 @@ control_notify_window_renamed(struct window *w) continue; s = c->session; - control_write(c, "%%window-renamed %u %s", w->id, w->name); + control_write(c, "%%window-renamed @%u %s", w->id, w->name); } } @@ -154,7 +158,7 @@ control_notify_attached_session_changed(struct client *c) return; s = c->session; - control_write(c, "%%session-changed %d %s", s->id, s->name); + control_write(c, "%%session-changed $%u %s", s->id, s->name); } void @@ -165,10 +169,10 @@ control_notify_session_renamed(struct session *s) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session != s) + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) continue; - control_write(c, "%%session-renamed %s", s->name); + control_write(c, "%%session-renamed $%u %s", s->id, s->name); } } @@ -180,7 +184,7 @@ control_notify_session_created(unused struct session *s) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) continue; control_write(c, "%%sessions-changed"); @@ -195,7 +199,7 @@ control_notify_session_close(unused struct session *s) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) continue; control_write(c, "%%sessions-changed"); diff --git a/format.c b/format.c index dc988278..b357876e 100644 --- a/format.c +++ b/format.c @@ -280,7 +280,7 @@ format_session(struct format_tree *ft, struct session *s) format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); format_add(ft, "session_width", "%u", s->sx); format_add(ft, "session_height", "%u", s->sy); - format_add(ft, "session_id", "%u", s->id); + format_add(ft, "session_id", "$%u", s->id); sg = session_group_find(s); format_add(ft, "session_grouped", "%d", sg != NULL); From 0ef24f99124b450bef17e3cc7895761e9eced049 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:41:16 +0000 Subject: [PATCH 81/91] Only send end guard if begin was sent, from George Nachman. --- cmd-queue.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cmd-queue.c b/cmd-queue.c index fba371dd..8bcc9192 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -151,6 +151,23 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) free(msg); } +/* Print a guard line. */ +int +cmdq_guard(struct cmd_q *cmdq, const char *guard) +{ + struct client *c = cmdq->client; + + if (c == NULL || c->session == NULL) + return 0; + if (!(c->flags & CLIENT_CONTROL)) + return 0; + + evbuffer_add_printf(c->stdout_data, "%%%s %ld %u\n", guard, + (long) cmdq->time, cmdq->number); + server_push_stdout(c); + return 1; +} + /* Add command list to queue and begin processing if needed. */ void cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist) @@ -179,16 +196,11 @@ cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist) int cmdq_continue(struct cmd_q *cmdq) { - struct client *c = cmdq->client; struct cmd_q_item *next; enum cmd_retval retval; - int guards, empty; + int empty, guard; char s[1024]; - guards = 0; - if (c != NULL && c->session != NULL) - guards = c->flags & CLIENT_CONTROL; - notify_disable(); empty = TAILQ_EMPTY(&cmdq->queue); @@ -209,14 +221,16 @@ cmdq_continue(struct cmd_q *cmdq) log_debug("cmdq %p: %s (client %d)", cmdq, s, cmdq->client != NULL ? cmdq->client->ibuf.fd : -1); - if (guards) - cmdq_print(cmdq, "%%begin"); + cmdq->time = time(NULL); + cmdq->number++; + + guard = cmdq_guard(cmdq, "begin"); retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq); - if (guards) { + if (guard) { if (retval == CMD_RETURN_ERROR) - cmdq_print(cmdq, "%%error"); + cmdq_guard(cmdq, "error"); else - cmdq_print(cmdq, "%%end"); + cmdq_guard(cmdq, "end"); } if (retval == CMD_RETURN_ERROR) From 111d993e75e869cb487302faf4319e1f4a02e8f8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:41:49 +0000 Subject: [PATCH 82/91] When only two panes in a window, only draw half the separating line as active. --- screen-redraw.c | 57 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 0d1d53da..4601c6f3 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -24,7 +24,11 @@ int screen_redraw_cell_border1(struct window_pane *, u_int, u_int); int screen_redraw_cell_border(struct client *, u_int, u_int); -int screen_redraw_check_cell(struct client *, u_int, u_int); +int screen_redraw_check_cell(struct client *, u_int, u_int, + struct window_pane **); +int screen_redraw_check_active(u_int, u_int, int, struct window *, + struct window_pane *); + void screen_redraw_draw_number(struct client *, struct window_pane *); #define CELL_INSIDE 0 @@ -93,7 +97,8 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py) /* Check if cell inside a pane. */ int -screen_redraw_check_cell(struct client *c, u_int px, u_int py) +screen_redraw_check_cell(struct client *c, u_int px, u_int py, + struct window_pane **wpp) { struct window *w = c->session->curw->window; struct window_pane *wp; @@ -105,6 +110,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) continue; + *wpp = wp; /* If outside the pane and its border, skip it. */ if ((wp->xoff != 0 && px < wp->xoff - 1) || @@ -162,9 +168,52 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py) } } + *wpp = NULL; return (CELL_OUTSIDE); } +/* Check active pane indicator. */ +int +screen_redraw_check_active(u_int px, u_int py, int type, struct window *w, + struct window_pane *wp) +{ + /* Is this off the active pane border? */ + if (screen_redraw_cell_border1(w->active, px, py) != 1) + return (0); + + /* If there are more than two panes, that's enough. */ + if (window_count_panes(w) != 2) + return (1); + + /* Else if the cell is not a border cell, forget it. */ + if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE)) + return (1); + + /* Check if the pane covers the whole width. */ + if (wp->xoff == 0 && wp->sx == w->sx) { + /* This can either be the top pane or the bottom pane. */ + if (wp->yoff == 0) { /* top pane */ + if (wp == w->active) + return (px <= wp->sx / 2); + return (px > wp->sx / 2); + } + return (0); + } + + /* Check if the pane covers the whole height. */ + if (wp->yoff == 0 && wp->sy == w->sy) { + /* This can either be the left pane or the right pane. */ + if (wp->xoff == 0) { /* left pane */ + if (wp == w->active) + return (py <= wp->sy / 2); + return (py > wp->sy / 2); + } + return (0); + } + + return (type); +} + /* Redraw entire screen. */ void screen_redraw_screen(struct client *c, int status_only, int borders_only) @@ -223,10 +272,10 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) break; } for (i = 0; i < tty->sx; i++) { - type = screen_redraw_check_cell(c, i, j); + type = screen_redraw_check_cell(c, i, j, &wp); if (type == CELL_INSIDE) continue; - if (screen_redraw_cell_border1(w->active, i, j) == 1) + if (screen_redraw_check_active(i, j, type, w, wp)) tty_attributes(tty, &active_gc); else tty_attributes(tty, &other_gc); From 0c969a7dfd7800ea3f86216069d99a03befbdda4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:42:01 +0000 Subject: [PATCH 83/91] Handle no client better in display-message. --- cmd-display-message.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index 7f31d7e2..52d47a4c 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -70,6 +70,18 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } + if (args_has(args, 'c')) { + c = cmd_find_client(cmdq, args_get(args, 'c'), 0); + if (c == NULL) + return (CMD_RETURN_ERROR); + } else { + c = cmd_current_client(cmdq); + if (c == NULL && !args_has(self->args, 'p')) { + cmdq_error(cmdq, "no client available"); + return (CMD_RETURN_ERROR); + } + } + template = args_get(args, 'F'); if (args->argc != 0) template = args->argv[0]; @@ -77,7 +89,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq) template = DISPLAY_MESSAGE_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 1)) != NULL) + if (c != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); From 270d90ce1e302e7d015abb30342cca0a6ecff048 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:42:19 +0000 Subject: [PATCH 84/91] Handle empty pending output (not a failure) and add \n. From George Nachman. --- cmd-capture-pane.c | 210 ++++++++++++++++++++++++++++----------------- 1 file changed, 133 insertions(+), 77 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index f3814f2f..779cbe08 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -29,10 +29,16 @@ enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_q *); +char *cmd_capture_pane_append(char *, size_t *, char *, size_t); +char *cmd_capture_pane_pending(struct args *, struct window_pane *, + size_t *); +char *cmd_capture_pane_history(struct args *, struct cmd_q *, + struct window_pane *, size_t *); + const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", - "ab:CeE:JpqS:t:", 0, 0, - "[-aCeJpq] [-b buffer-index] [-E end-line] [-S start-line]" + "ab:CeE:JpPqS:t:", 0, 0, + "[-aCeJpPq] [-b buffer-index] [-E end-line] [-S start-line]" CMD_TARGET_PANE_USAGE, 0, NULL, @@ -40,92 +46,140 @@ const struct cmd_entry cmd_capture_pane_entry = { cmd_capture_pane_exec }; +char * +cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen) +{ + buf = xrealloc(buf, 1, *len + linelen + 1); + memcpy(buf + *len, line, linelen); + *len += linelen; + return (buf); +} + +char * +cmd_capture_pane_pending(struct args *args, struct window_pane *wp, + size_t *len) +{ + char *buf, *line, tmp[5]; + size_t linelen; + u_int i; + + if (wp->ictx.since_ground == NULL) + return (xstrdup("")); + + line = EVBUFFER_DATA(wp->ictx.since_ground); + linelen = EVBUFFER_LENGTH(wp->ictx.since_ground); + + buf = xstrdup(""); + if (args_has(args, 'C')) { + for (i = 0; i < linelen; i++) { + if (line[i] >= ' ') { + tmp[0] = line[i]; + tmp[1] = '\0'; + } else + xsnprintf(tmp, sizeof tmp, "\\%03o", line[i]); + buf = cmd_capture_pane_append(buf, len, tmp, + strlen(tmp)); + } + } else + buf = cmd_capture_pane_append(buf, len, line, linelen); + return (buf); +} + +char * +cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq, + struct window_pane *wp, size_t *len) +{ + struct grid *gd; + const struct grid_line *gl; + struct grid_cell *gc = NULL; + int n, with_codes, escape_c0, join_lines; + u_int i, sx, top, bottom, tmp; + char *cause, *buf, *line; + size_t linelen; + + sx = screen_size_x(&wp->base); + if (args_has(args, 'a')) { + gd = wp->saved_grid; + if (gd == NULL) { + if (!args_has(args, 'q')) { + cmdq_error(cmdq, "no alternate screen"); + return (NULL); + } + return (xstrdup("")); + } + } else + gd = wp->base.grid; + + n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); + if (cause != NULL) { + top = gd->hsize; + free(cause); + } else if (n < 0 && (u_int) -n > gd->hsize) + top = 0; + else + top = gd->hsize + n; + if (top > gd->hsize + gd->sy - 1) + top = gd->hsize + gd->sy - 1; + + n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause); + if (cause != NULL) { + bottom = gd->hsize + gd->sy - 1; + free(cause); + } else if (n < 0 && (u_int) -n > gd->hsize) + bottom = 0; + else + bottom = gd->hsize + n; + if (bottom > gd->hsize + gd->sy - 1) + bottom = gd->hsize + gd->sy - 1; + + if (bottom < top) { + tmp = bottom; + bottom = top; + top = tmp; + } + + with_codes = args_has(args, 'e'); + escape_c0 = args_has(args, 'C'); + join_lines = args_has(args, 'J'); + + buf = NULL; + for (i = top; i <= bottom; i++) { + line = grid_string_cells(gd, 0, i, sx, &gc, with_codes, + escape_c0, !join_lines); + linelen = strlen(line); + + buf = cmd_capture_pane_append(buf, len, line, linelen); + + gl = grid_peek_line(gd, i); + if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED)) + buf[(*len)++] = '\n'; + + free(line); + } + return (buf); +} + enum cmd_retval cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c; struct window_pane *wp; - char *buf, *line, *cause; - struct screen *s; - struct grid *gd; - int buffer, n, with_codes, escape_c0, join_lines; - u_int i, limit, top, bottom, tmp, sx; - size_t len, linelen; - struct grid_cell *gc; - const struct grid_line *gl; + char *buf, *cause; + int buffer; + u_int limit; + size_t len; if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) return (CMD_RETURN_ERROR); - if (args_has(args, 'a')) { - s = NULL; - gd = wp->saved_grid; - sx = screen_size_x(&wp->base); - if (gd == NULL && !args_has(args, 'q')) { - cmdq_error(cmdq, "no alternate screen"); - return (CMD_RETURN_ERROR); - } - } else { - s = &wp->base; - sx = screen_size_x(s); - gd = s->grid; - } - - buf = NULL; len = 0; - - if (gd != NULL) { - n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause); - if (cause != NULL) { - top = gd->hsize; - free(cause); - } else if (n < 0 && (u_int) -n > gd->hsize) - top = 0; - else - top = gd->hsize + n; - if (top > gd->hsize + gd->sy - 1) - top = gd->hsize + gd->sy - 1; - - n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause); - if (cause != NULL) { - bottom = gd->hsize + gd->sy - 1; - free(cause); - } else if (n < 0 && (u_int) -n > gd->hsize) - bottom = 0; - else - bottom = gd->hsize + n; - if (bottom > gd->hsize + gd->sy - 1) - bottom = gd->hsize + gd->sy - 1; - - if (bottom < top) { - tmp = bottom; - bottom = top; - top = tmp; - } - - with_codes = args_has(args, 'e'); - escape_c0 = args_has(args, 'C'); - join_lines = args_has(args, 'J'); - - gc = NULL; - for (i = top; i <= bottom; i++) { - line = grid_string_cells(gd, 0, i, sx, &gc, with_codes, - escape_c0, !join_lines); - linelen = strlen(line); - - buf = xrealloc(buf, 1, len + linelen + 1); - memcpy(buf + len, line, linelen); - len += linelen; - - gl = grid_peek_line(gd, i); - if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED)) - buf[len++] = '\n'; - - free(line); - } - } else - buf = xstrdup(""); + if (args_has(args, 'P')) + buf = cmd_capture_pane_pending(args, wp, &len); + else + buf = cmd_capture_pane_history(args, cmdq, wp, &len); + if (buf == NULL) + return (CMD_RETURN_ERROR); if (args_has(args, 'p')) { c = cmdq->client; @@ -135,6 +189,8 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } evbuffer_add(c->stdout_data, buf, len); + if (args_has(args, 'P') && len > 0) + evbuffer_add(c->stdout_data, "\n", 1); server_push_stdout(c); } else { limit = options_get_number(&global_options, "buffer-limit"); From d28a39d01de47786a703e630a4f8930485cba7a1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:43:01 +0000 Subject: [PATCH 85/91] Extend jobs to support writing and use that for copy-pipe instead of popen, from Chris Johnsen. --- cmd-if-shell.c | 22 ++++++++++++---------- cmd-run-shell.c | 31 +++++++++++++++++-------------- job.c | 34 +++++++++++++++++++++++++++------- status.c | 2 +- 4 files changed, 57 insertions(+), 32 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index e2a45972..a3ca6555 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -59,19 +59,21 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; struct cmd_if_shell_data *cdata; char *shellcmd; - struct session *s; - struct winlink *wl; - struct window_pane *wp; + struct session *s = NULL; + struct winlink *wl = NULL; + struct window_pane *wp = NULL; struct format_tree *ft; - wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); - if (wl == NULL) - return (CMD_RETURN_ERROR); + if (args_has(args, 't')) + wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); ft = format_create(); - format_session(ft, s); - format_winlink(ft, s, wl); - format_window_pane(ft, wp); + if (s != NULL) + format_session(ft, s); + if (s != NULL && wl != NULL) + format_winlink(ft, s, wl); + if (wp != NULL) + format_window_pane(ft, wp); shellcmd = format_expand(ft, args->argv[0]); format_free(ft); @@ -87,7 +89,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) cdata->cmdq = cmdq; cmdq->references++; - job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata); + job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata); free(shellcmd); if (cdata->bflag) diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 5452ceff..e78d0e40 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -49,16 +49,17 @@ struct cmd_run_shell_data { char *cmd; struct cmd_q *cmdq; int bflag; - u_int wp_id; + int wp_id; }; void cmd_run_shell_print(struct job *job, const char *msg) { struct cmd_run_shell_data *cdata = job->data; - struct window_pane *wp; + struct window_pane *wp = NULL; - wp = window_pane_find_by_id(cdata->wp_id); + if (cdata->wp_id != -1) + wp = window_pane_find_by_id(cdata->wp_id); if (wp == NULL) { cmdq_print(cdata->cmdq, "%s", msg); return; @@ -76,31 +77,33 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; struct cmd_run_shell_data *cdata; char *shellcmd; - struct session *s; - struct winlink *wl; - struct window_pane *wp; + struct session *s = NULL; + struct winlink *wl = NULL; + struct window_pane *wp = NULL; struct format_tree *ft; - wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); - if (wl == NULL) - return (CMD_RETURN_ERROR); + if (args_has(args, 't')) + wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); ft = format_create(); - format_session(ft, s); - format_winlink(ft, s, wl); - format_window_pane(ft, wp); + if (s != NULL) + format_session(ft, s); + if (s != NULL && wl != NULL) + format_winlink(ft, s, wl); + if (wp != NULL) + format_window_pane(ft, wp); shellcmd = format_expand(ft, args->argv[0]); format_free(ft); cdata = xmalloc(sizeof *cdata); cdata->cmd = shellcmd; cdata->bflag = args_has(args, 'b'); - cdata->wp_id = wp->id; + cdata->wp_id = wp != NULL ? (int) wp->id : -1; cdata->cmdq = cmdq; cmdq->references++; - job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata); + job_run(shellcmd, s, cmd_run_shell_callback, cmd_run_shell_free, cdata); if (cdata->bflag) return (CMD_RETURN_NORMAL); diff --git a/job.c b/job.c index 64deeeab..b76b3345 100644 --- a/job.c +++ b/job.c @@ -33,13 +33,14 @@ */ void job_callback(struct bufferevent *, short, void *); +void job_write_callback(struct bufferevent *, void *); /* All jobs list. */ struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs); /* Start a job running, if it isn't already. */ struct job * -job_run(const char *cmd, +job_run(const char *cmd, struct session *s, void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) { struct job *job; @@ -52,7 +53,9 @@ job_run(const char *cmd, environ_init(&env); environ_copy(&global_environ, &env); - server_fill_environ(NULL, &env); + if (s != NULL) + environ_copy(&s->environ, &env); + server_fill_environ(s, &env); switch (pid = fork()) { case -1: @@ -64,20 +67,20 @@ job_run(const char *cmd, environ_push(&env); environ_free(&env); + if (dup2(out[1], STDIN_FILENO) == -1) + fatal("dup2 failed"); if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); - if (out[1] != STDOUT_FILENO) + if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO) close(out[1]); close(out[0]); nullfd = open(_PATH_DEVNULL, O_RDWR, 0); if (nullfd < 0) fatal("open failed"); - if (dup2(nullfd, STDIN_FILENO) == -1) - fatal("dup2 failed"); if (dup2(nullfd, STDERR_FILENO) == -1) fatal("dup2 failed"); - if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) + if (nullfd != STDERR_FILENO) close(nullfd); closefrom(STDERR_FILENO + 1); @@ -104,7 +107,8 @@ job_run(const char *cmd, job->fd = out[0]; setblocking(job->fd, 0); - job->event = bufferevent_new(job->fd, NULL, NULL, job_callback, job); + job->event = bufferevent_new(job->fd, NULL, job_write_callback, + job_callback, job); bufferevent_enable(job->event, EV_READ); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); @@ -133,6 +137,22 @@ job_free(struct job *job) free(job); } +/* Called when output buffer falls below low watermark (default is 0). */ +void +job_write_callback(unused struct bufferevent *bufev, void *data) +{ + struct job *job = data; + size_t len = EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job->event)); + + log_debug("job write %p: %s, pid %ld, output left %lu", job, job->cmd, + (long) job->pid, (unsigned long) len); + + if (len == 0) { + shutdown(job->fd, SHUT_WR); + bufferevent_disable(job->event, EV_WRITE); + } +} + /* Job buffer error callback. */ void job_callback(unused struct bufferevent *bufev, unused short events, void *data) diff --git a/status.c b/status.c index fc773dca..6ce0b871 100644 --- a/status.c +++ b/status.c @@ -594,7 +594,7 @@ status_find_job(struct client *c, char **iptr) /* If not found at all, start the job and add to the tree. */ if (so == NULL) { - job_run(cmd, status_job_callback, status_job_free, c); + job_run(cmd, NULL, status_job_callback, status_job_free, c); c->references++; so = xmalloc(sizeof *so); From 599dd2a56009300df999c54c73aa9e83268809e8 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:43:33 +0000 Subject: [PATCH 86/91] Create a new context when copying instead of using the input context. The input context may not exist yet. Fixes crash when copying from config file errors. --- window-copy.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/window-copy.c b/window-copy.c index 61fa382a..f5f78cf2 100644 --- a/window-copy.c +++ b/window-copy.c @@ -54,7 +54,8 @@ void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); void *window_copy_get_selection(struct window_pane *, size_t *); void window_copy_copy_buffer(struct window_pane *, int, void *, size_t); -void window_copy_copy_pipe(struct window_pane *, int, const char *); +void window_copy_copy_pipe( + struct window_pane *, struct session *, int, const char *); void window_copy_copy_selection(struct window_pane *, int); void window_copy_clear_selection(struct window_pane *); void window_copy_copy_line( @@ -539,7 +540,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) break; case MODEKEYCOPY_COPYPIPE: if (sess != NULL) { - window_copy_copy_pipe(wp, data->numprefix, arg); + window_copy_copy_pipe(wp, sess, data->numprefix, arg); window_pane_reset_mode(wp); return; } @@ -1384,10 +1385,14 @@ window_copy_get_selection(struct window_pane *wp, size_t *len) void window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len) { - u_int limit; + u_int limit; + struct screen_write_ctx ctx; - if (options_get_number(&global_options, "set-clipboard")) - screen_write_setselection(&wp->ictx.ctx, buf, len); + if (options_get_number(&global_options, "set-clipboard")) { + screen_write_start(&ctx, wp, NULL); + screen_write_setselection(&ctx, buf, len); + screen_write_stop(&ctx); + } if (idx == -1) { limit = options_get_number(&global_options, "buffer-limit"); @@ -1397,21 +1402,20 @@ window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len) } void -window_copy_copy_pipe(struct window_pane *wp, int idx, const char *arg) +window_copy_copy_pipe( + struct window_pane *wp, struct session *sess, int idx, const char *arg) { - void* buf; - size_t len; - FILE* f; + void *buf; + size_t len; + struct job *job; + buf = window_copy_get_selection(wp, &len); if (buf == NULL) return; - f = popen(arg, "w"); - if (f != NULL) { - fwrite(buf, 1, len, f); - pclose(f); - } + job = job_run(arg, sess, NULL, NULL, NULL); + bufferevent_write(job->event, buf, len); window_copy_copy_buffer(wp, idx, buf, len); } From 43fb9835fabee828c46d54b656a90a77eb756384 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:44:00 +0000 Subject: [PATCH 87/91] Add -P and -F to new-session. --- cmd-new-session.c | 50 ++++++++++++++++++++++++++++++++--------------- cmd-new-window.c | 6 ++---- tmux.h | 12 +++++++----- 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 1cc6fbab..653db876 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -35,9 +35,9 @@ enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "AdDn:s:t:x:y:", 0, 1, - "[-AdD] [-n window-name] [-s session-name] " CMD_TARGET_SESSION_USAGE - " [-x width] [-y height] [command]", + "AdDF:n:Ps:t:x:y:", 0, 1, + "[-AdDP] [-F format] [-n window-name] [-s session-name] " + CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, NULL, cmd_new_session_check, @@ -55,19 +55,20 @@ cmd_new_session_check(struct args *args) enum cmd_retval cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) { - struct args *args = self->args; - struct client *c = cmdq->client; - struct session *s, *groupwith; - struct window *w; - struct environ env; - struct termios tio, *tiop; - struct passwd *pw; - const char *newname, *target, *update, *cwd, *errstr; - char *cmd, *cause; - int detached, idx; - u_int sx, sy; - int already_attached; - + struct args *args = self->args; + struct client *c = cmdq->client; + struct session *s, *groupwith; + struct window *w; + struct environ env; + struct termios tio, *tiop; + struct passwd *pw; + const char *newname, *target, *update, *cwd, *errstr; + const char *template; + char *cmd, *cause, *cp; + int detached, idx; + u_int sx, sy; + int already_attached; + struct format_tree *ft; newname = args_get(args, 's'); if (newname != NULL) { @@ -233,6 +234,23 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (cfg_finished) cfg_show_causes(s); + /* Print if requested. */ + if (args_has(args, 'P')) { + if ((template = args_get(args, 'F')) == NULL) + template = NEW_SESSION_TEMPLATE; + + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + + cp = format_expand(ft, template); + cmdq_print(cmdq, "%s", cp); + free(cp); + + format_free(ft); + } + if (!detached) cmdq->client_exit = 0; return (CMD_RETURN_NORMAL); diff --git a/cmd-new-window.c b/cmd-new-window.c index 161dc549..eac0df44 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -46,12 +46,10 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) struct session *s; struct winlink *wl; struct client *c; - const char *cmd, *cwd; - const char *template; - char *cause; + const char *cmd, *cwd, *template; + char *cause, *cp; int idx, last, detached; struct format_tree *ft; - char *cp; if (args_has(args, 'a')) { wl = cmd_find_window(cmdq, args_get(args, 't'), &s); diff --git a/tmux.h b/tmux.h index afba7804..10da2bee 100644 --- a/tmux.h +++ b/tmux.h @@ -159,6 +159,7 @@ extern char **environ; /* Default templates for break-pane, new-window and split-window. */ #define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}" +#define NEW_SESSION_TEMPLATE "#{session_name}:" #define NEW_WINDOW_TEMPLATE BREAK_PANE_TEMPLATE #define SPLIT_WINDOW_TEMPLATE BREAK_PANE_TEMPLATE @@ -780,9 +781,6 @@ struct job { int fd; struct bufferevent *event; - struct bufferevent *out; - int outdone; - void (*callbackfn)(struct job *); void (*freefn)(void *); void *data; @@ -1416,6 +1414,9 @@ struct cmd_q { struct cmd_q_item *item; struct cmd *cmd; + time_t time; + u_int number; + void (*emptyfn)(struct cmd_q *); void *data; @@ -1611,8 +1612,8 @@ int options_table_find(const char *, const struct options_table_entry **, /* job.c */ extern struct joblist all_jobs; -struct job *job_run( - const char *, void (*)(struct job *), void (*)(void *), void *); +struct job *job_run(const char *, struct session *, + void (*)(struct job *), void (*)(void *), void *); void job_free(struct job *); void job_died(struct job *, int); @@ -1857,6 +1858,7 @@ int cmdq_free(struct cmd_q *); void printflike2 cmdq_print(struct cmd_q *, const char *, ...); void printflike2 cmdq_info(struct cmd_q *, const char *, ...); void printflike2 cmdq_error(struct cmd_q *, const char *, ...); +int cmdq_guard(struct cmd_q *, const char *); void cmdq_run(struct cmd_q *, struct cmd_list *); void cmdq_append(struct cmd_q *, struct cmd_list *); int cmdq_continue(struct cmd_q *); From e2295014d9c761381999e023872c22ea4827e736 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:44:16 +0000 Subject: [PATCH 88/91] Process ^[ as meta when a partial key is found. --- tty-keys.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tty-keys.c b/tty-keys.c index fc79c89b..33539d15 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -82,6 +82,13 @@ const struct tty_default_key_raw tty_default_raw_keys[] = { { "\033[C", KEYC_RIGHT }, { "\033[D", KEYC_LEFT }, + /* Other (xterm) "cursor" keys. */ + { "\033OH", KEYC_HOME }, + { "\033OF", KEYC_END }, + + { "\033[H", KEYC_HOME }, + { "\033[F", KEYC_END }, + /* rxvt-style arrow + modifier keys. */ { "\033Oa", KEYC_UP|KEYC_CTRL }, { "\033Ob", KEYC_DOWN|KEYC_CTRL }, @@ -491,6 +498,7 @@ tty_keys_next(struct tty *tty) goto complete_key; } +first_key: /* Is this a meta key? */ if (len >= 2 && buf[0] == '\033') { if (buf[1] != '\033') { @@ -511,7 +519,6 @@ tty_keys_next(struct tty *tty) } } -first_key: /* No key found, take first. */ key = (u_char) *buf; size = 1; From 4119c476aac32ca049991f06fc087d780ed882d1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:46:28 +0000 Subject: [PATCH 89/91] b comes before t. --- tmux.1 | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/tmux.1 b/tmux.1 index 74868fc2..5d4864d0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -23,7 +23,7 @@ .Sh SYNOPSIS .Nm tmux .Bk -words -.Op Fl 28lquv +.Op Fl 28lCquv .Op Fl c Ar shell-command .Op Fl f Ar file .Op Fl L Ar socket-name @@ -102,6 +102,11 @@ to assume the terminal supports 256 colours. Like .Fl 2 , but indicates that the terminal supports 88 colours. +.It Fl C +Start in control mode. +Given twice +.Xo ( Fl CC ) Xc +disables echo. .It Fl c Ar shell-command Execute .Ar shell-command @@ -666,7 +671,8 @@ command. Lock all clients attached to .Ar target-session . .It Xo Ic new-session -.Op Fl AdD +.Op Fl AdDP +.Op Fl F Ar format .Op Fl n Ar window-name .Op Fl s Ar session-name .Op Fl t Ar target-session @@ -731,6 +737,14 @@ or are invalid if .Fl t is used. +.Pp +The +.Fl P +option prints information about the new session after it has been created. +By default, it uses the format +.Ql #{session_name}: +but a different format may be specified with +.Fl F . .It Xo Ic refresh-client .Op Fl S .Op Fl t Ar target-client @@ -1062,7 +1076,7 @@ By default, it uses the format but a different format may be specified with .Fl F . .It Xo Ic capture-pane -.Op Fl aepq +.Op Fl aepPq .Op Fl b Ar buffer-index .Op Fl E Ar end-line .Op Fl S Ar start-line @@ -1089,6 +1103,9 @@ attributes. also escapes non-printable characters as octal \exxx. .Fl J joins wrapped lines and preserves trailing spaces at each line's end. +.Fl P +captures only any output that the pane has received that is the beginning of an +as-yet incomplete escape sequence. .Pp .Fl S and @@ -1458,9 +1475,9 @@ option. .It Xo Ic new-window .Op Fl adkP .Op Fl c Ar start-directory +.Op Fl F Ar format .Op Fl n Ar window-name .Op Fl t Ar target-window -.Op Fl F Ar format .Op Ar shell-command .Xc .D1 (alias: Ic neww ) @@ -1615,8 +1632,8 @@ is given in lines or cells (the default is 1). .Pp With .Fl Z , -the active pane is toggled between occupying the whole of the window and its -normal position in the layout. +the active pane is toggled between zoomed (occupying the whole of the window) +and unzoomed (its normal position in the layout). .It Xo Ic respawn-pane .Op Fl k .Op Fl t Ar target-pane @@ -3248,6 +3265,7 @@ The flag is one of the following symbols appended to the window name: .It Li "!" Ta "A bell has occurred in the window." .It Li "+" Ta "Window is monitored for content and it has appeared." .It Li "~" Ta "The window has been silent for the monitor-silence interval." +.It Li "Z" Ta "The window's active pane is zoomed." .El .Pp The # symbol relates to the @@ -3500,8 +3518,8 @@ Miscellaneous commands are as follows: .It Ic clock-mode Op Fl t Ar target-pane Display a large clock. .It Xo Ic if-shell -.Op Fl t Ar target-pane .Op Fl b +.Op Fl t Ar target-pane .Ar shell-command command .Op Ar command .Xc @@ -3606,6 +3624,91 @@ option above and the .Xr xterm 1 man page. .El +.Sh CONTROL MODE +.Nm +offers a textual interface called +.Em control mode . +This allows applications to communicate with +.Nm +using a simple text-only protocol. +.Pp +In control mode, a client sends +.Nm +commands or command sequences terminated by newlines on standard input. +Each command will produce one block of output on standard output. +An output block consists of a +.Em %begin +line followed by the output (which may be empty). +The output block ends with a +.Em %end +or +.Em %error . +.Em %begin +and matching +.Em %end +or +.Em %error +have two arguments: an integer time (as seconds from epoch) and command number. +For example: +.Bd -literal -offset indent +%begin 1363006971 2 +0: ksh* (1 panes) [80x24] [layout b25f,80x24,0,0,2] @2 (active) +%end 1363006971 2 +.Ed +.Pp +In control mode, +.Nm +outputs notifications. +A notification will never occur inside an output block. +.Pp +The following notifications are defined: +.Bl -tag -width Ds +.It Ic %exit Op Ar reason +The +.Nm +client is exiting immediately, either because it is not attached to any session +or an error occurred. +If present, +.Ar reason +describes why the client exited. +.It Ic %layout-change Ar window-id Ar window-layout +The layout of a window with ID +.Ar window-id +changed. +The new layout is +.Ar window-layout . +.It Ic %output Ar pane-id Ar value +A window pane produced output. +.Ar value +escapes non-printable characters and backslash as octal \\xxx. +.It Ic %session-changed Ar session-id Ar name +The client is now attached to the session with ID +.Ar session-id , +which is named +.Ar name . +.It Ic %session-renamed Ar name +The current session was renamed to +.Ar name . +.It Ic %sessions-changed +A session was created or destroyed. +.It Ic %unlinked-window-add Ar window-id +The window with ID +.Ar window-id +was created but is not linked to the current session. +.It Ic %window-add Ar window-id +The window with ID +.Ar window-id +was linked to the current session. +.It Ic %window-close Ar window-id +The window with ID +.Ar window-id +closed. +.It Ic %window-renamed Ar window-id Ar name +The window with ID +.Ar window-id +was renamed to +.Ar name . +.El .Sh FILES .Bl -tag -width "/etc/tmux.confXXX" -compact .It Pa ~/.tmux.conf From 673eb160d428b294cea1ed5ca2a2c3cb3760b00f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:53:54 +0000 Subject: [PATCH 90/91] Sort includes and fix spaces. --- cmd.c | 4 ++-- server-client.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd.c b/cmd.c index 83edaf64..d0348704 100644 --- a/cmd.c +++ b/cmd.c @@ -1245,8 +1245,8 @@ cmd_template_replace(const char *template, const char *s, int idx) { char ch, *buf; const char *ptr; - int replaced; - size_t len; + int replaced; + size_t len; if (strchr(template, '%') == NULL) return (xstrdup(template)); diff --git a/server-client.c b/server-client.c index 13c037d8..f61912bc 100644 --- a/server-client.c +++ b/server-client.c @@ -21,10 +21,10 @@ #include #include -#include -#include #include #include +#include +#include #include #include "tmux.h" From 58bb6f8c5650d496fb3b872766c0278aa024631d Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 25 Mar 2013 11:55:01 +0000 Subject: [PATCH 91/91] Set pane resize flag when needed. --- window.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/window.c b/window.c index 99d87ed6..0ab36033 100644 --- a/window.c +++ b/window.c @@ -918,6 +918,8 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL); if (wp->mode != NULL) wp->mode->resize(wp, sx, sy); + + wp->flags |= PANE_RESIZE; } /*