Skip to content

Commit

Permalink
Add a command queue to standardize and simplify commands that call other
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nicm committed Feb 23, 2013
1 parent 357da03 commit 3964309
Show file tree
Hide file tree
Showing 86 changed files with 1,218 additions and 1,219 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
126 changes: 33 additions & 93 deletions cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -142,61 +89,54 @@ 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;
u_int i;

if (s == NULL || ARRAY_EMPTY(&cfg_causes))
return;

wp = s->curw->window->active;

window_pane_set_mode(wp, &window_copy_mode);
Expand Down
3 changes: 2 additions & 1 deletion client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
43 changes: 22 additions & 21 deletions cmd-attach-session.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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);
}
25 changes: 13 additions & 12 deletions cmd-bind-key.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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;
Expand All @@ -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);
}
Expand All @@ -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;
Expand All @@ -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];
Expand Down
Loading

0 comments on commit 3964309

Please sign in to comment.