Replace %% in command lists (by copying them) for template arguments ,

this means they can be used with {} as well. Also make argument
processing from an existing vector preserve commands. GitHub issue 2858.
pull/2873/head
nicm 2021-08-27 17:25:55 +00:00
parent fd756a150b
commit daec63e5e6
16 changed files with 324 additions and 150 deletions

View File

@ -166,7 +166,7 @@ args_parse(const struct args_parse *parse, struct args_value *values,
} }
argument = *++found; argument = *++found;
if (argument != ':') { if (argument != ':') {
log_debug("%s: add -%c", __func__, flag); log_debug("%s: -%c", __func__, flag);
args_set(args, flag, NULL); args_set(args, flag, NULL);
continue; continue;
} }
@ -192,7 +192,7 @@ args_parse(const struct args_parse *parse, struct args_value *values,
args_copy_value(new, &values[i++]); args_copy_value(new, &values[i++]);
} }
s = args_value_as_string(new); 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); args_set(args, flag, new);
break; break;
} }
@ -203,7 +203,8 @@ args_parse(const struct args_parse *parse, struct args_value *values,
value = &values[i]; value = &values[i];
s = args_value_as_string(value); 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) { if (parse->cb != NULL) {
type = parse->cb(args, args->count, cause); type = parse->cb(args, args->count, cause);
@ -265,6 +266,63 @@ args_parse(const struct args_parse *parse, struct args_value *values,
return (args); 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. */ /* Free a value. */
void void
args_free_value(struct args_value *value) args_free_value(struct args_value *value)
@ -282,6 +340,16 @@ args_free_value(struct args_value *value)
free(value->cached); 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. */ /* Free an arguments set. */
void void
args_free(struct args *args) args_free(struct args *args)
@ -290,10 +358,8 @@ args_free(struct args *args)
struct args_entry *entry1; struct args_entry *entry1;
struct args_value *value; struct args_value *value;
struct args_value *value1; struct args_value *value1;
u_int i;
for (i = 0; i < args->count; i++) args_free_values(args->values, args->count);
args_free_value(&args->values[i]);
free(args->values); free(args->values);
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) { RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
@ -311,7 +377,7 @@ args_free(struct args *args)
/* Convert arguments to vector. */ /* Convert arguments to vector. */
void void
args_vector(struct args *args, int *argc, char ***argv) args_to_vector(struct args *args, int *argc, char ***argv)
{ {
char *s; char *s;
u_int i; 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. */ /* Add to string. */
static void printflike(3, 4) static void printflike(3, 4)
args_print_add(char **buf, size_t *len, const char *fmt, ...) args_print_add(char **buf, size_t *len, const char *fmt, ...)
@ -424,7 +505,7 @@ args_print(struct args *args)
char * char *
args_escape(const char *s) args_escape(const char *s)
{ {
static const char dquoted[] = " #';${}"; static const char dquoted[] = " #';${}%";
static const char squoted[] = " \""; static const char squoted[] = " \"";
char *escaped, *result; char *escaped, *result;
int flags, quotes = 0; int flags, quotes = 0;
@ -538,6 +619,13 @@ args_count(struct args *args)
return (args->count); return (args->count);
} }
/* Get argument values. */
struct args_value *
args_values(struct args *args)
{
return (args->values);
}
/* Get argument value. */ /* Get argument value. */
struct args_value * struct args_value *
args_value(struct args *args, u_int idx) 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); cmdq_error(item, "%s", error);
free(error); free(error);
} }
else else
cmdlist->references++; cmdlist->references++;
args_make_commands_free(state); args_make_commands_free(state);
return (cmdlist); return (cmdlist);
} }
@ -631,8 +719,11 @@ args_make_commands(struct args_command_state *state, int argc, char **argv,
char *cmd, *new_cmd; char *cmd, *new_cmd;
int i; int i;
if (state->cmdlist != NULL) if (state->cmdlist != NULL) {
return (state->cmdlist); if (argc == 0)
return (state->cmdlist);
return (cmd_list_copy(state->cmdlist, argc, argv));
}
cmd = xstrdup(state->cmd); cmd = xstrdup(state->cmd);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {

View File

@ -244,6 +244,7 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
ssize_t linelen; ssize_t linelen;
char *line = NULL, **caps = NULL, *cause; char *line = NULL, **caps = NULL, *cause;
u_int ncaps = 0; u_int ncaps = 0;
struct args_value *values;
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN); signal(SIGCHLD, SIG_IGN);
@ -259,17 +260,20 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
msg = MSG_COMMAND; msg = MSG_COMMAND;
/* /*
* It sucks parsing the command string twice (in client and * It's annoying parsing the command string twice (in client
* later in server) but it is necessary to get the start server * and later in server) but it is necessary to get the start
* flag. * 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 (pr->status == CMD_PARSE_SUCCESS) {
if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER)) if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
flags |= CLIENT_STARTSERVER; flags |= CLIENT_STARTSERVER;
cmd_list_free(pr->cmdlist); cmd_list_free(pr->cmdlist);
} else } else
free(pr->error); free(pr->error);
args_free_values(values, argc);
free(values);
} }
/* Create client process structure (starts logging). */ /* Create client process structure (starts logging). */

View File

@ -58,8 +58,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
key_code key; key_code key;
const char *tablename, *note = args_get(args, 'N'); const char *tablename, *note = args_get(args, 'N');
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
char **argv; int repeat;
int argc, repeat;
struct args_value *value; struct args_value *value;
u_int count = args_count(args); u_int count = args_count(args);
@ -92,9 +91,8 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
if (count == 2) if (count == 2)
pr = cmd_parse_from_string(args_string(args, 1), NULL); pr = cmd_parse_from_string(args_string(args, 1), NULL);
else { else {
args_vector(args, &argc, &argv); pr = cmd_parse_from_arguments(args_values(args) + 1, count - 1,
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL); NULL);
cmd_free_argv(argc, argv);
} }
switch (pr->status) { switch (pr->status) {
case CMD_PARSE_ERROR: case CMD_PARSE_ERROR:

View File

@ -24,13 +24,16 @@
* Enter a mode. * 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 = { const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree", .name = "choose-tree",
.alias = NULL, .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] " .usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
@ -44,7 +47,7 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client", .name = "choose-client",
.alias = NULL, .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] " .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
@ -58,7 +61,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer", .name = "choose-buffer",
.alias = NULL, .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] " .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", "[-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 .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 static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item) cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{ {

View File

@ -169,11 +169,13 @@ static int
cmd_command_prompt_callback(struct client *c, void *data, const char *s, cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done) int done)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
char *error; char *error;
struct cmdq_item *item = cdata->item, *new_item; struct cmdq_item *item = cdata->item, *new_item;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_command_prompt_prompt *prompt; struct cmd_command_prompt_prompt *prompt;
int argc = 0;
char **argv = NULL;
if (s == NULL) if (s == NULL)
goto out; goto out;
@ -181,7 +183,6 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
if (cdata->flags & PROMPT_INCREMENTAL) if (cdata->flags & PROMPT_INCREMENTAL)
goto out; goto out;
cmd_append_argv(&cdata->argc, &cdata->argv, s);
if (++cdata->current != cdata->count) { if (++cdata->current != cdata->count) {
prompt = &cdata->prompts[cdata->current]; prompt = &cdata->prompts[cdata->current];
status_prompt_update(c, prompt->prompt, prompt->input); 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, argc = cdata->argc;
&error); 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) { if (cmdlist == NULL) {
cmdq_append(c, cmdq_get_error(error)); cmdq_append(c, cmdq_get_error(error));
free(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)); new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
cmdq_insert_after(item, new_item); cmdq_insert_after(item, new_item);
} }
cmd_free_argv(argc, argv);
if (c->prompt_inputcb != cmd_command_prompt_callback) if (c->prompt_inputcb != cmd_command_prompt_callback)
return (1); return (1);

View File

@ -408,7 +408,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
shell = _PATH_BSHELL; shell = _PATH_BSHELL;
cmd_append_argv(&argc, &argv, shell); cmd_append_argv(&argc, &argv, shell);
} else } else
args_vector(args, &argc, &argv); args_to_vector(args, &argc, &argv);
if (args_has(args, 'E') > 1) if (args_has(args, 'E') > 1)
flags |= POPUP_CLOSEEXITZERO; flags |= POPUP_CLOSEEXITZERO;

View File

@ -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 }, .args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1, NULL },
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] " .usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
"[-f flags] [-n window-name] [-s session-name] " "[-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 }, .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.tc = c;
sc.name = args_get(args, 'n'); 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.idx = -1;
sc.cwd = args_get(args, 'c'); sc.cwd = args_get(args, 'c');

View File

@ -40,7 +40,7 @@ const struct cmd_entry cmd_new_window_entry = {
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL }, .args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] " .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 }, .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.tc = tc;
sc.name = args_get(args, 'n'); 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(); sc.environ = environ_create();
av = args_first_value(args, 'e'); av = args_first_value(args, 'e');

View File

@ -44,13 +44,15 @@ struct cmd_parse_scope {
enum cmd_parse_argument_type { enum cmd_parse_argument_type {
CMD_PARSE_STRING, CMD_PARSE_STRING,
CMD_PARSE_COMMANDS CMD_PARSE_COMMANDS,
CMD_PARSE_PARSED_COMMANDS
}; };
struct cmd_parse_argument { struct cmd_parse_argument {
enum cmd_parse_argument_type type; enum cmd_parse_argument_type type;
char *string; char *string;
struct cmd_parse_commands *commands; struct cmd_parse_commands *commands;
struct cmd_list *cmdlist;
TAILQ_ENTRY(cmd_parse_argument) entry; TAILQ_ENTRY(cmd_parse_argument) entry;
}; };
@ -608,6 +610,9 @@ cmd_parse_free_argument(struct cmd_parse_argument *arg)
case CMD_PARSE_COMMANDS: case CMD_PARSE_COMMANDS:
cmd_parse_free_commands(arg->commands); cmd_parse_free_commands(arg->commands);
break; break;
case CMD_PARSE_PARSED_COMMANDS:
cmd_list_free(arg->cmdlist);
break;
} }
free(arg); 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); cmd_parse_log_commands(arg->commands, s);
free(s); free(s);
break; 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++; j++;
} }
@ -818,6 +828,11 @@ cmd_parse_build_command(struct cmd_parse_command *cmd,
values[count].type = ARGS_COMMANDS; values[count].type = ARGS_COMMANDS;
values[count].cmdlist = pr->cmdlist; values[count].cmdlist = pr->cmdlist;
break; break;
case CMD_PARSE_PARSED_COMMANDS:
values[count].type = ARGS_COMMANDS;
values[count].cmdlist = arg->cmdlist;
values[count].cmdlist->references++;
break;
} }
count++; count++;
} }
@ -1023,39 +1038,19 @@ cmd_parse_from_buffer(const void *buf, size_t len, struct cmd_parse_input *pi)
return (&pr); return (&pr);
} }
static void struct cmd_parse_result *
cmd_parse_add_command(struct cmd_parse_commands *cmds, cmd_parse_from_arguments(struct args_value *values, u_int count,
struct cmd_parse_input *pi, 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;
struct cmd_parse_command *cmd; struct cmd_parse_command *cmd;
struct cmd_parse_argument *arg; struct cmd_parse_argument *arg;
int i; u_int i;
char *copy;
cmd_log_argv(argc, argv, "%s", __func__); size_t size;
int end;
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;
/* /*
* The commands are already split up into arguments, so just separate * 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); memset(&input, 0, sizeof input);
pi = &input; pi = &input;
} }
cmd_log_argv(argc, argv, "%s", __func__);
cmds = cmd_parse_new_commands(); cmds = cmd_parse_new_commands();
copy = cmd_copy_argv(argc, argv);
last = 0; cmd = xcalloc(1, sizeof *cmd);
for (i = 0; i < argc; i++) { cmd->line = pi->line;
size = strlen(copy[i]); TAILQ_INIT(&cmd->arguments);
if (size == 0 || copy[i][size - 1] != ';')
continue; for (i = 0; i < count; i++) {
copy[i][--size] = '\0'; end = 0;
if (size > 0 && copy[i][size - 1] == '\\') { if (values[i].type == ARGS_STRING) {
copy[i][size - 1] = ';'; copy = xstrdup(values[i].string);
continue; 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) { if (!TAILQ_EMPTY(&cmd->arguments))
new_argv = copy + last; TAILQ_INSERT_TAIL(cmds, cmd, entry);
new_argc = argc - last; 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_build_commands(cmds, pi, &pr);
cmd_parse_free_commands(cmds); cmd_parse_free_commands(cmds);
return (&pr); return (&pr);

View File

@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.args = { "c:e:kt:", 0, -1, NULL }, .args = { "c:e:kt:", 0, -1, NULL },
.usage = "[-k] [-c start-directory] [-e environment] " .usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_PANE_USAGE " [command]", CMD_TARGET_PANE_USAGE " [shell-command]",
.target = { 't', CMD_FIND_PANE, 0 }, .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.wl = wl;
sc.wp0 = wp; sc.wp0 = wp;
sc.lc = NULL;
sc.name = NULL; args_to_vector(args, &sc.argc, &sc.argv);
args_vector(args, &sc.argc, &sc.argv);
sc.environ = environ_create(); sc.environ = environ_create();
av = args_first_value(args, 'e'); av = args_first_value(args, 'e');

View File

@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_window_entry = {
.args = { "c:e:kt:", 0, -1, NULL }, .args = { "c:e:kt:", 0, -1, NULL },
.usage = "[-k] [-c start-directory] [-e environment] " .usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_WINDOW_USAGE " [command]", CMD_TARGET_WINDOW_USAGE " [shell-command]",
.target = { 't', CMD_FIND_WINDOW, 0 }, .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.wl = wl;
sc.tc = tc; sc.tc = tc;
sc.name = NULL; args_to_vector(args, &sc.argc, &sc.argv);
args_vector(args, &sc.argc, &sc.argv);
sc.environ = environ_create(); sc.environ = environ_create();
av = args_first_value(args, 'e'); av = args_first_value(args, 'e');

View File

@ -42,7 +42,8 @@ const struct cmd_entry cmd_split_window_entry = {
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL }, .args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " .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 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -136,8 +137,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.wp0 = wp; sc.wp0 = wp;
sc.lc = lc; sc.lc = lc;
sc.name = NULL; args_to_vector(args, &sc.argc, &sc.argv);
args_vector(args, &sc.argc, &sc.argv);
sc.environ = environ_create(); sc.environ = environ_create();
av = args_first_value(args, 'e'); av = args_first_value(args, 'e');

48
cmd.c
View File

@ -544,6 +544,23 @@ cmd_free(struct cmd *cmd)
free(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. */ /* Get a command as a string. */
char * char *
cmd_print(struct cmd *cmd) cmd_print(struct cmd *cmd)
@ -618,6 +635,37 @@ cmd_list_free(struct cmd_list *cmdlist)
free(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. */ /* Get a command list as a string. */
char * char *
cmd_list_print(struct cmd_list *cmdlist, int escaped) cmd_list_print(struct cmd_list *cmdlist, int escaped)

View File

@ -29,7 +29,7 @@
" 'Previous' 'p' {switch-client -p}" \ " 'Previous' 'p' {switch-client -p}" \
" ''" \ " ''" \
" 'Renumber' 'N' {move-window -r}" \ " '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 Session' 's' {new-session}" \
" 'New Window' 'w' {new-window}" " 'New Window' 'w' {new-window}"
@ -41,7 +41,7 @@
" 'Kill' 'X' {kill-window}" \ " 'Kill' 'X' {kill-window}" \
" 'Respawn' 'R' {respawn-window -k}" \ " 'Respawn' 'R' {respawn-window -k}" \
" '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \ " '#{?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 After' 'w' {new-window -a}" \
" 'New At End' 'W' {new-window}" " '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 'Break pane to a new window' ! { break-pane }",
"bind -N 'Split window vertically' '\"' { split-window }", "bind -N 'Split window vertically' '\"' { split-window }",
"bind -N 'List all paste buffers' '#' { list-buffers }", "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 'Split window horizontally' % { split-window -h }",
"bind -N 'Kill current window' & { confirm-before -p\"kill-window #W? (y/n)\" kill-window }", "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 previous client' ( { switch-client -p }",
"bind -N 'Switch to next client' ) { switch-client -n }", "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 'Delete the most recent paste buffer' - { delete-buffer }",
"bind -N 'Move the current window' . { command-prompt -T target \"move-window -t '%%'\" }", "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 'Describe key binding' '/' { command-prompt -kpkey { list-keys -1N '%%' } }",
"bind -N 'Select window 0' 0 { select-window -t:=0 }", "bind -N 'Select window 0' 0 { select-window -t:=0 }",
"bind -N 'Select window 1' 1 { select-window -t:=1 }", "bind -N 'Select window 1' 1 { select-window -t:=1 }",
"bind -N 'Select window 2' 2 { select-window -t:=2 }", "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 'Paste the most recent paste buffer' ] { paste-buffer -p }",
"bind -N 'Create a new window' c { new-window }", "bind -N 'Create a new window' c { new-window }",
"bind -N 'Detach the current client' d { detach-client }", "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 'Display window information' i { display-message }",
"bind -N 'Select the previously current window' l { last-window }", "bind -N 'Select the previously current window' l { last-window }",
"bind -N 'Toggle the marked pane' m { select-pane -m }", "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-k { send -X copy-pipe-end-of-line-and-cancel }",
"bind -Tcopy-mode C-n { send -X cursor-down }", "bind -Tcopy-mode C-n { send -X cursor-down }",
"bind -Tcopy-mode C-p { send -X cursor-up }", "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-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-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-v { send -X page-down }",
"bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }", "bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }",
"bind -Tcopy-mode Escape { send -X cancel }", "bind -Tcopy-mode Escape { send -X cancel }",
"bind -Tcopy-mode Space { send -X page-down }", "bind -Tcopy-mode Space { send -X page-down }",
"bind -Tcopy-mode , { send -X jump-reverse }", "bind -Tcopy-mode , { send -X jump-reverse }",
"bind -Tcopy-mode \\; { send -X jump-again }", "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 N { send -X search-reverse }",
"bind -Tcopy-mode R { send -X rectangle-toggle }", "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 X { send -X set-mark }",
"bind -Tcopy-mode f { command-prompt -1p'(jump forward)' 'send -X jump-forward \"%%%\"' }", "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 g { command-prompt -p'(goto line)' { send -X goto-line '%%' } }",
"bind -Tcopy-mode n { send -X search-again }", "bind -Tcopy-mode n { send -X search-again }",
"bind -Tcopy-mode q { send -X cancel }", "bind -Tcopy-mode q { send -X cancel }",
"bind -Tcopy-mode r { send -X refresh-from-pane }", "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 Home { send -X start-of-line }",
"bind -Tcopy-mode End { send -X end-of-line }", "bind -Tcopy-mode End { send -X end-of-line }",
"bind -Tcopy-mode MouseDown1Pane select-pane", "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 Down { send -X cursor-down }",
"bind -Tcopy-mode Left { send -X cursor-left }", "bind -Tcopy-mode Left { send -X cursor-left }",
"bind -Tcopy-mode Right { send -X cursor-right }", "bind -Tcopy-mode Right { send -X cursor-right }",
"bind -Tcopy-mode M-1 { command-prompt -Np'(repeat)' -I1 '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-2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
"bind -Tcopy-mode M-3 { command-prompt -Np'(repeat)' -I3 '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-4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }",
"bind -Tcopy-mode M-5 { command-prompt -Np'(repeat)' -I5 '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-6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }",
"bind -Tcopy-mode M-7 { command-prompt -Np'(repeat)' -I7 '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-8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
"bind -Tcopy-mode M-9 { command-prompt -Np'(repeat)' -I9 '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-top }",
"bind -Tcopy-mode M-> { send -X history-bottom }", "bind -Tcopy-mode M-> { send -X history-bottom }",
"bind -Tcopy-mode M-R { send -X top-line }", "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 Space { send -X begin-selection }",
"bind -Tcopy-mode-vi '$' { send -X end-of-line }", "bind -Tcopy-mode-vi '$' { send -X end-of-line }",
"bind -Tcopy-mode-vi , { send -X jump-reverse }", "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 0 { send -X start-of-line }",
"bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 'send -N \"%%%\"' }", "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 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
"bind -Tcopy-mode-vi 3 { command-prompt -Np'(repeat)' -I3 '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 4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }",
"bind -Tcopy-mode-vi 5 { command-prompt -Np'(repeat)' -I5 '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 6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }",
"bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 '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 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
"bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 '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 : { command-prompt -p'(goto line)' { send -X goto-line '%%' } }",
"bind -Tcopy-mode-vi \\; { send -X jump-again }", "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 A { send -X append-selection-and-cancel }",
"bind -Tcopy-mode-vi B { send -X previous-space }", "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 D { send -X copy-pipe-end-of-line-and-cancel }",
"bind -Tcopy-mode-vi E { send -X next-space-end }", "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 G { send -X history-bottom }",
"bind -Tcopy-mode-vi H { send -X top-line }", "bind -Tcopy-mode-vi H { send -X top-line }",
"bind -Tcopy-mode-vi J { send -X scroll-down }", "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 L { send -X bottom-line }",
"bind -Tcopy-mode-vi M { send -X middle-line }", "bind -Tcopy-mode-vi M { send -X middle-line }",
"bind -Tcopy-mode-vi N { send -X search-reverse }", "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 V { send -X select-line }",
"bind -Tcopy-mode-vi W { send -X next-space }", "bind -Tcopy-mode-vi W { send -X next-space }",
"bind -Tcopy-mode-vi X { send -X set-mark }", "bind -Tcopy-mode-vi X { send -X set-mark }",
"bind -Tcopy-mode-vi ^ { send -X back-to-indentation }", "bind -Tcopy-mode-vi ^ { send -X back-to-indentation }",
"bind -Tcopy-mode-vi b { send -X previous-word }", "bind -Tcopy-mode-vi b { send -X previous-word }",
"bind -Tcopy-mode-vi e { send -X next-word-end }", "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 g { send -X history-top }",
"bind -Tcopy-mode-vi h { send -X cursor-left }", "bind -Tcopy-mode-vi h { send -X cursor-left }",
"bind -Tcopy-mode-vi j { send -X cursor-down }", "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 o { send -X other-end }",
"bind -Tcopy-mode-vi q { send -X cancel }", "bind -Tcopy-mode-vi q { send -X cancel }",
"bind -Tcopy-mode-vi r { send -X refresh-from-pane }", "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 v { send -X rectangle-toggle }",
"bind -Tcopy-mode-vi w { send -X next-word }", "bind -Tcopy-mode-vi w { send -X next-word }",
"bind -Tcopy-mode-vi '{' { send -X previous-paragraph }", "bind -Tcopy-mode-vi '{' { send -X previous-paragraph }",

View File

@ -2124,6 +2124,7 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
int argc; int argc;
char **argv, *cause; char **argv, *cause;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
struct args_value *values;
if (c->flags & CLIENT_EXIT) if (c->flags & CLIENT_EXIT)
return; return;
@ -2149,7 +2150,8 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
*argv = xstrdup("new-session"); *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) { switch (pr->status) {
case CMD_PARSE_ERROR: case CMD_PARSE_ERROR:
cause = pr->error; cause = pr->error;
@ -2157,6 +2159,8 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
case CMD_PARSE_SUCCESS: case CMD_PARSE_SUCCESS:
break; break;
} }
args_free_values(values, argc);
free(values);
cmd_free_argv(argc, argv); cmd_free_argv(argc, argv);
cmdq_append(c, cmdq_get_command(pr->cmdlist, NULL)); cmdq_append(c, cmdq_get_command(pr->cmdlist, NULL));

10
tmux.h
View File

@ -2217,8 +2217,11 @@ void args_set(struct args *, u_char, struct args_value *);
struct args *args_create(void); struct args *args_create(void);
struct args *args_parse(const struct args_parse *, struct args_value *, struct args *args_parse(const struct args_parse *, struct args_value *,
u_int, char **); 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_value(struct args_value *);
void args_free_values(struct args_value *, u_int);
void args_free(struct args *); void args_free(struct args *);
char *args_print(struct args *); char *args_print(struct args *);
char *args_escape(const char *); char *args_escape(const char *);
@ -2227,6 +2230,7 @@ const char *args_get(struct args *, u_char);
u_char args_first(struct args *, struct args_entry **); u_char args_first(struct args *, struct args_entry **);
u_char args_next(struct args_entry **); u_char args_next(struct args_entry **);
u_int args_count(struct args *); u_int args_count(struct args *);
struct args_value *args_values(struct args *);
struct args_value *args_value(struct args *, u_int); struct args_value *args_value(struct args *, u_int);
const char *args_string(struct args *, u_int); const char *args_string(struct args *, u_int);
struct cmd_list *args_make_commands_now(struct cmd *, struct cmdq_item *, struct cmd_list *args_make_commands_now(struct cmd *, struct cmdq_item *,
@ -2291,9 +2295,11 @@ u_int cmd_get_group(struct cmd *);
void cmd_get_source(struct cmd *, const char **, u_int *); void cmd_get_source(struct cmd *, const char **, u_int *);
struct cmd *cmd_parse(struct args_value *, u_int, const char *, u_int, struct cmd *cmd_parse(struct args_value *, u_int, const char *, u_int,
char **); char **);
struct cmd *cmd_copy(struct cmd *, int, char **);
void cmd_free(struct cmd *); void cmd_free(struct cmd *);
char *cmd_print(struct cmd *); char *cmd_print(struct cmd *);
struct cmd_list *cmd_list_new(void); 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(struct cmd_list *, struct cmd *);
void cmd_list_append_all(struct cmd_list *, struct cmd_list *); void cmd_list_append_all(struct cmd_list *, struct cmd_list *);
void cmd_list_move(struct cmd_list *, struct cmd_list *); void cmd_list_move(struct cmd_list *, struct cmd_list *);
@ -2327,7 +2333,7 @@ enum cmd_parse_status cmd_parse_and_append(const char *,
struct cmdq_state *, char **); struct cmdq_state *, char **);
struct cmd_parse_result *cmd_parse_from_buffer(const void *, size_t, struct cmd_parse_result *cmd_parse_from_buffer(const void *, size_t,
struct cmd_parse_input *); 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 *); struct cmd_parse_input *);
/* cmd-queue.c */ /* cmd-queue.c */