1
0
mirror of https://github.com/tmux/tmux.git synced 2025-03-22 12:58:48 +00:00

Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2016-10-16 20:01:10 +01:00
commit c67b702588
29 changed files with 817 additions and 702 deletions

70
cfg.c
View File

@ -28,14 +28,25 @@
#include "tmux.h"
char *cfg_file;
static struct cmd_q *cfg_cmd_q;
int cfg_finished;
int cfg_references;
static char **cfg_causes;
static u_int cfg_ncauses;
struct client *cfg_client;
static void cfg_default_done(struct cmd_q *);
static enum cmd_retval
cfg_done(__unused struct cmd_q *cmdq, __unused void *data)
{
if (cfg_finished)
return (CMD_RETURN_NORMAL);
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_client != NULL)
server_client_unref(cfg_client);
return (CMD_RETURN_NORMAL);
}
void
set_cfg_file(const char *path)
@ -50,30 +61,24 @@ start_cfg(void)
const char *home;
int quiet = 0;
cfg_cmd_q = cmdq_new(NULL);
cfg_cmd_q->emptyfn = cfg_default_done;
cfg_finished = 0;
cfg_references = 1;
cfg_client = TAILQ_FIRST(&clients);
if (cfg_client != NULL)
cfg_client->references++;
load_cfg(TMUX_CONF, cfg_cmd_q, 1);
load_cfg(TMUX_CONF, cfg_client, NULL, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
quiet = 1;
}
if (cfg_file != NULL)
load_cfg(cfg_file, cfg_cmd_q, quiet);
load_cfg(cfg_file, cfg_client, NULL, quiet);
cmdq_continue(cfg_cmd_q);
cmdq_append(cfg_client, cmdq_get_callback(cfg_done, NULL));
}
int
load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
load_cfg(const char *path, struct client *c, struct cmd_q *cmdq, int quiet)
{
FILE *f;
char delim[3] = { '\\', '\\', '\0' };
@ -81,6 +86,7 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
size_t line = 0;
char *buf, *cause1, *p;
struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
@ -116,8 +122,13 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
if (cmdlist == NULL)
continue;
cmdq_append(cmdq, cmdlist, NULL);
new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
if (cmdq != NULL)
cmdq_insert_after(cmdq, new_cmdq);
else
cmdq_append(c, new_cmdq);
cmd_list_free(cmdlist);
found++;
}
fclose(f);
@ -125,37 +136,6 @@ load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
return (found);
}
static void
cfg_default_done(__unused struct cmd_q *cmdq)
{
log_debug("%s: %u references%s", __func__, cfg_references,
cfg_finished ? " (finished)" : "");
if (cfg_finished || --cfg_references != 0)
return;
cfg_finished = 1;
if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
cmdq_free(cfg_cmd_q);
cfg_cmd_q = NULL;
if (cfg_client != NULL) {
/*
* The client command queue starts with client_exit set to 1 so
* only continue if not empty (that is, we have been delayed
* during configuration parsing for long enough that the
* MSG_COMMAND has arrived), else the client will exit before
* the MSG_COMMAND which might tell it not to.
*/
if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
cmdq_continue(cfg_client->cmdq);
server_client_unref(cfg_client);
cfg_client = NULL;
}
}
void
cfg_add_cause(const char *fmt, ...)
{

View File

@ -145,7 +145,7 @@ cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag,
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);
hooks_run(c->session->hooks, c, NULL, "client-attached");
cmdq->client_exit = 0;
c->flags |= CLIENT_ATTACHED;
}
recalculate_sizes();
alerts_check_session(s);

View File

@ -121,12 +121,24 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_command_prompt_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static int
cmd_command_prompt_callback(void *data, const char *s)
{
struct cmd_command_prompt_cdata *cdata = data;
struct client *c = cdata->c;
struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
char *cause, *new_template, *prompt, *ptr;
char *input = NULL;
@ -153,17 +165,19 @@ cmd_command_prompt_callback(void *data, const char *s)
if (cmd_string_parse(new_template, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
free(cause);
}
return (0);
new_cmdq = cmdq_get_callback(cmd_command_prompt_error,
cause);
} else
new_cmdq = NULL;
} else {
new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
if (new_cmdq != NULL)
cmdq_append(c, new_cmdq);
if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback)
if (c->prompt_callbackfn != (void *)&cmd_command_prompt_callback)
return (1);
return (0);
}

View File

@ -83,12 +83,24 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_confirm_before_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static int
cmd_confirm_before_callback(void *data, const char *s)
{
struct cmd_confirm_before_data *cdata = data;
struct client *c = cdata->client;
struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
char *cause;
if (c->flags & CLIENT_DEAD)
@ -101,14 +113,17 @@ cmd_confirm_before_callback(void *data, const char *s)
if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
cmdq_error(c->cmdq, "%s", cause);
free(cause);
}
return (0);
new_cmdq = cmdq_get_callback(cmd_confirm_before_error,
cause);
} else
new_cmdq = NULL;
} else {
new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
if (new_cmdq != NULL)
cmdq_append(c, new_cmdq);
return (0);
}

View File

@ -61,7 +61,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp = cmdq->state.tflag.wp;
if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&cmdq->item->mouse, &s, NULL)) == NULL)
if ((wp = cmd_mouse_pane(&cmdq->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
@ -80,7 +80,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'M')) {
if (wp->mode != NULL && wp->mode != &window_copy_mode)
return (CMD_RETURN_NORMAL);
window_copy_start_drag(c, &cmdq->item->mouse);
window_copy_start_drag(c, &cmdq->mouse);
}
if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
window_copy_pageup(wp, 0);

View File

@ -65,32 +65,48 @@ cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_display_panes_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void
cmd_display_panes_callback(struct client *c, struct window_pane *wp)
{
struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
char *template, *cmd, *expanded, *cause;
template = c->identify_callback_data;
if (wp != NULL) {
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
if (wp == NULL)
goto out;
xasprintf(&expanded, "%%%u", wp->id);
cmd = cmd_template_replace(template, expanded, 1);
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
*cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause);
free(cause);
}
} else {
cmdq_run(c->cmdq, cmdlist, NULL);
cmd_list_free(cmdlist);
}
free(cmd);
free(expanded);
if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
new_cmdq = cmdq_get_callback(cmd_display_panes_error,
cause);
} else
new_cmdq = NULL;
} else {
new_cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmd_list_free(cmdlist);
}
if (new_cmdq != NULL)
cmdq_append(c, new_cmdq);
free(cmd);
free(expanded);
out:
free(c->identify_callback_data);
c->identify_callback_data = NULL;
c->identify_callback = NULL;

View File

@ -1005,7 +1005,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current,
/* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &cmdq->item->mouse;
m = &cmdq->mouse;
switch (type) {
case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);

View File

@ -31,9 +31,9 @@
static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *);
static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_done(struct cmd_q *);
static void cmd_if_shell_free(void *);
static enum cmd_retval cmd_if_shell_error(struct cmd_q *, void *);
static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell",
@ -56,11 +56,9 @@ struct cmd_if_shell_data {
char *cmd_if;
char *cmd_else;
struct client *client;
struct cmd_q *cmdq;
struct mouse_event mouse;
int bflag;
int references;
};
static enum cmd_retval
@ -70,6 +68,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd, *cause;
struct cmd_list *cmdlist;
struct cmd_q *new_cmdq;
struct session *s = cmdq->state.tflag.s;
struct winlink *wl = cmdq->state.tflag.wl;
struct window_pane *wp = cmdq->state.tflag.wp;
@ -104,7 +103,8 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
}
return (CMD_RETURN_ERROR);
}
cmdq_run(cmdq, cmdlist, &cmdq->item->mouse);
new_cmdq = cmdq_get_command(cmdlist, NULL, &cmdq->mouse, 0);
cmdq_insert_after(cmdq, new_cmdq);
cmd_list_free(cmdlist);
return (CMD_RETURN_NORMAL);
}
@ -121,92 +121,80 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
else
cdata->cmd_else = NULL;
cdata->bflag = args_has(args, 'b');
cdata->client = cmdq->client;
cdata->client->references++;
cdata->cmdq = cmdq;
memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
cmdq->references++;
if (!args_has(args, 'b'))
cdata->cmdq = cmdq;
else
cdata->cmdq = NULL;
memcpy(&cdata->mouse, &cmdq->mouse, sizeof cdata->mouse);
cdata->references = 1;
job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
cdata);
free(shellcmd);
if (cdata->bflag)
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
cmd_if_shell_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
static void
cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job->data;
struct cmd_q *cmdq = cdata->cmdq, *cmdq1;
struct client *c = cdata->client;
struct cmd_list *cmdlist;
char *cause, *cmd;
if (cmdq->flags & CMD_Q_DEAD)
return;
struct cmd_q *new_cmdq;
char *cause, *cmd, *file = cdata->file;
u_int line = cdata->line;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
cmd = cdata->cmd_else;
else
cmd = cdata->cmd_if;
if (cmd == NULL)
return;
goto out;
if (cmd_string_parse(cmd, &cmdlist, cdata->file, cdata->line,
&cause) != 0) {
if (cause != NULL) {
cmdq_error(cmdq, "%s", cause);
free(cause);
}
return;
if (cmd_string_parse(cmd, &cmdlist, file, line, &cause) != 0) {
if (cause != NULL)
new_cmdq = cmdq_get_callback(cmd_if_shell_error, cause);
else
new_cmdq = NULL;
} else {
new_cmdq = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
cmd_list_free(cmdlist);
}
cmdq1 = cmdq_new(cmdq->client);
cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata;
if (new_cmdq != NULL) {
if (cdata->cmdq == NULL)
cmdq_append(c, new_cmdq);
else
cmdq_insert_after(cdata->cmdq, new_cmdq);
}
cdata->references++;
cmdq_run(cmdq1, cmdlist, &cdata->mouse);
cmd_list_free(cmdlist);
}
static void
cmd_if_shell_done(struct cmd_q *cmdq1)
{
struct cmd_if_shell_data *cdata = cmdq1->data;
struct cmd_q *cmdq = cdata->cmdq;
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd_else);
free(cdata->cmd_if);
free(cdata->file);
free(cdata);
out:
if (cdata->cmdq != NULL)
cdata->cmdq->flags &= ~CMD_Q_WAITING;
}
static void
cmd_if_shell_free(void *data)
{
struct cmd_if_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq;
if (--cdata->references != 0)
return;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
server_client_unref(cdata->client);
free(cdata->cmd_else);
free(cdata->cmd_if);

View File

@ -46,17 +46,24 @@ const struct cmd_entry cmd_load_buffer_entry = {
.exec = cmd_load_buffer_exec
};
struct cmd_load_buffer_data {
struct cmd_q *cmdq;
char *bufname;
};
static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c = cmdq->client;
struct session *s;
FILE *f;
const char *path, *bufname, *cwd;
char *pdata, *new_pdata, *cause, *file, resolved[PATH_MAX];
size_t psize;
int ch, error;
struct args *args = self->args;
struct cmd_load_buffer_data *cdata;
struct client *c = cmdq->client;
struct session *s;
FILE *f;
const char *path, *bufname, *cwd;
char *pdata, *new_pdata, *cause, *file;
char resolved[PATH_MAX];
size_t psize;
int ch, error;
bufname = NULL;
if (args_has(args, 'b'))
@ -64,8 +71,12 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
path = args->argv[0];
if (strcmp(path, "-") == 0) {
cdata = xcalloc(1, sizeof *cdata);
cdata->cmdq = cmdq;
cdata->bufname = xstrdup(bufname);
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
(void *)bufname, &cause);
cdata, &cause);
if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause);
free(cause);
@ -136,9 +147,9 @@ error:
static void
cmd_load_buffer_callback(struct client *c, int closed, void *data)
{
const char *bufname = data;
char *pdata, *cause, *saved;
size_t psize;
struct cmd_load_buffer_data *cdata = data;
char *pdata, *cause, *saved;
size_t psize;
if (!closed)
return;
@ -146,7 +157,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
server_client_unref(c);
if (c->flags & CLIENT_DEAD)
return;
goto out;
psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
@ -156,7 +167,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize);
if (paste_set(pdata, psize, bufname, &cause) != 0) {
if (paste_set(pdata, psize, cdata->bufname, &cause) != 0) {
/* No context so can't use server_client_msg_error. */
if (~c->flags & CLIENT_UTF8) {
saved = cause;
@ -168,7 +179,9 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
free(pdata);
free(cause);
}
out:
cmdq_continue(c->cmdq);
cdata->cmdq->flags &= ~CMD_Q_WAITING;
free(cdata->bufname);
free(cdata);
}

View File

@ -312,14 +312,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
}
if (!detached)
cmdq->client_exit = 0;
c->flags |= CLIENT_ATTACHED;
if (to_free != NULL)
free((void *)to_free);
cmd_find_from_session(&fs, s);
if (hooks_wait(s->hooks, cmdq, &fs, "after-new-session") == 0)
return (CMD_RETURN_WAIT);
hooks_insert(s->hooks, cmdq, &fs, "after-new-session");
return (CMD_RETURN_NORMAL);
error:

View File

@ -157,8 +157,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
free((void *)to_free);
cmd_find_from_winlink(&fs, s, wl);
if (hooks_wait(s->hooks, cmdq, &fs, "after-new-window") == 0)
return (CMD_RETURN_WAIT);
hooks_insert(s->hooks, cmdq, &fs, "after-new-window");
return (CMD_RETURN_NORMAL);
error:

View File

@ -25,47 +25,316 @@
#include "tmux.h"
static enum cmd_retval cmdq_continue_one(struct cmd_q *);
static void cmdq_flush(struct cmd_q *);
/* Global command queue. */
static struct cmd_q_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
/* Create new command queue. */
/* Get command queue name. */
static const char *
cmdq_name(struct client *c)
{
static char s[32];
if (c == NULL)
return ("<global>");
xsnprintf(s, sizeof s, "<%p>", c);
return (s);
}
/* Get command queue from client. */
static struct cmd_q_list *
cmdq_get(struct client *c)
{
if (c == NULL)
return (&global_queue);
return (&c->queue);
}
/* Append an item. */
void
cmdq_append(struct client *c, struct cmd_q *cmdq)
{
struct cmd_q_list *queue = cmdq_get(c);
struct cmd_q *next;
do {
next = cmdq->next;
cmdq->next = NULL;
if (c != NULL)
c->references++;
cmdq->client = c;
cmdq->queue = queue;
TAILQ_INSERT_TAIL(queue, cmdq, entry);
cmdq = next;
} while (cmdq != NULL);
}
/* Insert an item. */
void
cmdq_insert_after(struct cmd_q *after, struct cmd_q *cmdq)
{
struct client *c = after->client;
struct cmd_q_list *queue = after->queue;
struct cmd_q *next;
do {
next = cmdq->next;
cmdq->next = NULL;
if (c != NULL)
c->references++;
cmdq->client = c;
cmdq->queue = queue;
if (after->next != NULL)
TAILQ_INSERT_AFTER(queue, after->next, cmdq, entry);
else
TAILQ_INSERT_AFTER(queue, after, cmdq, entry);
after->next = cmdq;
cmdq = next;
} while (cmdq != NULL);
}
/* Remove an item. */
static void
cmdq_remove(struct cmd_q *cmdq)
{
free((void *)cmdq->hook);
if (cmdq->client != NULL)
server_client_unref(cmdq->client);
if (cmdq->type == CMD_Q_COMMAND)
cmd_list_free(cmdq->cmdlist);
TAILQ_REMOVE(cmdq->queue, cmdq, entry);
free(cmdq);
}
/* Set command group. */
static u_int
cmdq_next_group(void)
{
static u_int group;
return (++group);
}
/* Remove all subsequent items that match this item's group. */
static void
cmdq_remove_group(struct cmd_q *cmdq)
{
struct cmd_q *this, *next;
this = TAILQ_NEXT(cmdq, entry);
while (this != NULL) {
next = TAILQ_NEXT(this, entry);
if (this->group == cmdq->group)
cmdq_remove(this);
this = next;
}
}
/* Get a command for the command queue. */
struct cmd_q *
cmdq_new(struct client *c)
cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct mouse_event *m, int flags)
{
struct cmd_q *cmdq, *first = NULL, *last = NULL;
struct cmd *cmd;
u_int group = cmdq_next_group();
TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
cmdq = xcalloc(1, sizeof *cmdq);
cmdq->type = CMD_Q_COMMAND;
cmdq->group = group;
cmdq->flags = flags;
cmdq->cmdlist = cmdlist;
cmdq->cmd = cmd;
if (current != NULL)
cmd_find_copy_state(&cmdq->current, current);
if (m != NULL)
memcpy(&cmdq->mouse, m, sizeof cmdq->mouse);
cmdlist->references++;
if (first == NULL)
first = cmdq;
if (last != NULL)
last->next = cmdq;
last = cmdq;
}
return (first);
}
/* Fire command on command queue. */
static enum cmd_retval
cmdq_fire_command(struct cmd_q *cmdq)
{
struct client *c = cmdq->client;
struct cmd *cmd = cmdq->cmd;
enum cmd_retval retval;
const char *name;
struct cmd_find_state *fsp, fs;
int flags;
flags = !!(cmd->flags & CMD_CONTROL);
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq) != 0) {
retval = CMD_RETURN_ERROR;
goto out;
}
if (cmdq->client == NULL)
cmdq->client = cmd_find_client(cmdq, NULL, CMD_FIND_QUIET);
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto out;
if (cmd->entry->flags & CMD_AFTERHOOK) {
name = cmd->entry->name;
if (cmd_find_valid_state(&cmdq->state.tflag))
fsp = &cmdq->state.tflag;
else {
if (cmd_find_current(&fs, cmdq, CMD_FIND_QUIET) != 0)
goto out;
fsp = &fs;
}
hooks_insert(fsp->s->hooks, cmdq, fsp, "after-%s", name);
}
out:
cmdq->client = c;
if (retval == CMD_RETURN_ERROR)
cmdq_guard(cmdq, "error", flags);
else
cmdq_guard(cmdq, "end", flags);
return (retval);
}
/* Get a callback for the command queue. */
struct cmd_q *
cmdq_get_callback(cmd_q_cb cb, void *data)
{
struct cmd_q *cmdq;
cmdq = xcalloc(1, sizeof *cmdq);
cmdq->references = 1;
cmdq->type = CMD_Q_CALLBACK;
cmdq->group = 0;
cmdq->flags = 0;
cmdq->client = c;
cmdq->client_exit = -1;
TAILQ_INIT(&cmdq->queue);
cmdq->item = NULL;
cmdq->cmd = NULL;
cmd_find_clear_state(&cmdq->current, NULL, 0);
cmdq->parent = NULL;
cmdq->cb = cb;
cmdq->data = data;
return (cmdq);
}
/* Free command queue */
int
cmdq_free(struct cmd_q *cmdq)
/* Fire callback on callback queue. */
static enum cmd_retval
cmdq_fire_callback(struct cmd_q *cmdq)
{
log_debug("cmdq %p free: %u references", cmdq, cmdq->references);
return (cmdq->cb(cmdq, cmdq->data));
}
if (--cmdq->references != 0) {
if (cmdq->flags & CMD_Q_DEAD)
return (1);
/* Process next item on command queue. */
u_int
cmdq_next(struct client *c)
{
struct cmd_q_list *queue = cmdq_get(c);
const char *name = cmdq_name(c);
struct cmd_q *cmdq;
enum cmd_retval retval;
u_int items = 0;
static u_int number;
if (TAILQ_EMPTY(queue)) {
log_debug("%s %s: empty", __func__, name);
return (0);
}
if (TAILQ_FIRST(queue)->flags & CMD_Q_WAITING) {
log_debug("%s %s: waiting", __func__, name);
return (0);
}
cmdq_flush(cmdq);
free(cmdq);
return (1);
log_debug("%s %s: enter", __func__, name);
for (;;) {
cmdq = TAILQ_FIRST(queue);
if (cmdq == NULL)
break;
log_debug("%s %s: type %d, flags %x", __func__, name,
cmdq->type, cmdq->flags);
/*
* Any item with the waiting flag set waits until an external
* event clears the flag (for example, a job - look at
* run-shell).
*/
if (cmdq->flags & CMD_Q_WAITING)
goto waiting;
/*
* Items are only fired once, once the fired flag is set, a
* waiting flag can only be cleared by an external event.
*/
if (~cmdq->flags & CMD_Q_FIRED) {
cmdq->time = time(NULL);
cmdq->number = ++number;
switch (cmdq->type)
{
case CMD_Q_COMMAND:
retval = cmdq_fire_command(cmdq);
/*
* If a command returns an error, remove any
* subsequent commands in the same group.
*/
if (retval == CMD_RETURN_ERROR)
cmdq_remove_group(cmdq);
break;
case CMD_Q_CALLBACK:
retval = cmdq_fire_callback(cmdq);
break;
default:
retval = CMD_RETURN_ERROR;
break;
}
cmdq->flags |= CMD_Q_FIRED;
if (retval == CMD_RETURN_WAIT) {
cmdq->flags |= CMD_Q_WAITING;
goto waiting;
}
items++;
}
cmdq_remove(cmdq);
}
log_debug("%s %s: exit (empty)", __func__, name);
return (items);
waiting:
log_debug("%s %s: exit (wait)", __func__, name);
return (items);
}
/* Print a guard line. */
void
cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
{
struct client *c = cmdq->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long)cmdq->time, cmdq->number, flags);
server_client_push_stdout(c);
}
/* Show message from command. */
@ -140,175 +409,3 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
free(msg);
}
/* Print a guard line. */
void
cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags)
{
struct client *c = cmdq->client;
if (c == NULL || !(c->flags & CLIENT_CONTROL))
return;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard,
(long) cmdq->time, cmdq->number, flags);
server_client_push_stdout(c);
}
/* Add command list to queue and begin processing if needed. */
void
cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{
cmdq_append(cmdq, cmdlist, m);
if (cmdq->item == NULL) {
cmdq->cmd = NULL;
cmdq_continue(cmdq);
}
}
/* Add command list to queue. */
void
cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
{
struct cmd_q_item *item;
item = xcalloc(1, sizeof *item);
item->cmdlist = cmdlist;
TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
cmdlist->references++;
if (m != NULL)
memcpy(&item->mouse, m, sizeof item->mouse);
else
item->mouse.valid = 0;
}
/* Process one command. */
static enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq)
{
struct cmd_list *cmdlist = cmdq->item->cmdlist;
struct cmd *cmd = cmdq->cmd;
enum cmd_retval retval;
char *tmp;
int flags = !!(cmd->flags & CMD_CONTROL);
const char *name;
struct cmd_find_state *fsp, fs;
cmdlist->references++;
tmp = cmd_print(cmd);
log_debug("cmdq %p: %s", cmdq, tmp);
free(tmp);
cmdq->time = time(NULL);
cmdq->number++;
cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error;
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
goto error;
if (~cmd->entry->flags & CMD_AFTERHOOK)
goto end;
if (cmd_find_valid_state(&cmdq->state.tflag))
fsp = &cmdq->state.tflag;
else {
if (cmd_find_current(&fs, cmdq, CMD_FIND_QUIET) != 0)
goto end;
fsp = &fs;
}
name = cmd->entry->name;
if (hooks_wait(fsp->s->hooks, cmdq, fsp, "after-%s", name) == 0)
retval = CMD_RETURN_WAIT;
end:
cmdq_guard(cmdq, "end", flags);
cmd_list_free(cmdlist);
return (retval);
error:
cmdq_guard(cmdq, "error", flags);
cmd_list_free(cmdlist);
return (CMD_RETURN_ERROR);
}
/* Continue processing command queue. Returns 1 if finishes empty. */
int
cmdq_continue(struct cmd_q *cmdq)
{
struct client *c = cmdq->client;
struct cmd_q_item *next;
enum cmd_retval retval;
int empty;
log_debug("continuing cmdq %p: flags %#x (%p)", cmdq, cmdq->flags, c);
cmdq->references++;
empty = TAILQ_EMPTY(&cmdq->queue);
if (empty)
goto empty;
if (cmdq->item == NULL) {
cmdq->item = TAILQ_FIRST(&cmdq->queue);
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} else
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
do {
while (cmdq->cmd != NULL) {
retval = cmdq_continue_one(cmdq);
if (retval == CMD_RETURN_ERROR)
break;
if (retval == CMD_RETURN_WAIT)
goto out;
if (retval == CMD_RETURN_STOP) {
cmdq_flush(cmdq);
goto empty;
}
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
next = TAILQ_NEXT(cmdq->item, qentry);
TAILQ_REMOVE(&cmdq->queue, cmdq->item, qentry);
cmd_list_free(cmdq->item->cmdlist);
free(cmdq->item);
cmdq->item = next;
if (cmdq->item != NULL)
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} while (cmdq->item != NULL);
empty:
log_debug("cmdq %p empty", cmdq);
if (cmdq->client_exit > 0)
cmdq->client->flags |= CLIENT_EXIT;
if (cmdq->emptyfn != NULL)
cmdq->emptyfn(cmdq);
empty = 1;
out:
cmdq_free(cmdq);
return (empty);
}
/* Flush command queue. */
static void
cmdq_flush(struct cmd_q *cmdq)
{
struct cmd_q_item *item, *item1;
TAILQ_FOREACH_SAFE(item, &cmdq->queue, qentry, item1) {
TAILQ_REMOVE(&cmdq->queue, item, qentry);
cmd_list_free(item->cmdlist);
free(item);
}
cmdq->item = NULL;
}

View File

@ -60,12 +60,12 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
int x, y;
if (args_has(args, 'M')) {
if (cmd_mouse_window(&cmdq->item->mouse, &s) == NULL)
if (cmd_mouse_window(&cmdq->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &cmdq->item->mouse);
cmd_resize_pane_mouse_update(c, &cmdq->mouse);
return (CMD_RETURN_NORMAL);
}

View File

@ -51,7 +51,6 @@ const struct cmd_entry cmd_run_shell_entry = {
struct cmd_run_shell_data {
char *cmd;
struct cmd_q *cmdq;
int bflag;
int wp_id;
};
@ -92,6 +91,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
cwd = s->cwd;
else
cwd = NULL;
ft = format_create(cmdq, 0);
format_defaults(ft, cmdq->state.c, s, wl, wp);
shellcmd = format_expand(ft, args->argv[0]);
@ -99,20 +99,24 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
cdata = xcalloc(1, sizeof *cdata);
cdata->cmd = shellcmd;
cdata->bflag = args_has(args, 'b');
if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id;
else
cdata->wp_id = -1;
cdata->cmdq = cmdq;
cmdq->references++;
if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id;
else
cdata->wp_id = -1;
if (!args_has(args, 'b'))
cdata->cmdq = cmdq;
job_run(shellcmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
cdata);
if (cdata->bflag)
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
@ -121,16 +125,11 @@ static void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job->data;
struct cmd_q *cmdq = cdata->cmdq;
char *cmd, *msg, *line;
char *cmd = cdata->cmd, *msg, *line;
size_t size;
int retcode;
u_int lines;
if (cmdq->flags & CMD_Q_DEAD)
return;
cmd = cdata->cmd;
lines = 0;
do {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
@ -163,16 +162,15 @@ cmd_run_shell_callback(struct job *job)
if (msg != NULL)
cmd_run_shell_print(job, msg);
free(msg);
if (cdata->cmdq != NULL)
cdata->cmdq->flags &= ~CMD_Q_WAITING;
}
static void
cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
struct cmd_q *cmdq = cdata->cmdq;
if (!cmdq_free(cmdq) && !cdata->bflag)
cmdq_continue(cmdq);
free(cdata->cmd);
free(cdata);

View File

@ -62,7 +62,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->state.c;
struct window_pane *wp = cmdq->state.tflag.wp;
struct session *s = cmdq->state.tflag.s;
struct mouse_event *m = &cmdq->item->mouse;
struct mouse_event *m = &cmdq->mouse;
const u_char *keystr;
int i, literal;
key_code key;

View File

@ -28,7 +28,7 @@
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *);
static void cmd_source_file_done(struct cmd_q *);
static enum cmd_retval cmd_source_file_done(struct cmd_q *, void *);
const struct cmd_entry cmd_source_file_entry = {
.name = "source-file",
@ -45,53 +45,31 @@ static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_q *cmdq1;
struct client *c = cmdq->client;
int quiet;
cmdq1 = cmdq_new(cmdq->client);
cmdq1->emptyfn = cmd_source_file_done;
cmdq1->data = cmdq;
struct cmd_q *new_cmdq;
quiet = args_has(args, 'q');
switch (load_cfg(args->argv[0], cmdq1, quiet)) {
switch (load_cfg(args->argv[0], c, cmdq, quiet)) {
case -1:
cmdq_free(cmdq1);
if (cfg_references == 0) {
if (cfg_finished)
cfg_print_causes(cmdq);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_ERROR);
case 0:
cmdq_free(cmdq1);
if (cfg_references == 0)
if (cfg_finished)
cfg_print_causes(cmdq);
return (CMD_RETURN_NORMAL);
}
log_debug("%s: cmdq %p, parent %p", __func__, cmdq1, cmdq);
cmdq->references++;
cfg_references++;
cmdq_continue(cmdq1);
return (CMD_RETURN_WAIT);
if (cfg_finished) {
new_cmdq = cmdq_get_callback(cmd_source_file_done, NULL);
cmdq_insert_after(cmdq, new_cmdq);
}
return (CMD_RETURN_NORMAL);
}
static void
cmd_source_file_done(struct cmd_q *cmdq1)
static enum cmd_retval
cmd_source_file_done(struct cmd_q *cmdq, __unused void *data)
{
struct cmd_q *cmdq = cmdq1->data;
log_debug("%s: cmdq %p, parent %p", __func__, cmdq1, cmdq);
if (cmdq1->client_exit >= 0)
cmdq->client_exit = cmdq1->client_exit;
cmdq_free(cmdq1);
cfg_references--;
if (cmdq_free(cmdq))
return;
if (cfg_references == 0)
cfg_print_causes(cmdq);
cmdq_continue(cmdq);
cfg_print_causes(cmdq);
return (CMD_RETURN_NORMAL);
}

View File

@ -187,8 +187,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
fs.w = w;
fs.wp = new_wp;
cmd_find_log_state(__func__, &fs);
if (hooks_wait(s->hooks, cmdq, &fs, "after-split-window") == 0)
return (CMD_RETURN_WAIT);
hooks_insert(s->hooks, cmdq, &fs, "after-split-window");
return (CMD_RETURN_NORMAL);
error:

View File

@ -41,13 +41,18 @@ const struct cmd_entry cmd_wait_for_entry = {
.exec = cmd_wait_for_exec
};
struct wait_item {
struct cmd_q *cmdq;
TAILQ_ENTRY(wait_item) entry;
};
struct wait_channel {
const char *name;
int locked;
int woken;
TAILQ_HEAD(, cmd_q) waiters;
TAILQ_HEAD(, cmd_q) lockers;
TAILQ_HEAD(, wait_item) waiters;
TAILQ_HEAD(, wait_item) lockers;
RB_ENTRY(wait_channel) entry;
};
@ -135,7 +140,7 @@ static enum cmd_retval
cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
{
struct cmd_q *wq, *wq1;
struct wait_item *wi, *wi1;
if (wc == NULL)
wc = cmd_wait_for_add(name);
@ -147,10 +152,11 @@ cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name,
}
log_debug("signal wait channel %s, with waiters", wc->name);
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
wi->cmdq->flags &= ~CMD_Q_WAITING;
TAILQ_REMOVE(&wc->waiters, wi, entry);
free(wi);
}
cmd_wait_for_remove(wc);
@ -158,10 +164,10 @@ cmd_wait_for_signal(__unused struct cmd_q *cmdq, const char *name,
}
static enum cmd_retval
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, struct wait_channel *wc)
{
struct client *c = cmdq->client;
struct client *c = cmdq->client;
struct wait_item *wi;
if (c == NULL || c->session != NULL) {
cmdq_error(cmdq, "not able to wait");
@ -178,16 +184,18 @@ cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
}
log_debug("wait channel %s not woken (%p)", wc->name, c);
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
cmdq->references++;
wi = xcalloc(1, sizeof *wi);
wi->cmdq = cmdq;
TAILQ_INSERT_TAIL(&wc->waiters, wi, entry);
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
cmd_wait_for_lock(struct cmd_q *cmdq, const char *name, struct wait_channel *wc)
{
struct wait_item *wi;
if (cmdq->client == NULL || cmdq->client->session != NULL) {
cmdq_error(cmdq, "not able to lock");
return (CMD_RETURN_ERROR);
@ -197,8 +205,9 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
wc = cmd_wait_for_add(name);
if (wc->locked) {
TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
cmdq->references++;
wi = xcalloc(1, sizeof *wi);
wi->cmdq = cmdq;
TAILQ_INSERT_TAIL(&wc->lockers, wi, entry);
return (CMD_RETURN_WAIT);
}
wc->locked = 1;
@ -210,17 +219,17 @@ static enum cmd_retval
cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
{
struct cmd_q *wq;
struct wait_item *wi;
if (wc == NULL || !wc->locked) {
cmdq_error(cmdq, "channel %s not locked", name);
return (CMD_RETURN_ERROR);
}
if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
if ((wi = TAILQ_FIRST(&wc->lockers)) != NULL) {
wi->cmdq->flags &= ~CMD_Q_WAITING;
TAILQ_REMOVE(&wc->lockers, wi, entry);
free(wi);
} else {
wc->locked = 0;
cmd_wait_for_remove(wc);
@ -233,19 +242,19 @@ void
cmd_wait_for_flush(void)
{
struct wait_channel *wc, *wc1;
struct cmd_q *wq, *wq1;
struct wait_item *wi, *wi1;
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
wi->cmdq->flags &= ~CMD_Q_WAITING;
TAILQ_REMOVE(&wc->waiters, wi, entry);
free(wi);
}
wc->woken = 1;
TAILQ_FOREACH_SAFE(wq, &wc->lockers, waitentry, wq1) {
TAILQ_REMOVE(&wc->lockers, wq, waitentry);
if (!cmdq_free(wq))
cmdq_continue(wq);
TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
wi->cmdq->flags &= ~CMD_Q_WAITING;
TAILQ_REMOVE(&wc->lockers, wi, entry);
free(wi);
}
wc->locked = 0;
cmd_wait_for_remove(wc);

51
cmd.c
View File

@ -389,12 +389,11 @@ usage:
static int
cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
struct cmd_q *cmdq, struct cmd_q *parent)
struct cmd_q *cmdq)
{
int targetflags, error;
struct cmd_find_state *fs = NULL;
struct cmd_find_state *current = NULL;
struct cmd_find_state tmp;
struct cmd_find_state current;
if (flag == CMD_NONE ||
flag == CMD_CLIENT ||
@ -448,21 +447,12 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
default:
fatalx("unknown %cflag %d", c, flag);
}
log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags);
if (parent != NULL) {
if (c == 't')
current = &parent->state.tflag;
else if (c == 's')
current = &parent->state.sflag;
}
if (current == NULL || !cmd_find_valid_state(current)) {
error = cmd_find_current(&tmp, cmdq, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
current = &tmp;
}
if (!cmd_find_empty_state(current) && !cmd_find_valid_state(current))
error = cmd_find_current(&current, cmdq, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
if (!cmd_find_empty_state(&current) && !cmd_find_valid_state(&current))
fatalx("invalid current state");
switch (flag) {
@ -474,13 +464,13 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
case CMD_SESSION_CANFAIL:
case CMD_SESSION_PREFERUNATTACHED:
case CMD_SESSION_WITHPANE:
error = cmd_find_target(fs, current, cmdq, target,
error = cmd_find_target(fs, &current, cmdq, target,
CMD_FIND_SESSION, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
break;
case CMD_MOVEW_R:
error = cmd_find_target(fs, current, cmdq, target,
error = cmd_find_target(fs, &current, cmdq, target,
CMD_FIND_SESSION, CMD_FIND_QUIET);
if (error == 0)
break;
@ -489,7 +479,7 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
case CMD_WINDOW_CANFAIL:
case CMD_WINDOW_MARKED:
case CMD_WINDOW_INDEX:
error = cmd_find_target(fs, current, cmdq, target,
error = cmd_find_target(fs, &current, cmdq, target,
CMD_FIND_WINDOW, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
@ -497,7 +487,7 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
case CMD_PANE:
case CMD_PANE_CANFAIL:
case CMD_PANE_MARKED:
error = cmd_find_target(fs, current, cmdq, target,
error = cmd_find_target(fs, &current, cmdq, target,
CMD_FIND_PANE, targetflags);
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
return (-1);
@ -509,14 +499,14 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag,
}
int
cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq, struct cmd_q *parent)
cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq)
{
const struct cmd_entry *entry = cmd->entry;
struct cmd_state *state = &cmdq->state;
char *tmp;
enum cmd_entry_flag flag;
const char *s;
int error;
const struct cmd_entry *entry = cmd->entry;
struct cmd_state *state = &cmdq->state;
char *tmp;
enum cmd_entry_flag flag;
const char *s;
int error;
tmp = cmd_print(cmd);
log_debug("preparing state for %s (client %p)", tmp, cmdq->client);
@ -545,18 +535,19 @@ cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq, struct cmd_q *parent)
state->c = cmd_find_client(cmdq, s, 1);
break;
}
log_debug("using client %p", state->c);
s = args_get(cmd->args, 't');
log_debug("preparing -t state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('t', s, entry->tflag, cmdq, parent);
error = cmd_prepare_state_flag('t', s, entry->tflag, cmdq);
if (error != 0)
return (error);
s = args_get(cmd->args, 's');
log_debug("preparing -s state: target %s", s == NULL ? "none" : s);
error = cmd_prepare_state_flag('s', s, entry->sflag, cmdq, parent);
error = cmd_prepare_state_flag('s', s, entry->sflag, cmdq);
if (error != 0)
return (error);

View File

@ -49,6 +49,21 @@ control_write_buffer(struct client *c, struct evbuffer *buffer)
server_client_push_stdout(c);
}
/* Control error callback. */
static enum cmd_retval
control_error(struct cmd_q *cmdq, void *data)
{
struct client *c = cmdq->client;
char *error = data;
cmdq_guard(cmdq, "begin", 1);
control_write(c, "parse error: %s", error);
cmdq_guard(cmdq, "error", 1);
free(error);
return (CMD_RETURN_NORMAL);
}
/* Control input callback. Read lines and fire commands. */
void
control_callback(struct client *c, int closed, __unused void *data)
@ -56,6 +71,7 @@ control_callback(struct client *c, int closed, __unused void *data)
char *line, *cause;
struct cmd_list *cmdlist;
struct cmd *cmd;
struct cmd_q *cmdq;
if (closed)
c->flags |= CLIENT_EXIT;
@ -70,18 +86,13 @@ control_callback(struct client *c, int closed, __unused void *data)
}
if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) {
c->cmdq->time = time(NULL);
c->cmdq->number++;
cmdq_guard(c->cmdq, "begin", 1);
control_write(c, "parse error: %s", cause);
cmdq_guard(c->cmdq, "error", 1);
free(cause);
cmdq = cmdq_get_callback(control_error, cause);
cmdq_append(c, cmdq);
} else {
TAILQ_FOREACH(cmd, &cmdlist->list, qentry)
cmd->flags |= CMD_CONTROL;
cmdq_run(c->cmdq, cmdlist, NULL);
cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmdq_append(c, cmdq);
cmd_list_free(cmdlist);
}

View File

@ -492,7 +492,6 @@ struct format_tree *
format_create(struct cmd_q *cmdq, int flags)
{
struct format_tree *ft;
struct cmd *cmd;
if (!event_initialized(&format_job_event)) {
evtimer_set(&format_job_event, format_job_timer, NULL);
@ -510,11 +509,9 @@ format_create(struct cmd_q *cmdq, int flags)
format_add_tv(ft, "start_time", &start_time);
if (cmdq != NULL && cmdq->cmd != NULL)
format_add(ft, "command_name", "%s", cmdq->cmd->entry->name);
if (cmdq != NULL && cmdq->parent != NULL) {
cmd = cmdq->parent->cmd;
format_add(ft, "command_hooked", "%s", cmd->entry->name);
}
format_add(ft, "command", "%s", cmdq->cmd->entry->name);
if (cmdq != NULL && cmdq->hook != NULL)
format_add(ft, "hook", "%s", cmdq->hook);
return (ft);
}

68
hooks.c
View File

@ -33,7 +33,6 @@ RB_GENERATE_STATIC(hooks_tree, hook, entry, hooks_cmp);
static struct hook *hooks_find1(struct hooks *, const char *);
static void hooks_free1(struct hooks *, struct hook *);
static void hooks_emptyfn(struct cmd_q *);
static int
hooks_cmp(struct hook *hook1, struct hook *hook2)
@ -140,28 +139,14 @@ hooks_find(struct hooks *hooks, const char *name)
return (hook);
}
static void
hooks_emptyfn(struct cmd_q *hooks_cmdq)
{
struct cmd_q *cmdq = hooks_cmdq->data;
if (cmdq != NULL) {
if (hooks_cmdq->client_exit >= 0)
cmdq->client_exit = hooks_cmdq->client_exit;
if (!cmdq_free(cmdq))
cmdq_continue(cmdq);
}
cmdq_free(hooks_cmdq);
}
int
void
hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
const char *fmt, ...)
{
struct hook *hook;
struct cmd_q *hooks_cmdq;
va_list ap;
char *name;
struct cmd_q *new_cmdq, *loop;
va_start(ap, fmt);
xvasprintf(&name, fmt, ap);
@ -170,34 +155,30 @@ hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
hook = hooks_find(hooks, name);
if (hook == NULL) {
free(name);
return (-1);
return;
}
log_debug("running hook %s", name);
new_cmdq = cmdq_get_command(hook->cmdlist, fs, NULL, CMD_Q_NOHOOKS);
for (loop = new_cmdq; loop != NULL; loop = loop->next)
loop->hook = xstrdup(name);
free(name);
hooks_cmdq = cmdq_new(c);
hooks_cmdq->flags |= CMD_Q_NOHOOKS;
if (fs != NULL)
cmd_find_copy_state(&hooks_cmdq->current, fs);
hooks_cmdq->parent = NULL;
cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
cmdq_free(hooks_cmdq);
return (0);
cmdq_append(c, new_cmdq);
}
int
hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
void
hooks_insert(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
const char *fmt, ...)
{
struct hook *hook;
struct cmd_q *hooks_cmdq;
va_list ap;
char *name;
struct cmd_q *new_cmdq, *loop;
if (cmdq->flags & CMD_Q_NOHOOKS)
return (-1);
return;
va_start(ap, fmt);
xvasprintf(&name, fmt, ap);
@ -206,23 +187,18 @@ hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
hook = hooks_find(hooks, name);
if (hook == NULL) {
free(name);
return (-1);
return;
}
log_debug("running hook %s (parent %p)", name, cmdq);
new_cmdq = cmdq_get_command(hook->cmdlist, fs, NULL, CMD_Q_NOHOOKS);
for (loop = new_cmdq; loop != NULL; loop = loop->next)
loop->hook = xstrdup(name);
free(name);
hooks_cmdq = cmdq_new(cmdq->client);
hooks_cmdq->flags |= CMD_Q_NOHOOKS;
if (fs != NULL)
cmd_find_copy_state(&hooks_cmdq->current, fs);
hooks_cmdq->parent = cmdq;
hooks_cmdq->emptyfn = hooks_emptyfn;
hooks_cmdq->data = cmdq;
if (cmdq != NULL)
cmdq->references++;
cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
return (0);
cmdq_insert_after(cmdq, new_cmdq);
else
cmdq_append(NULL, new_cmdq);
}

View File

@ -377,18 +377,22 @@ key_bindings_init(void)
struct cmd_list *cmdlist;
char *cause;
int error;
struct cmd_q *cmdq;
cmdq = cmdq_new(NULL);
for (i = 0; i < nitems(defaults); i++) {
error = cmd_string_parse(defaults[i], &cmdlist,
"<default-keys>", i, &cause);
if (error != 0)
fatalx("bad default key");
cmdq_run(cmdq, cmdlist, NULL);
cmdq_append(NULL, cmdq_get_command(cmdlist, NULL, NULL, 0));
cmd_list_free(cmdlist);
}
cmdq_free(cmdq);
}
static enum cmd_retval
key_bindings_read_only(struct cmd_q *cmdq, __unused void *data)
{
cmdq_error(cmdq, "client is read-only");
return (CMD_RETURN_ERROR);
}
void
@ -403,10 +407,8 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c,
if (!(cmd->entry->flags & CMD_READONLY))
readonly = 0;
}
if (!readonly && (c->flags & CLIENT_READONLY)) {
cmdq_error(c->cmdq, "client is read-only");
return;
}
cmdq_run(c->cmdq, bd->cmdlist, m);
if (!readonly && (c->flags & CLIENT_READONLY))
cmdq_append(c, cmdq_get_callback(key_bindings_read_only, NULL));
else
cmdq_append(c, cmdq_get_command(bd->cmdlist, NULL, m, 0));
}

View File

@ -65,7 +65,7 @@ notify_hook(struct notify_entry *ne)
const char *name;
struct cmd_find_state fs;
struct hook *hook;
struct cmd_q *hooks_cmdq;
struct cmd_q *new_cmdq, *loop;
name = notify_hooks[ne->type];
if (name == NULL)
@ -86,14 +86,12 @@ notify_hook(struct notify_entry *ne)
return;
log_debug("notify hook %s", name);
hooks_cmdq = cmdq_new(NULL);
hooks_cmdq->flags |= CMD_Q_NOHOOKS;
new_cmdq = cmdq_get_command(hook->cmdlist, &fs, NULL, CMD_Q_NOHOOKS);
cmd_find_copy_state(&hooks_cmdq->current, &fs);
hooks_cmdq->parent = NULL;
for (loop = new_cmdq; loop != NULL; loop = loop->next)
loop->hook = xstrdup(name);
cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
cmdq_free(hooks_cmdq);
cmdq_append(NULL, new_cmdq);
}
static void

View File

@ -124,8 +124,7 @@ server_client_create(int fd)
c->fd = -1;
c->cwd = NULL;
c->cmdq = cmdq_new(c);
c->cmdq->client_exit = 1;
TAILQ_INIT(&c->queue);
c->stdin_data = evbuffer_new();
c->stdout_data = evbuffer_new();
@ -242,10 +241,6 @@ server_client_lost(struct client *c)
free(c->prompt_string);
free(c->prompt_buffer);
c->cmdq->flags |= CMD_Q_DEAD;
cmdq_free(c->cmdq);
c->cmdq = NULL;
environ_free(c->environ);
proc_remove_peer(c->peer);
@ -279,6 +274,9 @@ server_client_free(__unused int fd, __unused short events, void *arg)
log_debug("free client %p (%d references)", c, c->references);
if (!TAILQ_EMPTY(&c->queue))
fatalx("queue not empty");
if (c->references == 0)
free(c);
}
@ -1262,6 +1260,29 @@ server_client_dispatch(struct imsg *imsg, void *arg)
}
}
/* Callback when command is done. */
static enum cmd_retval
server_client_command_done(struct cmd_q *cmdq, __unused void *data)
{
struct client *c = cmdq->client;
if (~c->flags & CLIENT_ATTACHED)
c->flags |= CLIENT_EXIT;
return (CMD_RETURN_NORMAL);
}
/* Show an error message. */
static enum cmd_retval
server_client_command_error(struct cmd_q *cmdq, void *data)
{
char *error = data;
cmdq_error(cmdq, "%s", error);
free(error);
return (CMD_RETURN_NORMAL);
}
/* Handle command message. */
static void
server_client_dispatch_command(struct client *c, struct imsg *imsg)
@ -1284,7 +1305,7 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
argc = data.argc;
if (cmd_unpack_argv(buf, len, argc, &argv) != 0) {
cmdq_error(c->cmdq, "command too long");
cause = xstrdup("command too long");
goto error;
}
@ -1295,20 +1316,19 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
}
if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) {
cmdq_error(c->cmdq, "%s", cause);
cmd_free_argv(argc, argv);
goto error;
}
cmd_free_argv(argc, argv);
if (c != cfg_client || cfg_finished)
cmdq_run(c->cmdq, cmdlist, NULL);
else
cmdq_append(c->cmdq, cmdlist, NULL);
cmdq_append(c, cmdq_get_command(cmdlist, NULL, NULL, 0));
cmdq_append(c, cmdq_get_callback(server_client_command_done, NULL));
cmd_list_free(cmdlist);
return;
error:
cmdq_append(c, cmdq_get_callback(server_client_command_error, cause));
if (cmdlist != NULL)
cmd_list_free(cmdlist);

View File

@ -192,9 +192,17 @@ static int
server_loop(void)
{
struct client *c;
u_int items;
notify_drain();
do {
items = cmdq_next(NULL);
TAILQ_FOREACH(c, &clients, entry)
items += cmdq_next(c);
} while (items != 0);
server_client_loop();
notify_drain();
if (!options_get_number(global_options, "exit-unattached")) {
if (!RB_EMPTY(&sessions))

4
tmux.1
View File

@ -3460,8 +3460,7 @@ The following variables are available, where appropriate:
.It Li "client_tty" Ta "" Ta "Pseudo terminal of client"
.It Li "client_utf8" Ta "" Ta "1 if client supports utf8"
.It Li "client_width" Ta "" Ta "Width of client"
.It Li "command_hooked" Ta "" Ta "Name of command hooked, if any"
.It Li "command_name" Ta "" Ta "Name of command in use, if any"
.It Li "command" Ta "" Ta "Name of command in use, if any"
.It Li "command_list_name" Ta "" Ta "Command name if listing commands"
.It Li "command_list_alias" Ta "" Ta "Command alias if listing commands"
.It Li "command_list_usage" Ta "" Ta "Command usage if listing commands"
@ -3471,6 +3470,7 @@ The following variables are available, where appropriate:
.It Li "history_bytes" Ta "" Ta "Number of bytes in window history"
.It Li "history_limit" Ta "" Ta "Maximum window history lines"
.It Li "history_size" Ta "" Ta "Size of history in bytes"
.It Li "hook" Ta "" Ta "Name of running hook, if any"
.It Li "host" Ta "#H" Ta "Hostname of local host"
.It Li "host_short" Ta "#h" Ta "Hostname of local host (no domain name)"
.It Li "insert_flag" Ta "" Ta "Pane insert flag"

268
tmux.h
View File

@ -42,6 +42,8 @@ extern char **environ;
struct args;
struct client;
struct cmd_q;
struct cmd_q_list;
struct environ;
struct input_ctx;
struct mode_key_cmdstr;
@ -633,7 +635,6 @@ struct grid {
struct hook {
const char *name;
struct cmd_q *cmdq;
struct cmd_list *cmdlist;
RB_ENTRY(hook) entry;
@ -1162,101 +1163,6 @@ struct message_entry {
TAILQ_ENTRY(message_entry) entry;
};
/* Client connection. */
struct client {
struct tmuxpeer *peer;
pid_t pid;
int fd;
struct event event;
int retval;
struct timeval creation_time;
struct timeval activity_time;
struct environ *environ;
char *title;
const char *cwd;
char *term;
char *ttyname;
struct tty tty;
void (*stdin_callback)(struct client *, int, void *);
void *stdin_callback_data;
struct evbuffer *stdin_data;
int stdin_closed;
struct evbuffer *stdout_data;
struct evbuffer *stderr_data;
struct event repeat_timer;
struct event click_timer;
u_int click_button;
struct event status_timer;
struct screen status;
#define CLIENT_TERMINAL 0x1
#define CLIENT_LOGIN 0x2
#define CLIENT_EXIT 0x4
#define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10
#define CLIENT_REPEAT 0x20
#define CLIENT_SUSPENDED 0x40
/* 0x80 unused */
#define CLIENT_IDENTIFY 0x100
#define CLIENT_DEAD 0x200
#define CLIENT_BORDERS 0x400
#define CLIENT_READONLY 0x800
#define CLIENT_REDRAWWINDOW 0x1000
#define CLIENT_CONTROL 0x2000
#define CLIENT_CONTROLCONTROL 0x4000
#define CLIENT_FOCUSED 0x8000
#define CLIENT_UTF8 0x10000
#define CLIENT_256COLOURS 0x20000
#define CLIENT_IDENTIFIED 0x40000
#define CLIENT_STATUSFORCE 0x80000
#define CLIENT_DOUBLECLICK 0x100000
#define CLIENT_TRIPLECLICK 0x200000
int flags;
struct key_table *keytable;
struct event identify_timer;
void (*identify_callback)(struct client *, struct window_pane *);
void *identify_callback_data;
char *message_string;
struct event message_timer;
u_int message_next;
TAILQ_HEAD(, message_entry) message_log;
char *prompt_string;
struct utf8_data *prompt_buffer;
size_t prompt_index;
int (*prompt_callbackfn)(void *, const char *);
void (*prompt_freefn)(void *);
void *prompt_data;
u_int prompt_hindex;
enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode;
#define PROMPT_SINGLE 0x1
#define PROMPT_NUMERIC 0x2
int prompt_flags;
struct session *session;
struct session *last_session;
int wlmouse;
struct cmd_q *cmdq;
int references;
TAILQ_ENTRY(client) entry;
};
TAILQ_HEAD(clients, client);
/* Parsed arguments structures. */
struct args_entry;
RB_HEAD(args_tree, args_entry);
@ -1326,42 +1232,46 @@ enum cmd_retval {
CMD_RETURN_STOP
};
/* Command queue entry. */
struct cmd_q_item {
struct cmd_list *cmdlist;
struct mouse_event mouse;
TAILQ_ENTRY(cmd_q_item) qentry;
/* Command queue item type. */
enum cmd_q_type {
CMD_Q_COMMAND,
CMD_Q_CALLBACK,
};
TAILQ_HEAD(cmd_q_items, cmd_q_item);
/* Command queue. */
/* Command queue item. */
typedef enum cmd_retval (*cmd_q_cb) (struct cmd_q *, void *);
struct cmd_q {
int references;
int flags;
#define CMD_Q_DEAD 0x1
#define CMD_Q_NOHOOKS 0x2
struct cmd_q_list *queue;
struct cmd_q *next;
struct client *client;
int client_exit;
struct cmd_q_items queue;
struct cmd_q_item *item;
enum cmd_q_type type;
u_int group;
u_int number;
time_t time;
const char *hook;
int flags;
#define CMD_Q_FIRED 0x1
#define CMD_Q_WAITING 0x2
#define CMD_Q_NOHOOKS 0x4
struct cmd_list *cmdlist;
struct cmd *cmd;
struct cmd_q *parent;
cmd_q_cb cb;
void *data;
struct cmd_find_state current;
struct cmd_state state;
time_t time;
u_int number;
struct mouse_event mouse;
void (*emptyfn)(struct cmd_q *);
void *data;
TAILQ_ENTRY(cmd_q) waitentry;
TAILQ_ENTRY(cmd_q) entry;
};
TAILQ_HEAD(cmd_q_list, cmd_q);
/* Command -c, -t or -s flags. */
enum cmd_entry_flag {
@ -1411,6 +1321,101 @@ struct cmd_entry {
enum cmd_retval (*exec)(struct cmd *, struct cmd_q *);
};
/* Client connection. */
struct client {
struct tmuxpeer *peer;
struct cmd_q_list queue;
pid_t pid;
int fd;
struct event event;
int retval;
struct timeval creation_time;
struct timeval activity_time;
struct environ *environ;
char *title;
const char *cwd;
char *term;
char *ttyname;
struct tty tty;
void (*stdin_callback)(struct client *, int, void *);
void *stdin_callback_data;
struct evbuffer *stdin_data;
int stdin_closed;
struct evbuffer *stdout_data;
struct evbuffer *stderr_data;
struct event repeat_timer;
struct event click_timer;
u_int click_button;
struct event status_timer;
struct screen status;
#define CLIENT_TERMINAL 0x1
#define CLIENT_LOGIN 0x2
#define CLIENT_EXIT 0x4
#define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10
#define CLIENT_REPEAT 0x20
#define CLIENT_SUSPENDED 0x40
#define CLIENT_ATTACHED 0x80
#define CLIENT_IDENTIFY 0x100
#define CLIENT_DEAD 0x200
#define CLIENT_BORDERS 0x400
#define CLIENT_READONLY 0x800
#define CLIENT_REDRAWWINDOW 0x1000
#define CLIENT_CONTROL 0x2000
#define CLIENT_CONTROLCONTROL 0x4000
#define CLIENT_FOCUSED 0x8000
#define CLIENT_UTF8 0x10000
#define CLIENT_256COLOURS 0x20000
#define CLIENT_IDENTIFIED 0x40000
#define CLIENT_STATUSFORCE 0x80000
#define CLIENT_DOUBLECLICK 0x100000
#define CLIENT_TRIPLECLICK 0x200000
int flags;
struct key_table *keytable;
struct event identify_timer;
void (*identify_callback)(struct client *, struct window_pane *);
void *identify_callback_data;
char *message_string;
struct event message_timer;
u_int message_next;
TAILQ_HEAD(, message_entry) message_log;
char *prompt_string;
struct utf8_data *prompt_buffer;
size_t prompt_index;
int (*prompt_callbackfn)(void *, const char *);
void (*prompt_freefn)(void *);
void *prompt_data;
u_int prompt_hindex;
enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode;
#define PROMPT_SINGLE 0x1
#define PROMPT_NUMERIC 0x2
int prompt_flags;
struct session *session;
struct session *last_session;
int wlmouse;
int references;
TAILQ_ENTRY(client) entry;
};
TAILQ_HEAD(clients, client);
/* Key binding and key table. */
struct key_binding {
key_code key;
@ -1506,10 +1511,9 @@ void proc_kill_peer(struct tmuxpeer *);
/* cfg.c */
extern int cfg_finished;
extern int cfg_references;
extern struct client *cfg_client;
void start_cfg(void);
int load_cfg(const char *, struct cmd_q *, int);
int load_cfg(const char *, struct client *, struct cmd_q *, int);
void set_cfg_file(const char *);
void printflike(1, 2) cfg_add_cause(const char *, ...);
void cfg_print_causes(struct cmd_q *);
@ -1559,9 +1563,9 @@ void hooks_add(struct hooks *, const char *, struct cmd_list *);
void hooks_copy(struct hooks *, struct hooks *);
void hooks_remove(struct hooks *, const char *);
struct hook *hooks_find(struct hooks *, const char *);
int printflike(4, 5) hooks_run(struct hooks *, struct client *,
void printflike(4, 5) hooks_run(struct hooks *, struct client *,
struct cmd_find_state *, const char *, ...);
int printflike(4, 5) hooks_wait(struct hooks *, struct cmd_q *,
void printflike(4, 5) hooks_insert(struct hooks *, struct cmd_q *,
struct cmd_find_state *, const char *, ...);
/* mode-key.c */
@ -1757,8 +1761,7 @@ char **cmd_copy_argv(int, char **);
void cmd_free_argv(int, char **);
char *cmd_stringify_argv(int, char **);
struct cmd *cmd_parse(int, char **, const char *, u_int, char **);
int cmd_prepare_state(struct cmd *, struct cmd_q *,
struct cmd_q *);
int cmd_prepare_state(struct cmd *, struct cmd_q *);
char *cmd_print(struct cmd *);
int cmd_mouse_at(struct window_pane *, struct mouse_event *,
u_int *, u_int *, int);
@ -1778,16 +1781,15 @@ void cmd_list_free(struct cmd_list *);
char *cmd_list_print(struct cmd_list *);
/* cmd-queue.c */
struct cmd_q *cmdq_new(struct client *);
int cmdq_free(struct cmd_q *);
struct cmd_q *cmdq_get_command(struct cmd_list *, struct cmd_find_state *,
struct mouse_event *, int);
struct cmd_q *cmdq_get_callback(cmd_q_cb, void *);
void cmdq_insert_after(struct cmd_q *, struct cmd_q *);
void cmdq_append(struct client *, struct cmd_q *);
u_int cmdq_next(struct client *);
void cmdq_guard(struct cmd_q *, const char *, int);
void printflike(2, 3) cmdq_print(struct cmd_q *, const char *, ...);
void printflike(2, 3) cmdq_error(struct cmd_q *, const char *, ...);
void cmdq_guard(struct cmd_q *, const char *, int);
void cmdq_run(struct cmd_q *, struct cmd_list *,
struct mouse_event *);
void cmdq_append(struct cmd_q *, struct cmd_list *,
struct mouse_event *);
int cmdq_continue(struct cmd_q *);
/* cmd-string.c */
int cmd_string_parse(const char *, struct cmd_list **, const char *,

View File

@ -246,6 +246,7 @@ window_choose_data_run(struct window_choose_data *cdata)
{
struct cmd_list *cmdlist;
char *cause;
struct cmd_q *cmdq;
/*
* The command template will have already been replaced. But if it's
@ -263,7 +264,8 @@ window_choose_data_run(struct window_choose_data *cdata)
return;
}
cmdq_run(cdata->start_client->cmdq, cmdlist, NULL);
cmdq = cmdq_get_command(cmdlist, NULL, NULL, 0);
cmdq_append(cdata->start_client, cmdq);
cmd_list_free(cmdlist);
}