diff options
author | Nicholas Marriott <nicholas.marriott@gmail.com> | 2013-02-23 22:25:58 +0000 |
---|---|---|
committer | Nicholas Marriott <nicholas.marriott@gmail.com> | 2013-02-23 22:25:58 +0000 |
commit | 3964309c67a683e5132662e38b5ff932af5cbeea (patch) | |
tree | f8566b756787ef7ceeed61e63f61b2a0ece4c751 | |
parent | 357da035b9d052b4cba8db806c6237272ade6673 (diff) |
Add a command queue to standardize and simplify commands that call other
commands and allow a command to block execution of subsequent commands. This
allows run-shell and if-shell to be synchronous which has been much requested.
Each client has a default command queue and commands are consumed one at a time
from it. A command may suspend execution from the queue by returning
CMD_RETURN_WAIT and then resume it by calling cmd_continue() - for example
run-shell does this from the callback that is fired after the job is freed.
When the command queue becomes empty, command clients are automatically exited
(unless attaching). A callback is also fired - this is used for nested commands
in, for example, if-shell which can block execution of the client's cmdq until
a new cmdq becomes empty.
Also merge all the old error/info/print functions together and lose the old
curclient/cmdclient distinction - a cmdq is bound to one client (or none if in
the configuration file), this is a command client if c->session is NULL
otherwise an attached client.
86 files changed, 1218 insertions, 1219 deletions
diff --git a/Makefile.am b/Makefile.am index ddeacd9a..5caa4983 100644 --- a/Makefile.am +++ b/Makefile.am @@ -104,6 +104,7 @@ dist_tmux_SOURCES = \ cmd-new-window.c \ cmd-paste-buffer.c \ cmd-pipe-pane.c \ + cmd-queue.c \ cmd-refresh-client.c \ cmd-rename-session.c \ cmd-rename-window.c \ @@ -27,80 +27,27 @@ #include "tmux.h" -/* - * Config file parser. Pretty quick and simple, each line is parsed into a - * argv array and executed as a command. - */ - -void printflike2 cfg_print(struct cmd_ctx *, const char *, ...); -void printflike2 cfg_error(struct cmd_ctx *, const char *, ...); - -char *cfg_cause; +struct cmd_q *cfg_cmd_q; int cfg_finished; -int cfg_references; +int cfg_references; struct causelist cfg_causes; -void printflike2 -cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...) -{ -} - -void printflike2 -cfg_error(unused struct cmd_ctx *ctx, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - xvasprintf(&cfg_cause, fmt, ap); - va_end(ap); -} - -void printflike2 -cfg_add_cause(struct causelist *causes, const char *fmt, ...) -{ - char *cause; - va_list ap; - - va_start(ap, fmt); - xvasprintf(&cause, fmt, ap); - va_end(ap); - - ARRAY_ADD(causes, cause); -} - -/* - * Load configuration file. Returns -1 for an error with a list of messages in - * causes. Note that causes must be initialised by the caller! - */ -enum cmd_retval -load_cfg(const char *path, struct cmd_ctx *ctx, struct causelist *causes) +int +load_cfg(const char *path, struct cmd_q *cmdq, char **cause) { FILE *f; - u_int n; - char *buf, *copy, *line, *cause; + u_int n, found; + char *buf, *copy, *line, *cause1, *msg; size_t len, oldlen; struct cmd_list *cmdlist; - enum cmd_retval retval; if ((f = fopen(path, "rb")) == NULL) { - cfg_add_cause(causes, "%s: %s", path, strerror(errno)); - return (CMD_RETURN_ERROR); - } - - cfg_references++; - - if (ctx != NULL) - cmd_ref_ctx(ctx); - else { - ctx = cmd_get_ctx(NULL, NULL); - ctx->error = cfg_error; - ctx->print = cfg_print; - ctx->info = cfg_print; + xasprintf(cause, "%s: %s", path, strerror(errno)); + return (-1); } - n = 0; + n = found = 0; line = NULL; - retval = CMD_RETURN_NORMAL; while ((buf = fgetln(f, &len))) { /* Trim \n. */ if (buf[len - 1] == '\n') @@ -142,53 +89,47 @@ load_cfg(const char *path, struct cmd_ctx *ctx, struct causelist *causes) continue; } - if (cmd_string_parse(buf, &cmdlist, &cause) != 0) { + /* Parse and run the command. */ + if (cmd_string_parse(buf, &cmdlist, path, n, &cause1) != 0) { free(copy); - if (cause == NULL) + if (cause1 == NULL) continue; - cfg_add_cause(causes, "%s: %u: %s", path, n, cause); - free(cause); + xasprintf(&msg, "%s:%u: %s", path, n, cause1); + ARRAY_ADD(&cfg_causes, msg); + free(cause1); continue; } free(copy); + if (cmdlist == NULL) continue; - - cfg_cause = NULL; - switch (cmd_list_exec(cmdlist, ctx)) { - case CMD_RETURN_YIELD: - if (retval != CMD_RETURN_ATTACH) - retval = CMD_RETURN_YIELD; - break; - case CMD_RETURN_ATTACH: - retval = CMD_RETURN_ATTACH; - break; - case CMD_RETURN_ERROR: - case CMD_RETURN_NORMAL: - break; - } + cmdq_append(cmdq, cmdlist); cmd_list_free(cmdlist); - if (cfg_cause != NULL) { - cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause); - free(cfg_cause); - } + found++; } - if (line != NULL) { - cfg_add_cause(causes, - "%s: %d: line continuation at end of file", path, n); + if (line != NULL) free(line); - } fclose(f); - cmd_free_ctx(ctx); + return (found); +} + +void +cfg_default_done(unused struct cmd_q *cmdq) +{ + if (--cfg_references != 0) + return; + cfg_finished = 1; - cfg_references--; + if (!RB_EMPTY(&sessions)) + cfg_show_causes(RB_MIN(sessions, &sessions)); - return (retval); + cmdq_free(cfg_cmd_q); + cfg_cmd_q = NULL; } void -show_cfg_causes(struct session *s) +cfg_show_causes(struct session *s) { struct window_pane *wp; char *cause; @@ -196,7 +137,6 @@ show_cfg_causes(struct session *s) if (s == NULL || ARRAY_EMPTY(&cfg_causes)) return; - wp = s->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); @@ -188,7 +188,8 @@ client_main(int argc, char **argv, int flags) * later in server) but it is necessary to get the start server * flag. */ - if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { + cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause); + if (cmdlist == NULL) { fprintf(stderr, "%s\n", cause); return (1); } diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 18a20244..5c8f76ed 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -26,7 +26,7 @@ * Attach existing session to the current terminal. */ -enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_attach_session_entry = { }; enum cmd_retval -cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; @@ -49,17 +49,17 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) u_int i; if (RB_EMPTY(&sessions)) { - ctx->error(ctx, "no sessions"); + cmdq_error(cmdq, "no sessions"); return (CMD_RETURN_ERROR); } - if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL) + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 1)) == NULL) return (CMD_RETURN_ERROR); - if (ctx->cmdclient == NULL && ctx->curclient == NULL) + if (cmdq->client == NULL) return (CMD_RETURN_NORMAL); - if (ctx->cmdclient == NULL) { + if (cmdq->client->session != NULL) { if (args_has(self->args, 'd')) { /* * Can't use server_write_session in case attaching to @@ -69,43 +69,44 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx) c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; - if (c == ctx->curclient) + if (c == cmdq->client) continue; server_write_client(c, MSG_DETACH, NULL, 0); } } - ctx->curclient->session = s; - notify_attached_session_changed(ctx->curclient); + cmdq->client->session = s; + notify_attached_session_changed(cmdq->client); session_update_activity(s); - server_redraw_client(ctx->curclient); + server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { - if (server_client_open(ctx->cmdclient, s, &cause) != 0) { - ctx->error(ctx, "open terminal failed: %s", cause); + if (server_client_open(cmdq->client, s, &cause) != 0) { + cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } if (args_has(self->args, 'r')) - ctx->cmdclient->flags |= CLIENT_READONLY; + cmdq->client->flags |= CLIENT_READONLY; if (args_has(self->args, 'd')) server_write_session(s, MSG_DETACH, NULL, 0); - ctx->cmdclient->session = s; - notify_attached_session_changed(ctx->cmdclient); - session_update_activity(s); - server_write_ready(ctx->cmdclient); - update = options_get_string(&s->options, "update-environment"); - environ_update(update, &ctx->cmdclient->environ, &s->environ); + environ_update(update, &cmdq->client->environ, &s->environ); - server_redraw_client(ctx->cmdclient); + cmdq->client->session = s; + notify_attached_session_changed(cmdq->client); + session_update_activity(s); + server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; + + server_write_ready(cmdq->client); + cmdq->client_exit = 0; } recalculate_sizes(); server_update_socket(); - return (CMD_RETURN_ATTACH); + return (CMD_RETURN_NORMAL); } diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 2a7b482a..71e79ea0 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -28,9 +28,9 @@ */ enum cmd_retval cmd_bind_key_check(struct args *); -enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); -enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int); +enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_q *, int); const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", @@ -56,7 +56,7 @@ cmd_bind_key_check(struct args *args) } enum cmd_retval -cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; char *cause; @@ -65,16 +65,17 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { - ctx->error(ctx, "unknown key: %s", args->argv[0]); + cmdq_error(cmdq, "unknown key: %s", args->argv[0]); return (CMD_RETURN_ERROR); } if (args_has(args, 't')) - return (cmd_bind_key_table(self, ctx, key)); + return (cmd_bind_key_table(self, cmdq, key)); - cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, &cause); + cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0, + &cause); if (cmdlist == NULL) { - ctx->error(ctx, "%s", cause); + cmdq_error(cmdq, "%s", cause); free(cause); return (CMD_RETURN_ERROR); } @@ -86,7 +87,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx) } enum cmd_retval -cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) +cmd_bind_key_table(struct cmd *self, struct cmd_q *cmdq, int key) { struct args *args = self->args; const char *tablename; @@ -97,25 +98,25 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key) tablename = args_get(args, 't'); if ((mtab = mode_key_findtable(tablename)) == NULL) { - ctx->error(ctx, "unknown key table: %s", tablename); + cmdq_error(cmdq, "unknown key table: %s", tablename); return (CMD_RETURN_ERROR); } cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]); if (cmd == MODEKEY_NONE) { - ctx->error(ctx, "unknown command: %s", args->argv[1]); + cmdq_error(cmdq, "unknown command: %s", args->argv[1]); return (CMD_RETURN_ERROR); } if (cmd != MODEKEYCOPY_COPYPIPE) { if (args->argc != 2) { - ctx->error(ctx, "no argument allowed"); + cmdq_error(cmdq, "no argument allowed"); return (CMD_RETURN_ERROR); } arg = NULL; } else { if (args->argc != 3) { - ctx->error(ctx, "no argument given"); + cmdq_error(cmdq, "no argument given"); return (CMD_RETURN_ERROR); } arg = args->argv[2]; diff --git a/cmd-break-pane.c b/cmd-break-pane.c index c270ca07..957fe563 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -26,7 +26,7 @@ * Break pane off into a window. */ -enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_break_pane_entry = { "break-pane", "breakp", @@ -39,7 +39,7 @@ const struct cmd_entry cmd_break_pane_entry = { }; enum cmd_retval -cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) +cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct winlink *wl; @@ -54,11 +54,11 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) const char *template; char *cp; - if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL) + if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) return (CMD_RETURN_ERROR); if (window_count_panes(wl->window) == 1) { - ctx->error(ctx, "can't break with only one pane"); + cmdq_error(cmdq, "can't break with only one pane"); return (CMD_RETURN_ERROR); } @@ -97,14 +97,14 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx) template = BREAK_PANE_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(ctx, NULL, 1)) != NULL) + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, wl); format_window_pane(ft, wp); cp = format_expand(ft, template); - ctx->print(ctx, "%s", cp); + cmdq_print(cmdq, "%s", cp); free(cp); format_free(ft); diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index fd65e093..cd899dd4 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -27,7 +27,7 @@ * Write the entire contents of a pane to a buffer or stdout. */ -enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *); +enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_capture_pane_entry = { "capture-pane", "capturep", @@ -41,7 +41,7 @@ const struct cmd_entry cmd_ca |