From 180faf73afe07d35e6002993a70d5fe63549ffce Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:09:59 +0000 Subject: 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++; - - window_choose_add(wp, wcd); - /* - * Interpolate action_data here, since the data we pass back is the - * expanded template itself. + * Interpolate action 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); + 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); 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); -- cgit From 9b7e18f166b1f771a2ad3096831bf145731deb1b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:12:10 +0000 Subject: 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; + + py = 0; + sy = src->sy; - px = py = 0; - previous_wrapped = 1; - for (line = 0; line < src->sy + src->hsize; line++) { - gl = src->linedata + line; + 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); } -- cgit From dd76497ab01620bf5c7b63205f3e1405f3c34d8c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:12:50 +0000 Subject: 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); } -- cgit From 63b4fd5cacc1a53b93e92ef007d5a7249f5cac38 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:14:09 +0000 Subject: 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. */ -- cgit From 69fe5ca5670bc32b585e3ebf2066861212d7d014 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:15:52 +0000 Subject: 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); -- cgit From 0c0953f3bda2ecf9c351624c730445405d87e495 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:17:01 +0000 Subject: 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); } -- cgit From c982279950de9c9ffa797aab48caa1bff89ee8d4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:19:25 +0000 Subject: 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 */ -- cgit From 51d989f5dfaa63a844ae291772f20c486a5982fb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:22:48 +0000 Subject: 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; -- cgit From 66414029a12af55f4e6b4a421d5e193c2561e30c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:23:07 +0000 Subject: 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; -- cgit From 4920306486122f3e6c1afd69518dbbdb40fbff5b Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:23:46 +0000 Subject: 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" -- cgit From dd46c95e23e546dfe5ad66e8200d87b739c15db2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:25:08 +0000 Subject: 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. */ -- cgit From 801d64a16e320f0f24dcc65d2da9eabb16b17dee Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:49:37 +0000 Subject: 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 -- cgit From 3665be7c4467126b64c43b8fd687dd3512ccc05a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:50:22 +0000 Subject: 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); } -- cgit From d5139d140154ef3e90fa65d0a8f2632bad1c67e1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 21 Mar 2013 16:52:02 +0000 Subject: Fix a comment for new key table names. --- tty-keys.c | 481 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 240 insertions(+), 241 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_DO