diff --git a/arguments.c b/arguments.c index 30e8fa0b..5669df92 100644 --- a/arguments.c +++ b/arguments.c @@ -166,7 +166,7 @@ args_parse(const struct args_parse *parse, struct args_value *values, } argument = *++found; if (argument != ':') { - log_debug("%s: add -%c", __func__, flag); + log_debug("%s: -%c", __func__, flag); args_set(args, flag, NULL); continue; } @@ -192,7 +192,7 @@ args_parse(const struct args_parse *parse, struct args_value *values, args_copy_value(new, &values[i++]); } s = args_value_as_string(new); - log_debug("%s: add -%c = %s", __func__, flag, s); + log_debug("%s: -%c = %s", __func__, flag, s); args_set(args, flag, new); break; } @@ -203,7 +203,8 @@ args_parse(const struct args_parse *parse, struct args_value *values, value = &values[i]; s = args_value_as_string(value); - log_debug("%s: %u = %s", __func__, i, s); + log_debug("%s: %u = %s (type %d)", __func__, i, s, + value->type); if (parse->cb != NULL) { type = parse->cb(args, args->count, cause); @@ -265,6 +266,63 @@ args_parse(const struct args_parse *parse, struct args_value *values, return (args); } +/* Copy and expand a value. */ +static void +args_copy_copy_value(struct args_value *to, struct args_value *from, int argc, + char **argv) +{ + char *s, *expanded; + int i; + + to->type = from->type; + switch (from->type) { + case ARGS_NONE: + break; + case ARGS_STRING: + expanded = xstrdup(from->string); + for (i = 0; i < argc; i++) { + s = cmd_template_replace(expanded, argv[i], i + 1); + free(expanded); + expanded = s; + } + to->string = expanded; + break; + case ARGS_COMMANDS: + to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv); + break; + } +} + +/* Copy an arguments set. */ +struct args * +args_copy(struct args *args, int argc, char **argv) +{ + struct args *new_args; + struct args_entry *entry; + struct args_value *value, *new_value; + u_int i; + + new_args = args_create(); + RB_FOREACH(entry, args_tree, &args->tree) { + if (entry->count == 1) { + args_set(new_args, entry->flag, NULL); + continue; + } + TAILQ_FOREACH(value, &entry->values, entry) { + new_value = xcalloc(1, sizeof *new_value); + args_copy_copy_value(new_value, value, argc, argv); + args_set(new_args, entry->flag, new_value); + } + } + new_args->count = args->count; + new_args->values = xcalloc(args->count, sizeof *new_args->values); + for (i = 0; i < args->count; i++) { + new_value = &new_args->values[i]; + args_copy_copy_value(new_value, &args->values[i], argc, argv); + } + return (new_args); +} + /* Free a value. */ void args_free_value(struct args_value *value) @@ -282,6 +340,16 @@ args_free_value(struct args_value *value) free(value->cached); } +/* Free values. */ +void +args_free_values(struct args_value *values, u_int count) +{ + u_int i; + + for (i = 0; i < count; i++) + args_free_value(&values[i]); +} + /* Free an arguments set. */ void args_free(struct args *args) @@ -290,10 +358,8 @@ args_free(struct args *args) struct args_entry *entry1; struct args_value *value; struct args_value *value1; - u_int i; - for (i = 0; i < args->count; i++) - args_free_value(&args->values[i]); + args_free_values(args->values, args->count); free(args->values); RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { @@ -311,7 +377,7 @@ args_free(struct args *args) /* Convert arguments to vector. */ void -args_vector(struct args *args, int *argc, char ***argv) +args_to_vector(struct args *args, int *argc, char ***argv) { char *s; u_int i; @@ -335,6 +401,21 @@ args_vector(struct args *args, int *argc, char ***argv) } } +/* Convert arguments from vector. */ +struct args_value * +args_from_vector(int argc, char **argv) +{ + struct args_value *values; + int i; + + values = xcalloc(argc, sizeof *values); + for (i = 0; i < argc; i++) { + values[i].type = ARGS_STRING; + values[i].string = xstrdup(argv[i]); + } + return (values); +} + /* Add to string. */ static void printflike(3, 4) args_print_add(char **buf, size_t *len, const char *fmt, ...) @@ -424,7 +505,7 @@ args_print(struct args *args) char * args_escape(const char *s) { - static const char dquoted[] = " #';${}"; + static const char dquoted[] = " #';${}%"; static const char squoted[] = " \""; char *escaped, *result; int flags, quotes = 0; @@ -538,6 +619,13 @@ args_count(struct args *args) return (args->count); } +/* Get argument values. */ +struct args_value * +args_values(struct args *args) +{ + return (args->values); +} + /* Get argument value. */ struct args_value * args_value(struct args *args, u_int idx) @@ -570,8 +658,8 @@ args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx) cmdq_error(item, "%s", error); free(error); } - else - cmdlist->references++; + else + cmdlist->references++; args_make_commands_free(state); return (cmdlist); } @@ -631,8 +719,11 @@ args_make_commands(struct args_command_state *state, int argc, char **argv, char *cmd, *new_cmd; int i; - if (state->cmdlist != NULL) - return (state->cmdlist); + if (state->cmdlist != NULL) { + if (argc == 0) + return (state->cmdlist); + return (cmd_list_copy(state->cmdlist, argc, argv)); + } cmd = xstrdup(state->cmd); for (i = 0; i < argc; i++) { diff --git a/client.c b/client.c index fc0e1dde..8ca08524 100644 --- a/client.c +++ b/client.c @@ -243,6 +243,7 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, ssize_t linelen; char *line = NULL, **caps = NULL, *cause; u_int ncaps = 0; + struct args_value *values; /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ signal(SIGCHLD, SIG_IGN); @@ -258,17 +259,20 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, msg = MSG_COMMAND; /* - * It sucks parsing the command string twice (in client and - * later in server) but it is necessary to get the start server - * flag. + * It's annoying parsing the command string twice (in client + * and later in server) but it is necessary to get the start + * server flag. */ - pr = cmd_parse_from_arguments(argc, argv, NULL); + values = args_from_vector(argc, argv); + pr = cmd_parse_from_arguments(values, argc, NULL); if (pr->status == CMD_PARSE_SUCCESS) { if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER)) flags |= CLIENT_STARTSERVER; cmd_list_free(pr->cmdlist); } else free(pr->error); + args_free_values(values, argc); + free(values); } /* Create client process structure (starts logging). */ diff --git a/cmd-bind-key.c b/cmd-bind-key.c index be0ae40e..dab03b01 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -58,8 +58,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item) key_code key; const char *tablename, *note = args_get(args, 'N'); struct cmd_parse_result *pr; - char **argv; - int argc, repeat; + int repeat; struct args_value *value; u_int count = args_count(args); @@ -92,9 +91,8 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item) if (count == 2) pr = cmd_parse_from_string(args_string(args, 1), NULL); else { - args_vector(args, &argc, &argv); - pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL); - cmd_free_argv(argc, argv); + pr = cmd_parse_from_arguments(args_values(args) + 1, count - 1, + NULL); } switch (pr->status) { case CMD_PARSE_ERROR: diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 9258f366..7aa1d217 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -24,13 +24,16 @@ * Enter a mode. */ -static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *); +static enum args_parse_type cmd_choose_tree_args_parse(struct args *args, + u_int idx, char **cause); +static enum cmd_retval cmd_choose_tree_exec(struct cmd *, + struct cmdq_item *); const struct cmd_entry cmd_choose_tree_entry = { .name = "choose-tree", .alias = NULL, - .args = { "F:f:GK:NO:rst:wZ", 0, 1, NULL }, + .args = { "F:f:GK:NO:rst:wZ", 0, 1, cmd_choose_tree_args_parse }, .usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] " "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", @@ -44,7 +47,7 @@ const struct cmd_entry cmd_choose_client_entry = { .name = "choose-client", .alias = NULL, - .args = { "F:f:K:NO:rt:Z", 0, 1, NULL }, + .args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse }, .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] " "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", @@ -58,7 +61,7 @@ const struct cmd_entry cmd_choose_buffer_entry = { .name = "choose-buffer", .alias = NULL, - .args = { "F:f:K:NO:rt:Z", 0, 1, NULL }, + .args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse }, .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] " "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", @@ -81,6 +84,13 @@ const struct cmd_entry cmd_customize_mode_entry = { .exec = cmd_choose_tree_exec }; +static enum args_parse_type +cmd_choose_tree_args_parse(__unused struct args *args, __unused u_int idx, + __unused char **cause) +{ + return (ARGS_PARSE_COMMANDS_OR_STRING); +} + static enum cmd_retval cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item) { diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 737c44c7..820053ec 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -169,11 +169,13 @@ static int cmd_command_prompt_callback(struct client *c, void *data, const char *s, int done) { - struct cmd_command_prompt_cdata *cdata = data; - char *error; - struct cmdq_item *item = cdata->item, *new_item; - struct cmd_list *cmdlist; - struct cmd_command_prompt_prompt *prompt; + struct cmd_command_prompt_cdata *cdata = data; + char *error; + struct cmdq_item *item = cdata->item, *new_item; + struct cmd_list *cmdlist; + struct cmd_command_prompt_prompt *prompt; + int argc = 0; + char **argv = NULL; if (s == NULL) goto out; @@ -181,7 +183,6 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s, if (cdata->flags & PROMPT_INCREMENTAL) goto out; - cmd_append_argv(&cdata->argc, &cdata->argv, s); if (++cdata->current != cdata->count) { prompt = &cdata->prompts[cdata->current]; status_prompt_update(c, prompt->prompt, prompt->input); @@ -189,8 +190,15 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s, } } - cmdlist = args_make_commands(cdata->state, cdata->argc, cdata->argv, - &error); + argc = cdata->argc; + argv = cmd_copy_argv(cdata->argc, cdata->argv); + cmd_append_argv(&argc, &argv, s); + if (done) { + cdata->argc = argc; + cdata->argv = cmd_copy_argv(argc, argv); + } + + cmdlist = args_make_commands(cdata->state, argc, argv, &error); if (cmdlist == NULL) { cmdq_append(c, cmdq_get_error(error)); free(error); @@ -201,6 +209,7 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s, new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); cmdq_insert_after(item, new_item); } + cmd_free_argv(argc, argv); if (c->prompt_inputcb != cmd_command_prompt_callback) return (1); diff --git a/cmd-display-menu.c b/cmd-display-menu.c index 4c5fb510..1a11bd01 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -407,7 +407,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) shell = _PATH_BSHELL; cmd_append_argv(&argc, &argv, shell); } else - args_vector(args, &argc, &argv); + args_to_vector(args, &argc, &argv); if (args_has(args, 'E') > 1) flags |= POPUP_CLOSEEXITZERO; diff --git a/cmd-new-session.c b/cmd-new-session.c index 93c7e7b4..cb9abfb3 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -42,7 +42,8 @@ const struct cmd_entry cmd_new_session_entry = { .args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1, NULL }, .usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] " "[-f flags] [-n window-name] [-s session-name] " - CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", + CMD_TARGET_SESSION_USAGE " [-x width] [-y height] " + "[shell-command]", .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, @@ -283,7 +284,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) sc.tc = c; sc.name = args_get(args, 'n'); - args_vector(args, &sc.argc, &sc.argv); + args_to_vector(args, &sc.argc, &sc.argv); sc.idx = -1; sc.cwd = args_get(args, 'c'); diff --git a/cmd-new-window.c b/cmd-new-window.c index e88795c2..e7f0868f 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -40,7 +40,7 @@ const struct cmd_entry cmd_new_window_entry = { .args = { "abc:de:F:kn:PSt:", 0, -1, NULL }, .usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] " - "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]", + "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [shell-command]", .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX }, @@ -105,7 +105,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) sc.tc = tc; sc.name = args_get(args, 'n'); - args_vector(args, &sc.argc, &sc.argv); + args_to_vector(args, &sc.argc, &sc.argv); sc.environ = environ_create(); av = args_first_value(args, 'e'); diff --git a/cmd-parse.y b/cmd-parse.y index a08c5819..2b5b7e0b 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -44,13 +44,15 @@ struct cmd_parse_scope { enum cmd_parse_argument_type { CMD_PARSE_STRING, - CMD_PARSE_COMMANDS + CMD_PARSE_COMMANDS, + CMD_PARSE_PARSED_COMMANDS }; struct cmd_parse_argument { enum cmd_parse_argument_type type; char *string; struct cmd_parse_commands *commands; + struct cmd_list *cmdlist; TAILQ_ENTRY(cmd_parse_argument) entry; }; @@ -608,6 +610,9 @@ cmd_parse_free_argument(struct cmd_parse_argument *arg) case CMD_PARSE_COMMANDS: cmd_parse_free_commands(arg->commands); break; + case CMD_PARSE_PARSED_COMMANDS: + cmd_list_free(arg->cmdlist); + break; } free(arg); } @@ -723,6 +728,11 @@ cmd_parse_log_commands(struct cmd_parse_commands *cmds, const char *prefix) cmd_parse_log_commands(arg->commands, s); free(s); break; + case CMD_PARSE_PARSED_COMMANDS: + s = cmd_list_print(arg->cmdlist, 0); + log_debug("%s %u:%u: %s", prefix, i, j, s); + free(s); + break; } j++; } @@ -818,6 +828,11 @@ cmd_parse_build_command(struct cmd_parse_command *cmd, values[count].type = ARGS_COMMANDS; values[count].cmdlist = pr->cmdlist; break; + case CMD_PARSE_PARSED_COMMANDS: + values[count].type = ARGS_COMMANDS; + values[count].cmdlist = arg->cmdlist; + values[count].cmdlist->references++; + break; } count++; } @@ -1023,39 +1038,19 @@ cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi) return (&pr); } -static void -cmd_parse_add_command(struct cmd_parse_commands *cmds, - struct cmd_parse_input *pi, int argc, char **argv) +struct cmd_parse_result * +cmd_parse_from_arguments(struct args_value *values, u_int count, + struct cmd_parse_input *pi) { + static struct cmd_parse_result pr; + struct cmd_parse_input input; + struct cmd_parse_commands *cmds; struct cmd_parse_command *cmd; struct cmd_parse_argument *arg; - int i; - - cmd_log_argv(argc, argv, "%s", __func__); - - cmd = xcalloc(1, sizeof *cmd); - cmd->line = pi->line; - - TAILQ_INIT(&cmd->arguments); - for (i = 0; i < argc; i++) { - arg = xcalloc(1, sizeof *arg); - arg->type = CMD_PARSE_STRING; - arg->string = xstrdup(argv[i]); - TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry); - } - - TAILQ_INSERT_TAIL(cmds, cmd, entry); -} - -struct cmd_parse_result * -cmd_parse_from_arguments(int argc, char **argv, struct cmd_parse_input *pi) -{ - static struct cmd_parse_result pr; - struct cmd_parse_input input; - struct cmd_parse_commands *cmds; - char **copy, **new_argv; - size_t size; - int i, last, new_argc; + u_int i; + char *copy; + size_t size; + int end; /* * The commands are already split up into arguments, so just separate @@ -1066,40 +1061,51 @@ cmd_parse_from_arguments(int argc, char **argv, struct cmd_parse_input *pi) memset(&input, 0, sizeof input); pi = &input; } - cmd_log_argv(argc, argv, "%s", __func__); cmds = cmd_parse_new_commands(); - copy = cmd_copy_argv(argc, argv); - last = 0; - for (i = 0; i < argc; i++) { - size = strlen(copy[i]); - if (size == 0 || copy[i][size - 1] != ';') - continue; - copy[i][--size] = '\0'; - if (size > 0 && copy[i][size - 1] == '\\') { - copy[i][size - 1] = ';'; - continue; + cmd = xcalloc(1, sizeof *cmd); + cmd->line = pi->line; + TAILQ_INIT(&cmd->arguments); + + for (i = 0; i < count; i++) { + end = 0; + if (values[i].type == ARGS_STRING) { + copy = xstrdup(values[i].string); + size = strlen(copy); + if (size != 0 && copy[size - 1] == ';') { + copy[--size] = '\0'; + if (size > 0 && copy[size - 1] == '\\') + copy[size - 1] = ';'; + else + end = 1; + } + if (!end || size != 0) { + arg = xcalloc(1, sizeof *arg); + arg->type = CMD_PARSE_STRING; + arg->string = copy; + TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry); + } + } else if (values[i].type == ARGS_COMMANDS) { + arg = xcalloc(1, sizeof *arg); + arg->type = CMD_PARSE_PARSED_COMMANDS; + arg->cmdlist = values[i].cmdlist; + arg->cmdlist->references++; + TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry); + } else + fatalx("unknown argument type"); + if (end) { + TAILQ_INSERT_TAIL(cmds, cmd, entry); + cmd = xcalloc(1, sizeof *cmd); + cmd->line = pi->line; + TAILQ_INIT(&cmd->arguments); } - - new_argc = i - last; - new_argv = copy + last; - if (size != 0) - new_argc++; - - if (new_argc != 0) - cmd_parse_add_command(cmds, pi, new_argc, new_argv); - last = i + 1; } - if (last != argc) { - new_argv = copy + last; - new_argc = argc - last; + if (!TAILQ_EMPTY(&cmd->arguments)) + TAILQ_INSERT_TAIL(cmds, cmd, entry); + else + free(cmd); - if (new_argc != 0) - cmd_parse_add_command(cmds, pi, new_argc, new_argv); - } - - cmd_free_argv(argc, copy); cmd_parse_build_commands(cmds, pi, &pr); cmd_parse_free_commands(cmds); return (&pr); diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 24a49dcb..821558ae 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -77,6 +77,58 @@ out: free(copy); } +static enum cmd_retval +cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item) +{ + struct args *args = cmd_get_args(self); + struct client *tc = cmdq_get_target_client(item); + const char *size = args_get(args, 'C'); + u_int w, x, y; + struct client_window *cw; + + if (sscanf(size, "@%u:%ux%u", &w, &x, &y) == 3) { + if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM || + y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) { + cmdq_error(item, "size too small or too big"); + return (CMD_RETURN_ERROR); + } + log_debug("%s: client %s window @%u: size %ux%u", __func__, + tc->name, w, x, y); + cw = server_client_add_client_window(tc, w); + cw->sx = x; + cw->sy = y; + tc->flags |= CLIENT_WINDOWSIZECHANGED; + recalculate_sizes_now(1); + return (CMD_RETURN_NORMAL); + } + if (sscanf(size, "@%u:", &w) == 1) { + cw = server_client_get_client_window(tc, w); + if (cw != NULL) { + log_debug("%s: client %s window @%u: no size", __func__, + tc->name, w); + cw->sx = 0; + cw->sy = 0; + recalculate_sizes_now(1); + } + return (CMD_RETURN_NORMAL); + } + + if (sscanf(size, "%u,%u", &x, &y) != 2 && + sscanf(size, "%ux%u", &x, &y) != 2) { + cmdq_error(item, "bad size argument"); + return (CMD_RETURN_ERROR); + } + if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM || + y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) { + cmdq_error(item, "size too small or too big"); + return (CMD_RETURN_ERROR); + } + tty_set_size(&tc->tty, x, y, 0, 0); + tc->flags |= CLIENT_SIZECHANGED; + recalculate_sizes_now(1); + return (CMD_RETURN_NORMAL); +} + static void cmd_refresh_client_update_offset(struct client *tc, const char *value) { @@ -117,8 +169,8 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) struct client *tc = cmdq_get_target_client(item); struct tty *tty = &tc->tty; struct window *w; - const char *size, *errstr; - u_int x, y, adjust; + const char *errstr; + u_int adjust; struct args_value *av; if (args_has(args, 'c') || @@ -205,21 +257,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) if (args_has(args, 'C')) { if (~tc->flags & CLIENT_CONTROL) goto not_control_client; - size = args_get(args, 'C'); - if (sscanf(size, "%u,%u", &x, &y) != 2 && - sscanf(size, "%ux%u", &x, &y) != 2) { - cmdq_error(item, "bad size argument"); - return (CMD_RETURN_ERROR); - } - if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM || - y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) { - cmdq_error(item, "size too small or too big"); - return (CMD_RETURN_ERROR); - } - tty_set_size(&tc->tty, x, y, 0, 0); - tc->flags |= CLIENT_SIZECHANGED; - recalculate_sizes_now(1); - return (CMD_RETURN_NORMAL); + return (cmd_refresh_client_control_client_size(self, item)); } if (args_has(args, 'S')) { diff --git a/cmd-resize-window.c b/cmd-resize-window.c index 24d73c87..ad739165 100644 --- a/cmd-resize-window.c +++ b/cmd-resize-window.c @@ -108,7 +108,9 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item) } options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL); - resize_window(w, sx, sy, xpixel, ypixel); + w->manual_sx = sx; + w->manual_sy = sy; + recalculate_size(w, 1); return (CMD_RETURN_NORMAL); } diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 652ef755..6d60002e 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_pane_entry = { .args = { "c:e:kt:", 0, -1, NULL }, .usage = "[-k] [-c start-directory] [-e environment] " - CMD_TARGET_PANE_USAGE " [command]", + CMD_TARGET_PANE_USAGE " [shell-command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -61,10 +61,8 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) sc.wl = wl; sc.wp0 = wp; - sc.lc = NULL; - sc.name = NULL; - args_vector(args, &sc.argc, &sc.argv); + args_to_vector(args, &sc.argc, &sc.argv); sc.environ = environ_create(); av = args_first_value(args, 'e'); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 4e6dc2a9..9a1a02c9 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_window_entry = { .args = { "c:e:kt:", 0, -1, NULL }, .usage = "[-k] [-c start-directory] [-e environment] " - CMD_TARGET_WINDOW_USAGE " [command]", + CMD_TARGET_WINDOW_USAGE " [shell-command]", .target = { 't', CMD_FIND_WINDOW, 0 }, @@ -61,8 +61,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) sc.wl = wl; sc.tc = tc; - sc.name = NULL; - args_vector(args, &sc.argc, &sc.argv); + args_to_vector(args, &sc.argc, &sc.argv); sc.environ = environ_create(); av = args_first_value(args, 'e'); diff --git a/cmd-split-window.c b/cmd-split-window.c index 109c587b..74c8b5ab 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -41,7 +41,8 @@ const struct cmd_entry cmd_split_window_entry = { .args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL }, .usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " - "[-F format] [-l size] " CMD_TARGET_PANE_USAGE " [command]", + "[-F format] [-l size] " CMD_TARGET_PANE_USAGE + "[shell-command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -135,8 +136,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) sc.wp0 = wp; sc.lc = lc; - sc.name = NULL; - args_vector(args, &sc.argc, &sc.argv); + args_to_vector(args, &sc.argc, &sc.argv); sc.environ = environ_create(); av = args_first_value(args, 'e'); diff --git a/cmd.c b/cmd.c index 4b1dbbbf..44952d11 100644 --- a/cmd.c +++ b/cmd.c @@ -543,6 +543,23 @@ cmd_free(struct cmd *cmd) free(cmd); } +/* Copy a command. */ +struct cmd * +cmd_copy(struct cmd *cmd, int argc, char **argv) +{ + struct cmd *new_cmd; + + new_cmd = xcalloc(1, sizeof *new_cmd); + new_cmd->entry = cmd->entry; + new_cmd->args = args_copy(cmd->args, argc, argv); + + if (cmd->file != NULL) + new_cmd->file = xstrdup(cmd->file); + new_cmd->line = cmd->line; + + return (new_cmd); +} + /* Get a command as a string. */ char * cmd_print(struct cmd *cmd) @@ -617,6 +634,37 @@ cmd_list_free(struct cmd_list *cmdlist) free(cmdlist); } +/* Copy a command list, expanding %s in arguments. */ +struct cmd_list * +cmd_list_copy(struct cmd_list *cmdlist, int argc, char **argv) +{ + struct cmd *cmd; + struct cmd_list *new_cmdlist; + struct cmd *new_cmd; + u_int group = cmdlist->group; + char *s; + + s = cmd_list_print(cmdlist, 0); + log_debug("%s: %s", __func__, s); + free(s); + + new_cmdlist = cmd_list_new(); + TAILQ_FOREACH(cmd, cmdlist->list, qentry) { + if (cmd->group != group) { + new_cmdlist->group = cmd_list_next_group++; + group = cmd->group; + } + new_cmd = cmd_copy(cmd, argc, argv); + cmd_list_append(new_cmdlist, new_cmd); + } + + s = cmd_list_print(new_cmdlist, 0); + log_debug("%s: %s", __func__, s); + free(s); + + return (new_cmdlist); +} + /* Get a command list as a string. */ char * cmd_list_print(struct cmd_list *cmdlist, int escaped) diff --git a/key-bindings.c b/key-bindings.c index 66e1ec9f..9f7e734a 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -29,7 +29,7 @@ " 'Previous' 'p' {switch-client -p}" \ " ''" \ " 'Renumber' 'N' {move-window -r}" \ - " 'Rename' 'n' {command-prompt -I \"#S\" \"rename-session -- '%%'\"}" \ + " 'Rename' 'n' {command-prompt -I \"#S\" {rename-session -- '%%'}}" \ " ''" \ " 'New Session' 's' {new-session}" \ " 'New Window' 'w' {new-window}" @@ -41,7 +41,7 @@ " 'Kill' 'X' {kill-window}" \ " 'Respawn' 'R' {respawn-window -k}" \ " '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \ - " 'Rename' 'n' {command-prompt -FI \"#W\" \"rename-window -t#{window_id} -- '%%'\"}" \ + " 'Rename' 'n' {command-prompt -FI \"#W\" {rename-window -t '#{window_id}' -- '%%'}}" \ " ''" \ " 'New After' 'w' {new-window -a}" \ " 'New At End' 'W' {new-window}" @@ -350,16 +350,16 @@ key_bindings_init(void) "bind -N 'Break pane to a new window' ! { break-pane }", "bind -N 'Split window vertically' '\"' { split-window }", "bind -N 'List all paste buffers' '#' { list-buffers }", - "bind -N 'Rename current session' '$' { command-prompt -I'#S' \"rename-session -- '%%'\" }", + "bind -N 'Rename current session' '$' { command-prompt -I'#S' { rename-session -- '%%' } }", "bind -N 'Split window horizontally' % { split-window -h }", "bind -N 'Kill current window' & { confirm-before -p\"kill-window #W? (y/n)\" kill-window }", - "bind -N 'Prompt for window index to select' \"'\" { command-prompt -T window-target -pindex \"select-window -t ':%%'\" }", + "bind -N 'Prompt for window index to select' \"'\" { command-prompt -T window-target -pindex { select-window -t ':%%' } }", "bind -N 'Switch to previous client' ( { switch-client -p }", "bind -N 'Switch to next client' ) { switch-client -n }", - "bind -N 'Rename current window' , { command-prompt -I'#W' \"rename-window -- '%%'\" }", + "bind -N 'Rename current window' , { command-prompt -I'#W' { rename-window -- '%%' } }", "bind -N 'Delete the most recent paste buffer' - { delete-buffer }", - "bind -N 'Move the current window' . { command-prompt -T target \"move-window -t '%%'\" }", - "bind -N 'Describe key binding' '/' { command-prompt -kpkey 'list-keys -1N \"%%%\"' }", + "bind -N 'Move the current window' . { command-prompt -T target { move-window -t '%%' } }", + "bind -N 'Describe key binding' '/' { command-prompt -kpkey { list-keys -1N '%%' } }", "bind -N 'Select window 0' 0 { select-window -t:=0 }", "bind -N 'Select window 1' 1 { select-window -t:=1 }", "bind -N 'Select window 2' 2 { select-window -t:=2 }", @@ -382,7 +382,7 @@ key_bindings_init(void) "bind -N 'Paste the most recent paste buffer' ] { paste-buffer -p }", "bind -N 'Create a new window' c { new-window }", "bind -N 'Detach the current client' d { detach-client }", - "bind -N 'Search for a pane' f { command-prompt \"find-window -Z -- '%%'\" }", + "bind -N 'Search for a pane' f { command-prompt { find-window -Z -- '%%' } }", "bind -N 'Display window information' i { display-message }", "bind -N 'Select the previously current window' l { last-window }", "bind -N 'Toggle the marked pane' m { select-pane -m }", @@ -482,25 +482,25 @@ key_bindings_init(void) "bind -Tcopy-mode C-k { send -X copy-pipe-end-of-line-and-cancel }", "bind -Tcopy-mode C-n { send -X cursor-down }", "bind -Tcopy-mode C-p { send -X cursor-up }", - "bind -Tcopy-mode C-r { command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' 'send -X search-backward-incremental \"%%%\"' }", - "bind -Tcopy-mode C-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' 'send -X search-forward-incremental \"%%%\"' }", + "bind -Tcopy-mode C-r { command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental '%%' } }", + "bind -Tcopy-mode C-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental '%%' } }", "bind -Tcopy-mode C-v { send -X page-down }", "bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }", "bind -Tcopy-mode Escape { send -X cancel }", "bind -Tcopy-mode Space { send -X page-down }", "bind -Tcopy-mode , { send -X jump-reverse }", "bind -Tcopy-mode \\; { send -X jump-again }", - "bind -Tcopy-mode F { command-prompt -1p'(jump backward)' 'send -X jump-backward \"%%%\"' }", + "bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }", "bind -Tcopy-mode N { send -X search-reverse }", "bind -Tcopy-mode R { send -X rectangle-toggle }", - "bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' 'send -X jump-to-backward \"%%%\"' }", + "bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }", "bind -Tcopy-mode X { send -X set-mark }", - "bind -Tcopy-mode f { command-prompt -1p'(jump forward)' 'send -X jump-forward \"%%%\"' }", - "bind -Tcopy-mode g { command-prompt -p'(goto line)' 'send -X goto-line \"%%%\"' }", + "bind -Tcopy-mode f { command-prompt -1p'(jump forward)' { send -X jump-forward '%%' } }", + "bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line '%%' } }", "bind -Tcopy-mode n { send -X search-again }", "bind -Tcopy-mode q { send -X cancel }", "bind -Tcopy-mode r { send -X refresh-from-pane }", - "bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' 'send -X jump-to-forward \"%%%\"' }", + "bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward '%%' } }", "bind -Tcopy-mode Home { send -X start-of-line }", "bind -Tcopy-mode End { send -X end-of-line }", "bind -Tcopy-mode MouseDown1Pane select-pane", @@ -516,15 +516,15 @@ key_bindings_init(void) "bind -Tcopy-mode Down { send -X cursor-down }", "bind -Tcopy-mode Left { send -X cursor-left }", "bind -Tcopy-mode Right { send -X cursor-right }", - "bind -Tcopy-mode M-1 { command-prompt -Np'(repeat)' -I1 'send -N \"%%%\"' }", - "bind -Tcopy-mode M-2 { command-prompt -Np'(repeat)' -I2 'send -N \"%%%\"' }", - "bind -Tcopy-mode M-3 { command-prompt -Np'(repeat)' -I3 'send -N \"%%%\"' }", - "bind -Tcopy-mode M-4 { command-prompt -Np'(repeat)' -I4 'send -N \"%%%\"' }", - "bind -Tcopy-mode M-5 { command-prompt -Np'(repeat)' -I5 'send -N \"%%%\"' }", - "bind -Tcopy-mode M-6 { command-prompt -Np'(repeat)' -I6 'send -N \"%%%\"' }", - "bind -Tcopy-mode M-7 { command-prompt -Np'(repeat)' -I7 'send -N \"%%%\"' }", - "bind -Tcopy-mode M-8 { command-prompt -Np'(repeat)' -I8 'send -N \"%%%\"' }", - "bind -Tcopy-mode M-9 { command-prompt -Np'(repeat)' -I9 'send -N \"%%%\"' }", + "bind -Tcopy-mode M-1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }", + "bind -Tcopy-mode M-2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }", + "bind -Tcopy-mode M-3 { command-prompt -Np'(repeat)' -I3 { send -N '%%' } }", + "bind -Tcopy-mode M-4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }", + "bind -Tcopy-mode M-5 { command-prompt -Np'(repeat)' -I5 { send -N '%%' } }", + "bind -Tcopy-mode M-6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }", + "bind -Tcopy-mode M-7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }", + "bind -Tcopy-mode M-8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }", + "bind -Tcopy-mode M-9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }", "bind -Tcopy-mode M-< { send -X history-top }", "bind -Tcopy-mode M-> { send -X history-bottom }", "bind -Tcopy-mode M-R { send -X top-line }", @@ -562,25 +562,25 @@ key_bindings_init(void) "bind -Tcopy-mode-vi Space { send -X begin-selection }", "bind -Tcopy-mode-vi '$' { send -X end-of-line }", "bind -Tcopy-mode-vi , { send -X jump-reverse }", - "bind -Tcopy-mode-vi / { command-prompt -T search -p'(search down)' 'send -X search-forward \"%%%\"' }", + "bind -Tcopy-mode-vi / { command-prompt -T search -p'(search down)' { send -X search-forward '%%' } }", "bind -Tcopy-mode-vi 0 { send -X start-of-line }", - "bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi 3 { command-prompt -Np'(repeat)' -I3 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi 4 { command-prompt -Np'(repeat)' -I4 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi 5 { command-prompt -Np'(repeat)' -I5 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi 6 { command-prompt -Np'(repeat)' -I6 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 'send -N \"%%%\"' }", - "bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' 'send -X goto-line \"%%%\"' }", + "bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }", + "bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }", + "bind -Tcopy-mode-vi 3 { command-prompt -Np'(repeat)' -I3 { send -N '%%' } }", + "bind -Tcopy-mode-vi 4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }", + "bind -Tcopy-mode-vi 5 { command-prompt -Np'(repeat)' -I5 { send -N '%%' } }", + "bind -Tcopy-mode-vi 6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }", + "bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }", + "bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }", + "bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }", + "bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' { send -X goto-line '%%' } }", "bind -Tcopy-mode-vi \\; { send -X jump-again }", - "bind -Tcopy-mode-vi ? { command-prompt -T search -p'(search up)' 'send -X search-backward \"%%%\"' }", + "bind -Tcopy-mode-vi ? { command-prompt -T search -p'(search up)' { send -X search-backward '%%' } }", "bind -Tcopy-mode-vi A { send -X append-selection-and-cancel }", "bind -Tcopy-mode-vi B { send -X previous-space }", "bind -Tcopy-mode-vi D { send -X copy-pipe-end-of-line-and-cancel }", "bind -Tcopy-mode-vi E { send -X next-space-end }", - "bind -Tcopy-mode-vi F { command-prompt -1p'(jump backward)' 'send -X jump-backward \"%%%\"' }", + "bind -Tcopy-mode-vi F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }", "bind -Tcopy-mode-vi G { send -X history-bottom }", "bind -Tcopy-mode-vi H { send -X top-line }", "bind -Tcopy-mode-vi J { send -X scroll-down }", @@ -588,14 +588,14 @@ key_bindings_init(void) "bind -Tcopy-mode-vi L { send -X bottom-line }", "bind -Tcopy-mode-vi M { send -X middle-line }", "bind -Tcopy-mode-vi N { send -X search-reverse }", - "bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' 'send -X jump-to-backward \"%%%\"' }", + "bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }", "bind -Tcopy-mode-vi V { send -X select-line }", "bind -Tcopy-mode-vi W { send -X next-space }", "bind -Tcopy-mode-vi X { send -X set-mark }", "bind -Tcopy-mode-vi ^ { send -X back-to-indentation }", "bind -Tcopy-mode-vi b { send -X previous-word }", "bind -Tcopy-mode-vi e { send -X next-word-end }", - "bind -Tcopy-mode-vi f { command-prompt -1p'(jump forward)' 'send -X jump-forward \"%%%\"' }", + "bind -Tcopy-mode-vi f { command-prompt -1p'(jump forward)' { send -X jump-forward '%%' } }", "bind -Tcopy-mode-vi g { send -X history-top }", "bind -Tcopy-mode-vi h { send -X cursor-left }", "bind -Tcopy-mode-vi j { send -X cursor-down }", @@ -605,7 +605,7 @@ key_bindings_init(void) "bind -Tcopy-mode-vi o { send -X other-end }", "bind -Tcopy-mode-vi q { send -X cancel }", "bind -Tcopy-mode-vi r { send -X refresh-from-pane }", - "bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' 'send -X jump-to-forward \"%%%\"' }", + "bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward '%%' } }", "bind -Tcopy-mode-vi v { send -X rectangle-toggle }", "bind -Tcopy-mode-vi w { send -X next-word }", "bind -Tcopy-mode-vi '{' { send -X previous-paragraph }", diff --git a/resize.c b/resize.c index f321e7d2..8416ad6a 100644 --- a/resize.c +++ b/resize.c @@ -87,7 +87,9 @@ ignore_client_size(struct client *c) return (1); } } - if ((c->flags & CLIENT_CONTROL) && (~c->flags & CLIENT_SIZECHANGED)) + if ((c->flags & CLIENT_CONTROL) && + (~c->flags & CLIENT_SIZECHANGED) && + (~c->flags & CLIENT_WINDOWSIZECHANGED)) return (1); return (0); } @@ -113,23 +115,25 @@ clients_calculate_size(int type, int current, struct client *c, int, int, struct session *, struct window *), u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel) { - struct client *loop; - u_int cx, cy, n = 0; - - /* Manual windows do not have their size changed based on a client. */ - if (type == WINDOW_SIZE_MANUAL) { - log_debug("%s: type is manual", __func__); - return (0); - } + struct client *loop; + struct client_window *cw; + u_int cx, cy, n = 0; /* * Start comparing with 0 for largest and UINT_MAX for smallest or * latest. */ - if (type == WINDOW_SIZE_LARGEST) - *sx = *sy = 0; - else - *sx = *sy = UINT_MAX; + if (type == WINDOW_SIZE_LARGEST) { + *sx = 0; + *sy = 0; + } else if (type == WINDOW_SIZE_MANUAL) { + *sx = w->manual_sx; + *sy = w->manual_sy; + log_debug("%s: manual size %ux%u", __func__, *sx, *sy); + } else { + *sx = UINT_MAX; + *sy = UINT_MAX; + } *xpixel = *ypixel = 0; /* @@ -139,14 +143,18 @@ clients_calculate_size(int type, int current, struct client *c, if (type == WINDOW_SIZE_LATEST && w != NULL) n = clients_with_window(w); + /* Skip setting the size if manual */ + if (type == WINDOW_SIZE_MANUAL) + goto skip; + /* Loop over the clients and work out the size. */ TAILQ_FOREACH(loop, &clients, entry) { if (loop != c && ignore_client_size(loop)) { - log_debug("%s: ignoring %s", __func__, loop->name); + log_debug("%s: ignoring %s (1)", __func__, loop->name); continue; } if (loop != c && skip_client(loop, type, current, s, w)) { - log_debug("%s: skipping %s", __func__, loop->name); + log_debug("%s: skipping %s (1)", __func__, loop->name); continue; } @@ -160,9 +168,23 @@ clients_calculate_size(int type, int current, struct client *c, continue; } + /* + * If the client has a per-window size, use this instead if it is + * smaller. + */ + if (w != NULL) + cw = server_client_get_client_window(loop, w->id); + else + cw = NULL; + /* Work out this client's size. */ - cx = loop->tty.sx; - cy = loop->tty.sy - status_line_size(loop); + if (cw != NULL) { + cx = cw->sx; + cy = cw->sy; + } else { + cx = loop->tty.sx; + cy = loop->tty.sy - status_line_size(loop); + } /* * If it is larger or smaller than the best so far, update the @@ -191,7 +213,44 @@ clients_calculate_size(int type, int current, struct client *c, else log_debug("%s: no calculated size", __func__); +skip: + /* + * Do not allow any size to be larger than the per-client window size + * if one exists. + */ + if (w != NULL) { + TAILQ_FOREACH(loop, &clients, entry) { + if (loop != c && ignore_client_size(loop)) + continue; + if (loop != c && skip_client(loop, type, current, s, w)) + continue; + + /* Look up per-window size if any. */ + if (~loop->flags & CLIENT_WINDOWSIZECHANGED) + continue; + cw = server_client_get_client_window(loop, w->id); + if (cw == NULL) + continue; + + /* Clamp the size. */ + log_debug("%s: %s size for @%u is %ux%u", __func__, + loop->name, w->id, cw->sx, cw->sy); + if (cw->sx != 0 && *sx > cw->sx) + *sx = cw->sx; + if (cw->sy != 0 && *sy > cw->sy) + *sy = cw->sy; + } + } + if (*sx != UINT_MAX && *sy != UINT_MAX) + log_debug("%s: calculated size %ux%u", __func__, *sx, *sy); + else + log_debug("%s: no calculated size", __func__); + /* Return whether a suitable size was found. */ + if (type == WINDOW_SIZE_MANUAL) { + log_debug("%s: type is manual", __func__); + return (1); + } if (type == WINDOW_SIZE_LARGEST) { log_debug("%s: type is largest", __func__); return (*sx != 0 && *sy != 0); diff --git a/server-client.c b/server-client.c index 3efee844..1290c2a6 100644 --- a/server-client.c +++ b/server-client.c @@ -2121,6 +2121,7 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) int argc; char **argv, *cause; struct cmd_parse_result *pr; + struct args_value *values; if (c->flags & CLIENT_EXIT) return; @@ -2146,7 +2147,8 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) *argv = xstrdup("new-session"); } - pr = cmd_parse_from_arguments(argc, argv, NULL); + values = args_from_vector(argc, argv); + pr = cmd_parse_from_arguments(values, argc, NULL); switch (pr->status) { case CMD_PARSE_ERROR: cause = pr->error; @@ -2154,6 +2156,8 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) case CMD_PARSE_SUCCESS: break; } + args_free_values(values, argc); + free(values); cmd_free_argv(argc, argv); cmdq_append(c, cmdq_get_command(pr->cmdlist, NULL)); @@ -2444,7 +2448,7 @@ server_client_get_flags(struct client *c) } /* Get client window. */ -static struct client_window * +struct client_window * server_client_get_client_window(struct client *c, u_int id) { struct client_window cw = { .window = id }; @@ -2452,6 +2456,21 @@ server_client_get_client_window(struct client *c, u_int id) return (RB_FIND(client_windows, &c->windows, &cw)); } +/* Add client window. */ +struct client_window * +server_client_add_client_window(struct client *c, u_int id) +{ + struct client_window *cw; + + cw = server_client_get_client_window(c, id); + if (cw == NULL) { + cw = xcalloc(1, sizeof *cw); + cw->window = id; + RB_INSERT(client_windows, &c->windows, cw); + } + return cw; +} + /* Get client active pane. */ struct window_pane * server_client_get_pane(struct client *c) @@ -2480,12 +2499,7 @@ server_client_set_pane(struct client *c, struct window_pane *wp) if (s == NULL) return; - cw = server_client_get_client_window(c, s->curw->window->id); - if (cw == NULL) { - cw = xcalloc(1, sizeof *cw); - cw->window = s->curw->window->id; - RB_INSERT(client_windows, &c->windows, cw); - } + cw = server_client_add_client_window(c, s->curw->window->id); cw->pane = wp; log_debug("%s pane now %%%u", c->name, wp->id); } diff --git a/tmux.1 b/tmux.1 index 2f5ac243..b8e96984 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1331,7 +1331,7 @@ specified multiple times. .Op Fl cDlLRSU .Op Fl A Ar pane:state .Op Fl B Ar name:what:format -.Op Fl C Ar XxY +.Op Fl C Ar size .Op Fl f Ar flags .Op Fl t Ar target-client .Op Ar adjustment @@ -1375,7 +1375,17 @@ window, changing the current window in the attached session will reset it. .Pp .Fl C -sets the width and height of a control mode client. +sets the width and height of a control mode client or of a window for a +control mode client, +.Ar size +must be one of +.Ql widthxheight +or +.Ql window ID:widthxheight , +for example +.Ql 80x24 +or +.Ql @0:80x24 . .Fl A allows a control mode client to trigger actions on a pane. The argument is a pane ID (with leading diff --git a/tmux.h b/tmux.h index e363fc75..c95daa46 100644 --- a/tmux.h +++ b/tmux.h @@ -999,6 +999,8 @@ struct window { u_int sx; u_int sy; + u_int manual_sx; + u_int manual_sy; u_int xpixel; u_int ypixel; @@ -1556,6 +1558,10 @@ RB_HEAD(client_files, client_file); struct client_window { u_int window; struct window_pane *pane; + + u_int sx; + u_int sy; + RB_ENTRY(client_window) entry; }; RB_HEAD(client_windows, client_window); @@ -1651,6 +1657,7 @@ struct client { #define CLIENT_ACTIVEPANE 0x80000000ULL #define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL #define CLIENT_CONTROL_WAITEXIT 0x200000000ULL +#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL #define CLIENT_ALLREDRAWFLAGS \ (CLIENT_REDRAWWINDOW| \ CLIENT_REDRAWSTATUS| \ @@ -2211,8 +2218,11 @@ void args_set(struct args *, u_char, struct args_value *); struct args *args_create(void); struct args *args_parse(const struct args_parse *, struct args_value *, u_int, char **); -void args_vector(struct args *, int *, char ***); +struct args *args_copy(struct args *, int, char **); +void args_to_vector(struct args *, int *, char ***); +struct args_value *args_from_vector(int, char **); void args_free_value(struct args_value *); +void args_free_values(struct args_value *, u_int); void args_free(struct args *); char *args_print(struct args *); char *args_escape(const char *); @@ -2221,6 +2231,7 @@ const char *args_get(struct args *, u_char); u_char args_first(struct args *, struct args_entry **); u_char args_next(struct args_entry **); u_int args_count(struct args *); +struct args_value *args_values(struct args *); struct args_value *args_value(struct args *, u_int); const char *args_string(struct args *, u_int); struct cmd_list *args_make_commands_now(struct cmd *, struct cmdq_item *, @@ -2285,9 +2296,11 @@ u_int cmd_get_group(struct cmd *); void cmd_get_source(struct cmd *, const char **, u_int *); struct cmd *cmd_parse(struct args_value *, u_int, const char *, u_int, char **); +struct cmd *cmd_copy(struct cmd *, int, char **); void cmd_free(struct cmd *); char *cmd_print(struct cmd *); struct cmd_list *cmd_list_new(void); +struct cmd_list *cmd_list_copy(struct cmd_list *, int, char **); void cmd_list_append(struct cmd_list *, struct cmd *); void cmd_list_append_all(struct cmd_list *, struct cmd_list *); void cmd_list_move(struct cmd_list *, struct cmd_list *); @@ -2321,7 +2334,7 @@ enum cmd_parse_status cmd_parse_and_append(const char *, struct cmdq_state *, char **); struct cmd_parse_result *cmd_parse_from_buffer(const void *, size_t, struct cmd_parse_input *); -struct cmd_parse_result *cmd_parse_from_arguments(int, char **, +struct cmd_parse_result *cmd_parse_from_arguments(struct args_value *, u_int, struct cmd_parse_input *); /* cmd-queue.c */ @@ -2466,6 +2479,8 @@ void server_client_push_stderr(struct client *); const char *server_client_get_cwd(struct client *, struct session *); void server_client_set_flags(struct client *, const char *); const char *server_client_get_flags(struct client *); +struct client_window *server_client_get_client_window(struct client *, u_int); +struct client_window *server_client_add_client_window(struct client *, u_int); struct window_pane *server_client_get_pane(struct client *); void server_client_set_pane(struct client *, struct window_pane *); void server_client_remove_pane(struct window_pane *); diff --git a/window.c b/window.c index 5e256874..ec9644bc 100644 --- a/window.c +++ b/window.c @@ -316,6 +316,8 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) w->sx = sx; w->sy = sy; + w->manual_sx = sx; + w->manual_sy = sy; w->xpixel = xpixel; w->ypixel = ypixel;