mirror of
https://github.com/tmux/tmux.git
synced 2025-01-05 23:38:48 +00:00
Rewrite command queue handling. Each client still has a command queue,
but there is also now a global command queue. Instead of command queues being dispatched on demand from wherever the command happens to be added, they are now all dispatched from the top level server loop. Command queues may now also include callbacks as well as commands, and items may be inserted after the current command as well as at the end. This all makes command queues significantly more predictable and easier to use, and avoids the complex multiple nested command queues used by source-file, if-shell and friends. A mass rename of struct cmdq to a better name (cmdq_item probably) is coming.
This commit is contained in:
parent
bfe14b5312
commit
ddc4512d2e
70
cfg.c
70
cfg.c
@ -29,14 +29,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)
|
||||
@ -51,30 +62,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' };
|
||||
@ -82,6 +87,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) {
|
||||
@ -117,8 +123,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);
|
||||
@ -126,37 +137,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, ...)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -1006,7 +1006,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);
|
||||
|
110
cmd-if-shell.c
110
cmd-if-shell.c
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
489
cmd-queue.c
489
cmd-queue.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -188,8 +188,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:
|
||||
|
@ -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
51
cmd.c
@ -390,12 +390,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 ||
|
||||
@ -449,21 +448,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(¤t, cmdq, targetflags);
|
||||
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
|
||||
return (-1);
|
||||
if (!cmd_find_empty_state(¤t) && !cmd_find_valid_state(¤t))
|
||||
fatalx("invalid current state");
|
||||
|
||||
switch (flag) {
|
||||
@ -475,13 +465,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, ¤t, 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, ¤t, cmdq, target,
|
||||
CMD_FIND_SESSION, CMD_FIND_QUIET);
|
||||
if (error == 0)
|
||||
break;
|
||||
@ -490,7 +480,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, ¤t, cmdq, target,
|
||||
CMD_FIND_WINDOW, targetflags);
|
||||
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
|
||||
return (-1);
|
||||
@ -498,7 +488,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, ¤t, cmdq, target,
|
||||
CMD_FIND_PANE, targetflags);
|
||||
if (error != 0 && ~targetflags & CMD_FIND_QUIET)
|
||||
return (-1);
|
||||
@ -510,14 +500,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);
|
||||
@ -546,18 +536,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);
|
||||
|
||||
|
29
control.c
29
control.c
@ -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);
|
||||
}
|
||||
|
||||
|
9
format.c
9
format.c
@ -473,7 +473,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);
|
||||
@ -491,11 +490,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
68
hooks.c
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
12
notify.c
12
notify.c
@ -66,7 +66,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)
|
||||
@ -87,14 +87,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
|
||||
|
@ -126,8 +126,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();
|
||||
@ -244,10 +243,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);
|
||||
@ -281,6 +276,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);
|
||||
}
|
||||
@ -1254,6 +1252,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)
|
||||
@ -1276,7 +1297,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;
|
||||
}
|
||||
|
||||
@ -1287,20 +1308,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);
|
||||
|
||||
|
10
server.c
10
server.c
@ -190,9 +190,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
4
tmux.1
@ -3456,8 +3456,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"
|
||||
@ -3467,6 +3466,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
268
tmux.h
@ -40,6 +40,8 @@ extern char **environ;
|
||||
|
||||
struct args;
|
||||
struct client;
|
||||
struct cmd_q;
|
||||
struct cmd_q_list;
|
||||
struct environ;
|
||||
struct input_ctx;
|
||||
struct mode_key_cmdstr;
|
||||
@ -631,7 +633,6 @@ struct grid {
|
||||
struct hook {
|
||||
const char *name;
|
||||
|
||||
struct cmd_q *cmdq;
|
||||
struct cmd_list *cmdlist;
|
||||
|
||||
RB_ENTRY(hook) entry;
|
||||
@ -1160,101 +1161,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);
|
||||
@ -1324,42 +1230,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 {
|
||||
@ -1409,6 +1319,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;
|
||||
@ -1504,10 +1509,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 *);
|
||||
@ -1557,9 +1561,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 */
|
||||
@ -1755,8 +1759,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);
|
||||
@ -1776,16 +1779,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 *,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user