aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cfg.c141
-rw-r--r--client.c20
-rw-r--r--cmd-attach-session.c59
-rw-r--r--cmd-bind-key.c51
-rw-r--r--cmd-break-pane.c17
-rw-r--r--cmd-capture-pane.c177
-rw-r--r--cmd-choose-buffer.c46
-rw-r--r--cmd-choose-client.c51
-rw-r--r--cmd-choose-list.c41
-rw-r--r--cmd-choose-tree.c55
-rw-r--r--cmd-clear-history.c6
-rw-r--r--cmd-clock-mode.c6
-rw-r--r--cmd-command-prompt.c20
-rw-r--r--cmd-confirm-before.c47
-rw-r--r--cmd-copy-mode.c6
-rw-r--r--cmd-delete-buffer.c8
-rw-r--r--cmd-detach-client.c10
-rw-r--r--cmd-display-message.c32
-rw-r--r--cmd-display-panes.c6
-rw-r--r--cmd-find-window.c37
-rw-r--r--cmd-has-session.c6
-rw-r--r--cmd-if-shell.c103
-rw-r--r--cmd-join-pane.c26
-rw-r--r--cmd-kill-pane.c7
-rw-r--r--cmd-kill-server.c5
-rw-r--r--cmd-kill-session.c6
-rw-r--r--cmd-kill-window.c6
-rw-r--r--cmd-link-window.c10
-rw-r--r--cmd-list-buffers.c7
-rw-r--r--cmd-list-clients.c9
-rw-r--r--cmd-list-commands.c16
-rw-r--r--cmd-list-keys.c21
-rw-r--r--cmd-list-panes.c32
-rw-r--r--cmd-list-sessions.c6
-rw-r--r--cmd-list-windows.c22
-rw-r--r--cmd-list.c76
-rw-r--r--cmd-load-buffer.c30
-rw-r--r--cmd-lock-server.c11
-rw-r--r--cmd-move-window.c12
-rw-r--r--cmd-new-session.c160
-rw-r--r--cmd-new-window.c26
-rw-r--r--cmd-paste-buffer.c10
-rw-r--r--cmd-pipe-pane.c13
-rw-r--r--cmd-queue.c281
-rw-r--r--cmd-refresh-client.c34
-rw-r--r--cmd-rename-session.c10
-rw-r--r--cmd-rename-window.c6
-rw-r--r--cmd-resize-pane.c52
-rw-r--r--cmd-respawn-pane.c10
-rw-r--r--cmd-respawn-window.c12
-rw-r--r--cmd-rotate-window.c6
-rw-r--r--cmd-run-shell.c86
-rw-r--r--cmd-save-buffer.c134
-rw-r--r--cmd-select-layout.c15
-rw-r--r--cmd-select-pane.c16
-rw-r--r--cmd-select-window.c16
-rw-r--r--cmd-send-keys.c25
-rw-r--r--cmd-server-info.c58
-rw-r--r--cmd-set-buffer.c8
-rw-r--r--cmd-set-environment.c16
-rw-r--r--cmd-set-option.c183
-rw-r--r--cmd-show-environment.c16
-rw-r--r--cmd-show-messages.c8
-rw-r--r--cmd-show-options.c116
-rw-r--r--cmd-source-file.c85
-rw-r--r--cmd-split-window.c34
-rw-r--r--cmd-start-server.c5
-rw-r--r--cmd-string.c5
-rw-r--r--cmd-suspend-client.c6
-rw-r--r--cmd-swap-pane.c10
-rw-r--r--cmd-swap-window.c10
-rw-r--r--cmd-switch-client.c18
-rw-r--r--cmd-unbind-key.c14
-rw-r--r--cmd-unlink-window.c8
-rw-r--r--cmd-wait-for.c197
-rw-r--r--cmd.c186
-rw-r--r--control-notify.c35
-rw-r--r--control.c58
-rw-r--r--format.c104
-rw-r--r--grid-view.c2
-rw-r--r--grid.c387
-rw-r--r--input-keys.c18
-rw-r--r--input.c58
-rw-r--r--job.c35
-rw-r--r--key-bindings.c83
-rw-r--r--key-string.c11
-rw-r--r--layout-custom.c9
-rw-r--r--layout.c40
-rw-r--r--mode-key.c7
-rw-r--r--names.c25
-rw-r--r--options-table.c18
-rw-r--r--resize.c35
-rw-r--r--screen-redraw.c60
-rw-r--r--screen-write.c144
-rw-r--r--screen.c13
-rw-r--r--server-client.c205
-rw-r--r--server-fn.c23
-rw-r--r--server-window.c4
-rw-r--r--server.c45
-rw-r--r--session.c52
-rw-r--r--status.c43
-rw-r--r--tmux.1344
-rw-r--r--tmux.c10
-rw-r--r--tmux.h278
-rw-r--r--tty-keys.c778
-rw-r--r--tty.c50
-rw-r--r--window-choose.c228
-rw-r--r--window-clock.c1
-rw-r--r--window-copy.c81
-rw-r--r--window.c98
-rw-r--r--xterm-keys.c28
111 files changed, 4147 insertions, 2405 deletions
diff --git a/cfg.c b/cfg.c
index 5e3e47e9..1153de67 100644
--- a/cfg.c
+++ b/cfg.c
@@ -27,79 +27,33 @@
#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;
-/* ARGSUSED */
-void printflike2
-cfg_print(unused struct cmd_ctx *ctx, unused const char *fmt, ...)
-{
-}
-
-/* ARGSUSED */
-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 *ctxin, 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;
- struct cmd_ctx ctx;
- enum cmd_retval retval;
+ log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) {
- cfg_add_cause(causes, "%s: %s", path, strerror(errno));
- return (CMD_RETURN_ERROR);
+ xasprintf(cause, "%s: %s", path, strerror(errno));
+ return (-1);
}
- cfg_references++;
-
- n = 0;
+ n = found = 0;
line = NULL;
- retval = CMD_RETURN_NORMAL;
while ((buf = fgetln(f, &len))) {
/* Trim \n. */
if (buf[len - 1] == '\n')
len--;
- log_debug ("%s: %s", path, buf);
+ log_debug("%s: %.*s", path, (int)len, buf);
/* Current line is the continuation of the previous one. */
if (line != NULL) {
@@ -131,68 +85,52 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
buf = copy;
while (isspace((u_char)*buf))
buf++;
- if (*buf == '\0')
+ if (*buf == '\0') {
+ free(copy);
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;
-
- if (ctxin == NULL) {
- ctx.msgdata = NULL;
- ctx.curclient = NULL;
- ctx.cmdclient = NULL;
- } else {
- ctx.msgdata = ctxin->msgdata;
- ctx.curclient = ctxin->curclient;
- ctx.cmdclient = ctxin->cmdclient;
- }
-
- ctx.error = cfg_error;
- ctx.print = cfg_print;
- ctx.info = cfg_print;
-
- 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);
- cfg_references--;
+ return (found);
+}
- return (retval);
+void
+cfg_default_done(unused struct cmd_q *cmdq)
+{
+ if (--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;
}
void
-show_cfg_causes(struct session *s)
+cfg_show_causes(struct session *s)
{
struct window_pane *wp;
char *cause;
@@ -200,7 +138,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);
diff --git a/client.c b/client.c
index ae4f5066..91f47650 100644
--- a/client.c
+++ b/client.c
@@ -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);
}
@@ -269,7 +270,7 @@ client_main(int argc, char **argv, int flags)
if (msg == MSG_COMMAND) {
/* Fill in command line arguments. */
cmddata.pid = environ_pid;
- cmddata.idx = environ_idx;
+ cmddata.session_id = environ_session_id;
/* Prepare command for server. */
cmddata.argc = argc;
@@ -295,8 +296,16 @@ client_main(int argc, char **argv, int flags)
ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
- } else if (flags & IDENTIFY_TERMIOS)
+ } else if (flags & IDENTIFY_TERMIOS) {
+ if (flags & IDENTIFY_CONTROL) {
+ if (client_exitreason != CLIENT_EXIT_NONE)
+ printf("%%exit %s\n", client_exit_message());
+ else
+ printf("%%exit\n");
+ printf("\033\\");
+ }
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
+ }
setblocking(STDIN_FILENO, 1);
return (client_exitval);
}
@@ -364,7 +373,6 @@ client_update_event(void)
}
/* Callback to handle signals in the client. */
-/* ARGSUSED */
void
client_signal(int sig, unused short events, unused void *data)
{
@@ -411,7 +419,6 @@ client_signal(int sig, unused short events, unused void *data)
}
/* Callback for client imsg read events. */
-/* ARGSUSED */
void
client_callback(unused int fd, short events, void *data)
{
@@ -446,7 +453,6 @@ lost_server:
}
/* Callback for client stdin read events. */
-/* ARGSUSED */
void
client_stdin_callback(unused int fd, unused short events, unused void *data1)
{
@@ -518,6 +524,7 @@ client_dispatch_wait(void *data)
event_del(&client_stdin);
client_attached = 1;
+ client_write_server(MSG_RESIZE, NULL, 0);
break;
case MSG_STDIN:
if (datalen != 0)
@@ -575,7 +582,6 @@ client_dispatch_wait(void *data)
}
/* Dispatch imsgs in attached state (after MSG_READY). */
-/* ARGSUSED */
int
client_dispatch_attached(void)
{
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index 18a20244..07185737 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,9 +39,8 @@ 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(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag)
{
- struct args *args = self->args;
struct session *s;
struct client *c;
const char *update;
@@ -49,18 +48,18 @@ 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, tflag, 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 (args_has(self->args, 'd')) {
+ if (cmdq->client->session != NULL) {
+ if (dflag) {
/*
* Can't use server_write_session in case attaching to
* the same session as currently attached to.
@@ -69,43 +68,53 @@ 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;
+ if (rflag)
+ cmdq->client->flags |= CLIENT_READONLY;
- if (args_has(self->args, 'd'))
+ if (dflag)
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);
+}
+
+enum cmd_retval
+cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ return (cmd_attach_session(cmdq, args_get(args, 't'),
+ args_has(args, 'd'), args_has(args, 'r')));
}
diff --git a/cmd-bind-key.c b/cmd-bind-key.c
index 28e94e26..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",
@@ -46,7 +46,7 @@ enum cmd_retval
cmd_bind_key_check(struct args *args)
{
if (args_has(args, 't')) {
- if (args->argc != 2)
+ if (args->argc != 2 && args->argc != 3)
return (CMD_RETURN_ERROR);
} else {
if (args->argc < 2)
@@ -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,36 +87,50 @@ 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;
const struct mode_key_table *mtab;
struct mode_key_binding *mbind, mtmp;
enum mode_key_cmd cmd;
+ const char *arg;
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) {
+ cmdq_error(cmdq, "no argument allowed");
+ return (CMD_RETURN_ERROR);
+ }
+ arg = NULL;
+ } else {
+ if (args->argc != 3) {
+ cmdq_error(cmdq, "no argument given");
+ return (CMD_RETURN_ERROR);
+ }
+ arg = args->argv[2];
+ }
+
mtmp.key = key;
mtmp.mode = !!args_has(args, 'c');
- if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
- mbind->cmd = cmd;
- return (CMD_RETURN_NORMAL);
+ if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) == NULL) {
+ mbind = xmalloc(sizeof *mbind);
+ mbind->key = mtmp.key;
+ mbind->mode = mtmp.mode;
+ RB_INSERT(mode_key_tree, mtab->tree, mbind);
}
- mbind = xmalloc(sizeof *mbind);
- mbind->key = mtmp.key;
- mbind->mode = mtmp.mode;
mbind->cmd = cmd;
- RB_INSERT(mode_key_tree, mtab->tree, mbind);
+ mbind->arg = arg != NULL ? xstrdup(arg) : NULL;
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-break-pane.c b/cmd-break-pane.c
index 637105ab..8ed9a1a6 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,15 +54,17 @@ 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);
}
w = wl->window;
+ server_unzoom_window(w);
+
TAILQ_REMOVE(&w->panes, wp, entry);
if (wp == w->active) {
w->active = w->last;
@@ -82,7 +84,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
name = default_window_name(w);
window_set_name(w, name);
free(name);
- layout_init(w);
+ layout_init(w, wp);
base_idx = options_get_number(&s->options, "base-index");
wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */
@@ -93,19 +95,18 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
server_status_session_group(s);
if (args_has(args, 'P')) {
-
if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE;
ft = format_create();
- if ((c = cmd_find_client(ctx, NULL)) != 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 adb827bb..f59dc2d6 100644
--- a/cmd-capture-pane.c
+++ b/cmd-capture-pane.c
@@ -24,15 +24,21 @@
#include "tmux.h"
/*
- * Write the entire contents of a pane to a buffer.
+ * 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 *);
+
+char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
+char *cmd_capture_pane_pending(struct args *, struct window_pane *,
+ size_t *);
+char *cmd_capture_pane_history(struct args *, struct cmd_q *,
+ struct window_pane *, size_t *);
const struct cmd_entry cmd_capture_pane_entry = {
"capture-pane", "capturep",
- "b:E:S:t:", 0, 0,
- "[-b buffer-index] [-E end-line] [-S start-line] "
+ "ab:CeE:JpPqS:t:", 0, 0,
+ "[-aCeJpPq] [-b buffer-index] [-E end-line] [-S start-line]"
CMD_TARGET_PANE_USAGE,
0,
NULL,
@@ -40,25 +46,69 @@ const struct cmd_entry cmd_capture_pane_entry = {
cmd_capture_pane_exec
};
-enum cmd_retval
-cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
+char *
+cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
{
- struct args *args = self->args;
- struct window_pane *wp;
- char *buf, *line, *cause;
- struct screen *s;
- struct grid *gd;
- int buffer, n;
- u_int i, limit, top, bottom, tmp;
- size_t len, linelen;
+ buf = xrealloc(buf, 1, *len + linelen + 1);
+ memcpy(buf + *len, line, linelen);
+ *len += linelen;
+ return (buf);
+}
- if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
- return (CMD_RETURN_ERROR);
- s = &wp->base;
- gd = s->grid;
+char *
+cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
+ size_t *len)
+{
+ char *buf, *line, tmp[5];
+ size_t linelen;
+ u_int i;
+
+ if (wp->ictx.since_ground == NULL)
+ return (xstrdup(""));
+
+ line = EVBUFFER_DATA(wp->ictx.since_ground);
+ linelen = EVBUFFER_LENGTH(wp->ictx.since_ground);
+
+ buf = xstrdup("");
+ if (args_has(args, 'C')) {
+ for (i = 0; i < linelen; i++) {
+ if (line[i] >= ' ') {
+ tmp[0] = line[i];
+ tmp[1] = '\0';
+ } else
+ xsnprintf(tmp, sizeof tmp, "\\%03o", line[i]);
+ buf = cmd_capture_pane_append(buf, len, tmp,
+ strlen(tmp));
+ }
+ } else
+ buf = cmd_capture_pane_append(buf, len, line, linelen);
+ return (buf);
+}
- buf = NULL;
- len = 0;
+char *
+cmd_capture_pane_history(struct args *args, struct cmd_q *cmdq,
+ struct window_pane *wp, size_t *len)
+{
+ struct grid *gd;
+ const struct grid_line *gl;
+ struct grid_cell *gc = NULL;
+ int n, with_codes, escape_c0, join_lines;
+ u_int i, sx, top, bottom, tmp;
+ char *cause, *buf, *line;
+ size_t linelen;
+
+ sx = screen_size_x(&wp->base);
+ if (args_has(args, 'a')) {
+ gd = wp->saved_grid;
+ if (gd == NULL) {
+ if (!args_has(args, 'q')) {
+ cmdq_error(cmdq, "no alternate screen");
+ return (NULL);
+ }
+ return (xstrdup(""));
+ }
+ } else
+ gd = wp->base.grid;
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause);
if (cause != NULL) {
@@ -88,37 +138,80 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
top = tmp;
}
- for (i = top; i <= bottom; i++) {
- line = grid_string_cells(s->grid, 0, i, screen_size_x(s));
- linelen = strlen(line);
+ with_codes = args_has(args, 'e');
+ escape_c0 = args_has(args, 'C');
+ join_lines = args_has(args, 'J');
- buf = xrealloc(buf, 1, len + linelen + 1);
- memcpy(buf + len, line, linelen);
- len += linelen;
- buf[len++] = '\n';
+ buf = NULL;
+ for (i = top; i <= bottom; i++) {
+ line = grid_string_cells(gd, 0, i, sx, &gc, with_codes,
+ escape_c0, !join_lines);
+ linelen = strlen(line);
- free(line);
- }
+ buf = cmd_capture_pane_append(buf, len, line, linelen);
- limit = options_get_number(&global_options, "buffer-limit");
+ gl = grid_peek_line(gd, i);
+ if (!join_lines || !(gl->flags & GRID_LINE_WRAPPED))
+ buf[(*len)++] = '\n';
- if (!args_has(args, 'b')) {
- paste_add(&global_buffers, buf, len, limit);
- return (CMD_RETURN_NORMAL);
+ free(line);
}
+ return (buf);
+}
- buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
- if (cause != NULL) {
- ctx->error(ctx, "buffer %s", cause);
- free(buf);
- free(cause);
+enum cmd_retval
+cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ struct client *c;
+ struct window_pane *wp;
+ char *buf, *cause;
+ int buffer;
+ u_int limit;
+ size_t len;
+
+ if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
- }
- if (paste_replace(&global_buffers, buffer, buf, len) != 0) {
- ctx->error(ctx, "no buffer %d", buffer);
- free(buf);
+ len = 0;
+ if (args_has(args, 'P'))
+ buf = cmd_capture_pane_pending(args, wp, &len);
+ else
+ buf = cmd_capture_pane_history(args, cmdq, wp, &len);
+ if (buf == NULL)
return (CMD_RETURN_ERROR);
+
+ if (args_has(args, 'p')) {
+ c = cmdq->client;
+ if (c == NULL ||
+ (c->session != NULL && !(c->flags & CLIENT_CONTROL))) {
+ cmdq_error(cmdq, "can't write to stdout");
+ return (CMD_RETURN_ERROR);
+ }
+ evbuffer_add(c->stdout_data, buf, len);
+ if (args_has(args, 'P') && len > 0)
+ evbuffer_add(c->stdout_data, "\n", 1);
+ server_push_stdout(c);
+ } else {
+ limit = options_get_number(&global_options, "buffer-limit");
+ if (!args_has(args, 'b')) {
+ paste_add(&global_buffers, buf, len, limit);
+ return (CMD_RETURN_NORMAL);
+ }
+
+ buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
+ if (cause != NULL) {
+ cmdq_error(cmdq, "buffer %s", cause);
+ free(buf);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
+
+ if (paste_replace(&global_buffers, buffer, buf, len) != 0) {
+ cmdq_error(cmdq, "no buffer %d", buffer);
+ free(buf);
+ return (CMD_RETURN_ERROR);
+ }
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index 50505ea1..e6b79d91 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -27,10 +27,7 @@
* Enter choice mode to choose a buffer.
*/
-enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
-
-void cmd_choose_buffer_callback(struct window_choose_data *);
-void cmd_choose_buffer_free(struct window_choose_data *);
+enum cmd_retval cmd_choose_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_buffer_entry = {
"choose-buffer", NULL,
@@ -43,9 +40,10 @@ const struct cmd_entry cmd_choose_buffer_entry = {
};
enum cmd_retval
-cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
+ struct client *c;
struct window_choose_data *cdata;
struct winlink *wl;
struct paste_buffer *pb;
@@ -53,15 +51,15 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
const char *template;
u_int idx;
- if (ctx->curclient == NULL) {
- ctx->error(ctx, "must be run interactively");
+ if ((c = cmd_current_client(cmdq)) == NULL) {
+ cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_BUFFER_TEMPLATE;
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
if (paste_get_top(&global_buffers) == NULL)
@@ -77,9 +75,8 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
idx = 0;
while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) {
- cdata = window_choose_data_create(ctx);
+ cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx - 1;
- cdata->client->references++;
cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", idx - 1);
@@ -93,34 +90,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
}
free(action);
- window_choose_ready(wl->window->active,
- 0, cmd_choose_buffer_callback, cmd_choose_buffer_free);
+ window_choose_ready(wl->window->active, 0, NULL);
return (CMD_RETURN_NORMAL);
}
-
-void
-cmd_choose_buffer_callback(struct window_choose_data *cdata)
-{
- if (cdata == NULL)
- return;
- if (cdata->client->flags & CLIENT_DEAD)
- return;
-
- window_choose_ctx(cdata);
-}
-
-void
-cmd_choose_buffer_free(struct window_choose_data *data)
-{
- struct window_choose_data *cdata = data;
-
- if (cdata == NULL)
- return;
-
- cdata->client->references--;
-
- free(cdata->command);
- free(cdata->ft_template);
- free(cdata);
-}
diff --git a/cmd-choose-client.c b/cmd-choose-client.c
index 75ef8f2c..40752a70 100644
--- a/cmd-choose-client.c
+++ b/cmd-choose-client.c
@@ -27,10 +27,9 @@
* Enter choice mode to choose a client.
*/
-enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *);
void cmd_choose_client_callback(struct window_choose_data *);
-void cmd_choose_client_free(struct window_choose_data *);
const struct cmd_entry cmd_choose_client_entry = {
"choose-client", NULL,
@@ -47,22 +46,23 @@ struct cmd_choose_client_data {
};
enum cmd_retval
-cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
+ struct client *c;
+ struct client *c1;
struct window_choose_data *cdata;
struct winlink *wl;
- struct client *c;
const char *template;
char *action;
u_int i, idx, cur;
- if (ctx->curclient == NULL) {
- ctx->error(ctx, "must be run interactively");
+ if ((c = cmd_current_client(cmdq)) == NULL) {
+ cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
@@ -78,30 +78,29 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
cur = idx = 0;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
- c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session == NULL)
+ c1 = ARRAY_ITEM(&clients, i);
+ if (c1 == NULL || c1->session == NULL || c1->tty.path == NULL)
continue;
- if (c == ctx->curclient)
+ if (c1 == cmdq->client)
cur = idx;
idx++;
- cdata = window_choose_data_create(ctx);
+ cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = i;
- cdata->client->references++;
cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", i);
- format_session(cdata->ft, c->session);
- format_client(cdata->ft, c);
+ format_session(cdata->ft, c1->session);
+ format_client(cdata->ft, c1);
- cdata->command = cmd_template_replace(action, c->tty.path, 1);
+ cdata->command = cmd_template_replace(action, c1->tty.path, 1);
window_choose_add(wl->window->active, cdata);
}
free(action);
- window_choose_ready(wl->window->active,
- cur, cmd_choose_client_callback, cmd_choose_client_free);
+ window_choose_ready(wl->window->active, cur,
+ cmd_choose_client_callback);
return (CMD_RETURN_NORMAL);
}
@@ -113,7 +112,7 @@ cmd_choose_client_callback(struct window_choose_data *cdata)
if (cdata == NULL)
return;
- if (cdata->client->flags & CLIENT_DEAD)
+ if (cdata->start_client->flags & CLIENT_DEAD)
return;
if (cdata->idx > ARRAY_LENGTH(&clients) - 1)
@@ -122,19 +121,5 @@ cmd_choose_client_callback(struct window_choose_data *cdata)
if (c == NULL || c->session == NULL)
return;
- window_choose_ctx(cdata);
-}
-
-void
-cmd_choose_client_free(struct window_choose_data *cdata)
-{
- if (cdata == NULL)
- return;
-
- cdata->client->references--;
-
- free(cdata->ft_template);
- free(cdata->command);
- format_free(cdata->ft);
- free(cdata);
+ window_choose_data_run(cdata);
}
diff --git a/cmd-choose-list.c b/cmd-choose-list.c
index 4c32e694..15f87294 100644
--- a/cmd-choose-list.c
+++ b/cmd-choose-list.c
@@ -31,10 +31,7 @@
* Enter choose mode to choose a custom list.
*/
-enum cmd_retval cmd_choose_list_exec(struct cmd *, struct cmd_ctx *);
-
-void cmd_choose_list_callback(struct window_choose_data *);
-void cmd_choose_list_free(struct window_choose_data *);
+enum cmd_retval cmd_choose_list_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_list_entry = {
"choose-list", NULL,
@@ -47,23 +44,24 @@ const struct cmd_entry cmd_choose_list_entry = {
};
enum cmd_retval
-cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_choose_list_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
+ struct client *c;
struct winlink *wl;
const char *list1;
char *template, *item, *copy, *list;
u_int idx;
- if (ctx->curclient == NULL) {
- ctx->error(ctx, "must be run interactively");
+ if ((c = cmd_current_client(cmdq)) == NULL) {
+ cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
if ((list1 = args_get(args, 'l')) == NULL)
return (CMD_RETURN_ERROR);
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
@@ -80,7 +78,7 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx)
{
if (*item == '\0') /* no empty entries */
continue;
- window_choose_add_item(wl->window->active, ctx, wl, item,
+ window_choose_add_item(wl->window->active, c, wl, item,
template, idx);
idx++;
}
@@ -92,32 +90,9 @@ cmd_choose_list_exec(struct cmd *self, struct cmd_ctx *ctx)
return (CMD_RETURN_ERROR);
}
- window_choose_ready(wl->window->active, 0, cmd_choose_list_callback,
- cmd_choose_list_free);
+ window_choose_ready(wl->window->active, 0, NULL);
free(template);
return (CMD_RETURN_NORMAL);
}
-
-void
-cmd_choose_list_callback(struct window_choose_data *cdata)
-{
- if (cdata == NULL || (cdata->client->flags & CLIENT_DEAD))
- return;
-
- window_choose_ctx(cdata);
-}
-
-void
-cmd_choose_list_free(struct window_choose_data *cdata)
-{
- cdata->session->references--;
- cdata->client->references--;
-
- free(cdata->ft_template);
- free(cdata->command);
- format_free(cdata->ft);
- free(cdata);
-
-}
diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c
index cf0b772a..e2d382b3 100644
--- a/cmd-choose-tree.c
+++ b/cmd-choose-tree.c
@@ -32,15 +32,12 @@
* Enter choice mode to choose a session and/or window.
*/
-enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_ctx *);
-
-void cmd_choose_tree_callback(struct window_choose_data *);
-void cmd_choose_tree_free(struct window_choose_data *);
+enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_choose_tree_entry = {
"choose-tree", NULL,
"S:W:swub:c:t:", 0, 1,
- "[-swu] [-b session-template] [-c window template] [-S format] " \
+ "[-suw] [-b session-template] [-c window template] [-S format] " \
"[-W format] " CMD_TARGET_WINDOW_USAGE,
0,
NULL,
@@ -69,11 +66,12 @@ const struct cmd_entry cmd_choose_window_entry = {
};
enum cmd_retval
-cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl, *wm;
struct session *s, *s2;
+ struct client *c;
struct window_choose_data *wcd = NULL;
const char *ses_template, *win_template;
char *final_win_action, *cur_win_template;
@@ -86,14 +84,15 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx)
ses_template = win_template = NULL;
ses_action = win_action = NULL;
- if (ctx->curclient == NULL) {
- ctx->error(ctx, "must be run interactively");
+ if ((c = cmd_current_client(cmdq)) == NULL) {
+ cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
- s = ctx->curclient->session;
+ if ((s = c->session) == NULL)
+ return (CMD_RETURN_ERROR);
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
@@ -175,7 +174,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx)
}
wcd = window_choose_add_session(wl->window->active,
- ctx, s2, ses_template, (char *)ses_action, idx_ses);
+ c, s2, ses_template, ses_action, idx_ses);
/* If we're just choosing sessions, skip choosing windows. */
if (sflag && !wflag) {
@@ -204,8 +203,9 @@ windows_only:
cur_win = idx_ses;
}
- xasprintf(&final_win_action, "%s ; %s", win_action,
- wcd ? wcd->command : "");
+ xasprintf(&final_win_action, "%s %s %s",
+ wcd != NULL ? wcd->command : "",
+ wcd != NULL ? ";" : "", win_action);
if (win_ses != win_max)
cur_win_template = final_win_template_middle;
@@ -213,7 +213,7 @@ windows_only:
cur_win_template = final_win_template_last;
window_choose_add_window(wl->window->active,
- ctx, s2, wm, cur_win_template,
+ c, s2, wm, cur_win_template,
final_win_action,
(wflag && !sflag) ? win_ses : idx_ses);
@@ -230,35 +230,10 @@ windows_only:
free(final_win_template_middle);
free(final_win_template_last);
- window_choose_ready(wl->window->active, cur_win,
- cmd_choose_tree_callback, cmd_choose_tree_free);
+ window_choose_ready(wl->window->active, cur_win, NULL);
if (args_has(args, 'u'))
window_choose_expand_all(wl->window->active);
return (CMD_RETURN_NORMAL);
}
-
-void
-cmd_choose_tree_callback(struct window_choose_data *cdata)
-{
- if (cdata == NULL)
- return;
-
- if (cdata->client->flags & CLIENT_DEAD)
- return;
-
- window_choose_ctx(cdata);
-}
-
-void
-cmd_choose_tree_free(struct window_choose_data *cdata)
-{
- cdata->session->references--;
- cdata->client->references--;
-
- free(cdata->ft_template);
- free(cdata->command);
- format_free(cdata->ft);
- free(cdata);
-}
diff --git a/cmd-clear-history.c b/cmd-clear-history.c
index 27f73dbb..aebaa27d 100644
--- a/cmd-clear-history.c
+++ b/cmd-clear-history.c
@@ -24,7 +24,7 @@
* Clear pane history.
*/
-enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_clear_history_entry = {
"clear-history", "clearhist",
@@ -37,13 +37,13 @@ const struct cmd_entry cmd_clear_history_entry = {
};
enum cmd_retval
-cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_clear_history_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct window_pane *wp;
struct grid *gd;
- if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
+ if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
gd = wp->base.grid;
diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c
index 139e7157..872f3d53 100644
--- a/cmd-clock-mode.c
+++ b/cmd-clock-mode.c
@@ -24,7 +24,7 @@
* Enter clock mode.
*/
-enum cmd_retval cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_clock_mode_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_clock_mode_entry = {
"clock-mode", NULL,
@@ -37,12 +37,12 @@ const struct cmd_entry cmd_clock_mode_entry = {
};
enum cmd_retval
-cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_clock_mode_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct window_pane *wp;
- if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
+ if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
window_pane_set_mode(wp, &window_clock_mode);
diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c
index ea380353..3bb79ed9 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -31,7 +31,7 @@
void cmd_command_prompt_key_binding(struct cmd *, int);
int cmd_command_prompt_check(struct args *);
-enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *);
int cmd_command_prompt_callback(void *, const char *);
void cmd_command_prompt_free(void *);
@@ -85,7 +85,7 @@ cmd_command_prompt_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const char *inputs, *prompts;
@@ -94,7 +94,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
char *prompt, *ptr, *input = NULL;
size_t n;
- if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
+ if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->prompt_string != NULL)
@@ -150,7 +150,6 @@ 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_ctx ctx;
char *cause, *new_template, *prompt, *ptr;
char *input = NULL;
@@ -175,7 +174,7 @@ cmd_command_prompt_callback(void *data, const char *s)
return (1);
}
- if (cmd_string_parse(new_template, &cmdlist, &cause) != 0) {
+ 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);
@@ -184,16 +183,7 @@ cmd_command_prompt_callback(void *data, const char *s)
return (0);
}
- ctx.msgdata = NULL;
- ctx.curclient = c;
-
- ctx.error = key_bindings_error;
- ctx.print = key_bindings_print;
- ctx.info = key_bindings_info;
-
- ctx.cmdclient = NULL;
-
- cmd_list_exec(cmdlist, &ctx);
+ cmdq_run(c->cmdq, cmdlist);
cmd_list_free(cmdlist);
if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback)
diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c
index 329027cc..e670f69c 100644
--- a/cmd-confirm-before.c
+++ b/cmd-confirm-before.c
@@ -27,7 +27,7 @@
*/
void cmd_confirm_before_key_binding(struct cmd *, int);
-enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmd_q *);
int cmd_confirm_before_callback(void *, const char *);
void cmd_confirm_before_free(void *);
@@ -43,8 +43,8 @@ const struct cmd_entry cmd_confirm_before_entry = {
};
struct cmd_confirm_before_data {
- struct client *c;
char *cmd;
+ struct client *client;
};
void
@@ -66,7 +66,7 @@ cmd_confirm_before_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_confirm_before_data *cdata;
@@ -74,12 +74,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
char *cmd, *copy, *new_prompt, *ptr;
const char *prompt;
- if (ctx->curclient == NULL) {
- ctx->error(ctx, "must be run interactively");
- return (CMD_RETURN_ERROR);
- }
-
- if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
+ if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if ((prompt = args_get(args, 'p')) != NULL)
@@ -93,48 +88,43 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
cdata = xmalloc(sizeof *cdata);
cdata->cmd = xstrdup(args->argv[0]);
- cdata->c = c;
- status_prompt_set(cdata->c, new_prompt, NULL,
+
+ cdata->client = c;
+ cdata->client->references++;
+
+ status_prompt_set(c, new_prompt, NULL,
cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
PROMPT_SINGLE);
free(new_prompt);
- return (CMD_RETURN_YIELD);
+ return (CMD_RETURN_NORMAL);
}
int
cmd_confirm_before_callback(void *data, const char *s)
{
struct cmd_confirm_before_data *cdata = data;
- struct client *c = cdata->c;
+ struct client *c = cdata->client;
struct cmd_list *cmdlist;
- struct cmd_ctx ctx;
char *cause;
+ if (c->flags & CLIENT_DEAD)
+ return (0);
+
if (s == NULL || *s == '\0')
return (0);
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (0);
- if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
+ if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
- *cause = toupper((u_char) *cause);
- status_message_set(c, "%s", cause);
+ cmdq_error(c->cmdq, "%s", cause);
free(cause);
}
return (0);
}
- ctx.msgdata = NULL;
- ctx.curclient = c;
-
- ctx.error = key_bindings_error;
- ctx.print = key_bindings_print;
- ctx.info = key_bindings_info;
-
- ctx.cmdclient = NULL;
-
- cmd_list_exec(cmdlist, &ctx);
+ cmdq_run(c->cmdq, cmdlist);
cmd_list_free(cmdlist);
return (0);
@@ -144,6 +134,9 @@ void
cmd_confirm_before_free(void *data)
{
struct cmd_confirm_before_data *cdata = data;
+ struct client *c = cdata->client;
+
+ c->references--;
free(cdata->cmd);
free(cdata);
diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c
index 8a5b5fc4..f014be83 100644
--- a/cmd-copy-mode.c
+++ b/cmd-copy-mode.c
@@ -25,7 +25,7 @@
*/
void cmd_copy_mode_key_binding(struct cmd *, int);
-enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_copy_mode_entry = {
"copy-mode", NULL,
@@ -46,12 +46,12 @@ cmd_copy_mode_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct window_pane *wp;
- if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
+ if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
if (window_pane_set_mode(wp, &window_copy_mode) != 0)
diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c
index f9d2587c..bc3982ca 100644
--- a/cmd-delete-buffer.c
+++ b/cmd-delete-buffer.c
@@ -26,7 +26,7 @@
* Delete a paste buffer.
*/
-enum cmd_retval cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_delete_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_delete_buffer_entry = {
"delete-buffer", "deleteb",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_delete_buffer_entry = {
};
enum cmd_retval
-cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
char *cause;
@@ -52,13 +52,13 @@ cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
- ctx->error(ctx, "buffer %s", cause);
+ cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (paste_free_index(&global_buffers, buffer) != 0) {
- ctx->error(ctx, "no buffer %d", buffer);
+ cmdq_error(cmdq, "no buffer %d", buffer);
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-detach-client.c b/cmd-detach-client.c
index f75b37a3..6e00e079 100644
--- a/cmd-detach-client.c
+++ b/cmd-detach-client.c
@@ -24,7 +24,7 @@
* Detach a client.
*/
-enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_detach_client_entry = {
"detach-client", "detach",
@@ -37,7 +37,7 @@ const struct cmd_entry cmd_detach_client_entry = {
};
enum cmd_retval
-cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c, *c2;
@@ -51,7 +51,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
msgtype = MSG_DETACH;
if (args_has(args, 's')) {
- s = cmd_find_session(ctx, args_get(args, 's'), 0);
+ s = cmd_find_session(cmdq, args_get(args, 's'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
@@ -61,7 +61,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
server_write_client(c, msgtype, NULL, 0);
}
} else {
- c = cmd_find_client(ctx, args_get(args, 't'));
+ c = cmd_find_client(cmdq, args_get(args, 't'), 0);
if (c == NULL)
return (CMD_RETURN_ERROR);
@@ -76,5 +76,5 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
server_write_client(c, msgtype, NULL, 0);
}
- return (CMD_RETURN_NORMAL);
+ return (CMD_RETURN_STOP);
}
diff --git a/cmd-display-message.c b/cmd-display-message.c
index 244c557c..485ccf08 100644
--- a/cmd-display-message.c
+++ b/cmd-display-message.c
@@ -27,7 +27,7 @@
* Displays a message in the status line.
*/
-enum cmd_retval cmd_display_message_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_display_message_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_display_message_entry = {
"display-message", "display",
@@ -41,7 +41,7 @@ const struct cmd_entry cmd_display_message_entry = {
};
enum cmd_retval
-cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
@@ -55,24 +55,33 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
time_t t;
size_t len;
- if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
- return (CMD_RETURN_ERROR);
-
if (args_has(args, 't')) {
- wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp);
+ wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
if (wl == NULL)
return (CMD_RETURN_ERROR);
} else {
- wl = cmd_find_pane(ctx, NULL, &s, &wp);
+ wl = cmd_find_pane(cmdq, NULL, &s, &wp);
if (wl == NULL)
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'F') && args->argc != 0) {
- ctx->error(ctx, "only one of -F or argument must be given");
+ cmdq_error(cmdq, "only one of -F or argument must be given");
return (CMD_RETURN_ERROR);
}
+ if (args_has(args, 'c')) {
+ c = cmd_find_client(cmdq, args_get(args, 'c'), 0);
+ if (c == NULL)
+ return (CMD_RETURN_ERROR);
+ } else {
+ c = cmd_current_client(cmdq);
+ if (c == NULL && !args_has(self->args, 'p')) {
+ cmdq_error(cmdq, "no client available");
+ return (CMD_RETURN_ERROR);
+ }
+ }
+
template = args_get(args, 'F');
if (args->argc != 0)
template = args->argv[0];
@@ -80,7 +89,8 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create();
- format_client(ft, c);
+ if (c != NULL)
+ format_client(ft, c);
format_session(ft, s);
format_winlink(ft, s, wl);
format_window_pane(ft, wp);
@@ -91,11 +101,11 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
msg = format_expand(ft, out);
if (args_has(self->args, 'p'))
- ctx->print(ctx, "%s", msg);
+ cmdq_print(cmdq, "%s", msg);
else
status_message_set(c, "%s", msg);
-
free(msg);
format_free(ft);
+
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-display-panes.c b/cmd-display-panes.c
index 2745ac59..4a8731a4 100644
--- a/cmd-display-panes.c
+++ b/cmd-display-panes.c
@@ -24,7 +24,7 @@
* Display panes on a client.
*/
-enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_display_panes_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_display_panes_entry = {
"display-panes", "displayp",
@@ -37,12 +37,12 @@ const struct cmd_entry cmd_display_panes_entry = {
};
enum cmd_retval
-cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
- if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
+ if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_set_identify(c);
diff --git a/cmd-find-window.c b/cmd-find-window.c
index 9a0a8a42..02f19307 100644
--- a/cmd-find-window.c
+++ b/cmd-find-window.c
@@ -28,10 +28,9 @@
* Find window containing text.
*/
-enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_q *);
void cmd_find_window_callback(struct window_choose_data *);
-void cmd_find_window_free(struct window_choose_data *);
/* Flags for determining matching behavior. */
#define CMD_FIND_WINDOW_BY_TITLE 0x1
@@ -128,9 +127,10 @@ cmd_find_window_match(struct cmd_find_window_data_list *find_list,
}
enum cmd_retval
-cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
+ struct client *c;
struct window_choose_data *cdata;
struct session *s;
struct winlink *wl, *wm;
@@ -139,13 +139,13 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
const char *template;
u_int i, match_flags;
- if (ctx->curclient == NULL) {
- ctx->error(ctx, "must be run interactively");
+ if ((c = cmd_current_client(cmdq)) == NULL) {
+ cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
- s = ctx->curclient->session;
+ s = c->session;
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
if ((template = args_get(args, 'F')) == NULL)
@@ -162,7 +162,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
free(searchstr);
if (ARRAY_LENGTH(&find_list) == 0) {
- ctx->error(ctx, "no windows matching: %s", str);
+ cmdq_error(cmdq, "no windows matching: %s", str);
ARRAY_FREE(&find_list);
return (CMD_RETURN_ERROR);
}
@@ -180,9 +180,8 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
for (i = 0; i < ARRAY_LENGTH(&find_list); i++) {
wm = ARRAY_ITEM(&find_list, i).wl;
- cdata = window_choose_data_create(ctx);
+ cdata = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = wm->idx;
- cdata->client->references++;
cdata->wl = wm;
cdata->ft_template = xstrdup(template);
@@ -198,8 +197,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
window_choose_add(wl->window->active, cdata);
}
- window_choose_ready(wl->window->active,
- 0, cmd_find_window_callback, cmd_find_window_free);
+ window_choose_ready(wl->window->active, 0, cmd_find_window_callback);
out:
ARRAY_FREE(&find_list);
@@ -215,7 +213,7 @@ cmd_find_window_callback(struct window_choose_data *cdata)
if (cdata == NULL)
return;
- s = cdata->session;
+ s = cdata->start_session;
if (!session_alive(s))
return;
@@ -228,16 +226,3 @@ cmd_find_window_callback(struct window_choose_data *cdata)
recalculate_sizes();
}
}
-
-void
-cmd_find_window_free(struct window_choose_data *cdata)
-{
- if (cdata == NULL)
- return;
-
- cdata->session->references--;
-
- free(cdata->ft_template);
- format_free(cdata->ft);
- free(cdata);
-}
diff --git a/cmd-has-session.c b/cmd-has-session.c
index 9f19c4db..c4286b86 100644
--- a/cmd-has-session.c
+++ b/cmd-has-session.c
@@ -24,7 +24,7 @@
* Cause client to report an error and exit with 1 if session doesn't exist.
*/
-enum cmd_retval cmd_has_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_has_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_has_session_entry = {
"has-session", "has",
@@ -37,11 +37,11 @@ const struct cmd_entry cmd_has_session_entry = {
};
enum cmd_retval
-cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_has_session_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
- if (cmd_find_session(ctx, args_get(args, 't'), 0) == NULL)
+ if (cmd_find_session(cmdq, args_get(args, 't'), 0) == NULL)
return (CMD_RETURN_ERROR);
return (CMD_RETURN_NORMAL);
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 636cf805..dddd5d4e 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -29,15 +29,16 @@
* Executes a tmux command if a shell command returns true or false.
*/
-enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *);
void cmd_if_shell_callback(struct job *);
+void cmd_if_shell_done(struct cmd_q *);
void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = {
"if-shell", "if",
- "", 2, 3,
- "shell-command command [command]",
+ "bt:", 2, 3,
+ "[-b] " CMD_TARGET_PANE_USAGE " shell-command command [command]",
0,
NULL,
NULL,
@@ -47,15 +48,34 @@ const struct cmd_entry cmd_if_shell_entry = {
struct cmd_if_shell_data {
char *cmd_if;
char *cmd_else;
- struct cmd_ctx ctx;
+ struct cmd_q *cmdq;
+ int bflag;
+ int started;
};
enum cmd_retval
-cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_if_shell_data *cdata;
- const char *shellcmd = args->argv[0];
+ char *shellcmd;
+ struct session *s = NULL;
+ struct winlink *wl = NULL;
+ struct window_pane *wp = NULL;
+ struct format_tree *ft;
+
+ if (args_has(args, 't'))
+ wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
+
+ ft = format_create();
+ if (s != NULL)
+ format_session(ft, s);
+ if (s != NULL && wl != NULL)
+ format_winlink(ft, s, wl);
+ if (wp != NULL)
+ format_window_pane(ft, wp);
+ shellcmd = format_expand(ft, args->argv[0]);
+ format_free(ft);
cdata = xmalloc(sizeof *cdata);
cdata->cmd_if = xstrdup(args->argv[1]);
@@ -63,56 +83,83 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
cdata->cmd_else = xstrdup(args->argv[2]);
else
cdata->cmd_else = NULL;
- memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
+ cdata->bflag = args_has(args, 'b');
- if (ctx->cmdclient != NULL)
- ctx->cmdclient->references++;
- if (ctx->curclient != NULL)
- ctx->curclient->references++;
+ cdata->started = 0;
+ cdata->cmdq = cmdq;
+ cmdq->references++;
- job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata);
+ job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata);
+ free(shellcmd);
- return (CMD_RETURN_YIELD); /* don't let client exit */
+ if (cdata->bflag)
+ return (CMD_RETURN_NORMAL);
+ return (CMD_RETURN_WAIT);
}
void
cmd_if_shell_callback(struct job *job)
{
struct cmd_if_shell_data *cdata = job->data;
- struct cmd_ctx *ctx = &cdata->ctx;
+ struct cmd_q *cmdq = cdata->cmdq, *cmdq1;
struct cmd_list *cmdlist;
char *cause, *cmd;
- if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) {
+ if (cmdq->dead)
+ return;
+
+ if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
cmd = cdata->cmd_else;
- if (cmd == NULL)
- return;
- } else
+ else
cmd = cdata->cmd_if;
- if (cmd_string_parse(cmd, &cmdlist, &cause) != 0) {
+ if (cmd == NULL)
+ return;
+
+ if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
if (cause != NULL) {
- ctx->error(ctx, "%s", cause);
+ cmdq_error(cmdq, "%s", cause);
free(cause);
}
return;
}
- cmd_list_exec(cmdlist, ctx);
+ cdata->started = 1;
+
+ cmdq1 = cmdq_new(cmdq->client);
+ cmdq1->emptyfn = cmd_if_shell_done;
+ cmdq1->data = cdata;
+
+ cmdq_run(cmdq1, cmdlist);
cmd_list_free(cmdlist);
}
void
+cmd_if_shell_done(struct cmd_q *cmdq1)
+{
+ struct cmd_if_shell_data *cdata = cmdq1->data;
+ struct cmd_q *cmdq = cdata->cmdq;
+
+ if (!cmdq_free(cmdq) && !cdata->bflag)
+ cmdq_continue(cmdq);
+
+ cmdq_free(cmdq1);
+
+ free(cdata->cmd_else);
+ free(cdata->cmd_if);
+ free(cdata);
+}
+
+void
cmd_if_shell_free(void *data)
{
struct cmd_if_shell_data *cdata = data;
- struct cmd_ctx *ctx = &cdata->ctx;
+ struct cmd_q *cmdq = cdata->cmdq;
- if (ctx->cmdclient != NULL) {
- ctx->cmdclient->references--;
- ctx->cmdclient->flags |= CLIENT_EXIT;
- }
- if (ctx->curclient != NULL)
- ctx->curclient->references--;
+ if (cdata->started)
+ return;
+
+ if (!cmdq_free(cmdq) && !cdata->bflag)
+ cmdq_continue(cmdq);
free(cdata->cmd_else);
free(cdata->cmd_if);
diff --git a/cmd-join-pane.c b/cmd-join-pane.c
index a2e7a2dc..2cf587e0 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -29,9 +29,9 @@
*/
void cmd_join_pane_key_binding(struct cmd *, int);
-enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_q *);
-enum cmd_retval join_pane(struct cmd *, struct cmd_ctx *, int);
+enum cmd_retval join_pane(struct cmd *, struct cmd_q *, int);
const struct cmd_entry cmd_join_pane_entry = {
"join-pane", "joinp",
@@ -68,13 +68,13 @@ cmd_join_pane_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
- return (join_pane(self, ctx, self->entry == &cmd_join_pane_entry));
+ return (join_pane(self, cmdq, self->entry == &cmd_join_pane_entry));
}
enum cmd_retval
-join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
+join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
{
struct args *args = self->args;
struct session *dst_s;
@@ -86,23 +86,25 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
enum layout_type type;
struct layout_cell *lc;
- dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp);
+ dst_wl = cmd_find_pane(cmdq, args_get(args, 't'), &dst_s, &dst_wp);
if (dst_wl == NULL)
return (CMD_RETURN_ERROR);
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
+ server_unzoom_window(dst_w);
- src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
+ src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;
+ server_unzoom_window(src_w);
if (not_same_window && src_w == dst_w) {
- ctx->error(ctx, "can't join a pane to its own window");
+ cmdq_error(cmdq, "can't join a pane to its own window");
return (CMD_RETURN_ERROR);
}
if (!not_same_window && src_wp == dst_wp) {
- ctx->error(ctx, "source and target panes must be different");
+ cmdq_error(cmdq, "source and target panes must be different");
return (CMD_RETURN_ERROR);
}
@@ -114,14 +116,14 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
- ctx->error(ctx, "size %s", cause);
+ cmdq_error(cmdq, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause);
if (cause != NULL) {
- ctx->error(ctx, "percentage %s", cause);
+ cmdq_error(cmdq, "percentage %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
@@ -132,7 +134,7 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
}
lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'));
if (lc == NULL) {
- ctx->error(ctx, "create pane failed: pane too small");
+ cmdq_error(cmdq, "create pane failed: pane too small");
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c
index 4f7af2ea..40761350 100644
--- a/cmd-kill-pane.c
+++ b/cmd-kill-pane.c
@@ -26,7 +26,7 @@
* Kill pane.
*/
-enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_kill_pane_entry = {
"kill-pane", "killp",
@@ -39,14 +39,15 @@ const struct cmd_entry cmd_kill_pane_entry = {
};
enum cmd_retval
-cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_kill_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
struct window_pane *loopwp, *tmpwp, *wp;
- if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
+ if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
return (CMD_RETURN_ERROR);
+ server_unzoom_window(wl->window);
if (window_count_panes(wl->window) == 1) {
/* Only one pane, kill the window. */
diff --git a/cmd-kill-server.c b/cmd-kill-server.c
index 6eb39c41..a6065460 100644
--- a/cmd-kill-server.c
+++ b/cmd-kill-server.c
@@ -27,7 +27,7 @@
* Kill the server and do nothing else.
*/
-enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_kill_server_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_kill_server_entry = {
"kill-server", NULL,
@@ -39,9 +39,8 @@ const struct cmd_entry cmd_kill_server_entry = {
cmd_kill_server_exec
};
-/* ARGSUSED */
enum cmd_retval
-cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
+cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_q *cmdq)
{
kill(getpid(), SIGTERM);
diff --git a/cmd-kill-session.c b/cmd-kill-session.c
index 145f77e9..a12cc8a4 100644
--- a/cmd-kill-session.c
+++ b/cmd-kill-session.c
@@ -27,7 +27,7 @@
* Note this deliberately has no alias to make it hard to hit by accident.
*/
-enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_kill_session_entry = {
"kill-session", NULL,
@@ -40,12 +40,12 @@ const struct cmd_entry cmd_kill_session_entry = {
};
enum cmd_retval
-cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s, *s2, *s3;
- if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'a')) {
diff --git a/cmd-kill-window.c b/cmd-kill-window.c
index 88f8dd54..34b97499 100644
--- a/cmd-kill-window.c
+++ b/cmd-kill-window.c
@@ -24,7 +24,7 @@
* Destroy window.
*/
-enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_kill_window_entry = {
"kill-window", "killw",
@@ -37,13 +37,13 @@ const struct cmd_entry cmd_kill_window_entry = {
};
enum cmd_retval
-cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl, *wl2, *wl3;
struct session *s;
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'a')) {
diff --git a/cmd-link-window.c b/cmd-link-window.c
index 0e9c55ef..2be8ace0 100644
--- a/cmd-link-window.c
+++ b/cmd-link-window.c
@@ -26,7 +26,7 @@
* Link a window into another session.
*/
-enum cmd_retval cmd_link_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_link_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_link_window_entry = {
"link-window", "linkw",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_link_window_entry = {
};
enum cmd_retval
-cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_link_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *src, *dst;
@@ -47,15 +47,15 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
char *cause;
int idx, kflag, dflag;
- if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 's'), &src)) == NULL)
return (CMD_RETURN_ERROR);
- if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
+ if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &dst)) == -2)
return (CMD_RETURN_ERROR);
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
- ctx->error(ctx, "can't link window: %s", cause);
+ cmdq_error(cmdq, "can't link window: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c
index f0d17877..58af0020 100644
--- a/cmd-list-buffers.c
+++ b/cmd-list-buffers.c
@@ -27,7 +27,7 @@
* List paste buffers.
*/
-enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_list_buffers_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_buffers_entry = {
"list-buffers", "lsb",
@@ -39,9 +39,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
cmd_list_buffers_exec
};
-/* ARGSUSED */
enum cmd_retval
-cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct paste_buffer *pb;
@@ -60,7 +59,7 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx)
format_paste_buffer(ft, pb);
line = format_expand(ft, template);
- ctx->print(ctx, "%s", line);
+ cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
diff --git a/cmd-list-clients.c b/cmd-list-clients.c
index 19976cfd..59f63099 100644
--- a/cmd-list-clients.c
+++ b/cmd-list-clients.c
@@ -28,7 +28,7 @@
* List all clients.
*/
-enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_clients_entry = {
"list-clients", "lsc",
@@ -40,9 +40,8 @@ const struct cmd_entry cmd_list_clients_entry = {
cmd_list_clients_exec
};
-/* ARGSUSED */
enum cmd_retval
-cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
@@ -53,7 +52,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
char *line;
if (args_has(args, 't')) {
- s = cmd_find_session(ctx, args_get(args, 't'), 0);
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
} else
@@ -76,7 +75,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
format_client(ft, c);
line = format_expand(ft, template);
- ctx->print(ctx, "%s", line);
+ cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
diff --git a/cmd-list-commands.c b/cmd-list-commands.c
index 68e0e80d..1bf6e703 100644
--- a/cmd-list-commands.c
+++ b/cmd-list-commands.c
@@ -24,7 +24,7 @@
* List all commands with usages.
*/
-enum cmd_retval cmd_list_commands_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_list_commands_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_commands_entry = {
"list-commands", "lscm",
@@ -36,14 +36,20 @@ const struct cmd_entry cmd_list_commands_entry = {
cmd_list_commands_exec
};
-/* ARGSUSED */
enum cmd_retval
-cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_commands_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
const struct cmd_entry **entryp;
- for (entryp = cmd_table; *entryp != NULL; entryp++)
- ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage);
+ for (entryp = cmd_table; *entryp != NULL; entryp++) {
+ if ((*entryp)->alias != NULL) {
+ cmdq_print(cmdq, "%s (%s) %s", (*entryp)->name,
+ (*entryp)->alias, (*entryp)->usage);
+ } else {
+ cmdq_print(cmdq, "%s %s", (*entryp)->name,
+ (*entryp)->usage);
+ }
+ }
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-list-keys.c b/cmd-list-keys.c
index 51eeb674..78998b66 100644
--- a/cmd-list-keys.c
+++ b/cmd-list-keys.c
@@ -26,8 +26,8 @@
* List key bindings.
*/
-enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_ctx *);
-enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmd_q *);
+enum cmd_retval cmd_list_keys_table(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_keys_entry = {
"list-keys", "lsk",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_list_keys_entry = {
};
enum cmd_retval
-cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct key_binding *bd;
@@ -50,7 +50,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
int width, keywidth;
if (args_has(args, 't'))
- return (cmd_list_keys_table(self, ctx));
+ return (cmd_list_keys_table(self, cmdq));
width = 0;
@@ -91,14 +91,14 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
continue;
cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
- ctx->print(ctx, "bind-key %s", tmp);
+ cmdq_print(cmdq, "bind-key %s", tmp);
}
return (CMD_RETURN_NORMAL);
}
enum cmd_retval
-cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_keys_table(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const char *tablename;
@@ -109,7 +109,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
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);
}
@@ -138,9 +138,12 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
mode = "c";
cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
if (cmdstr != NULL) {
- ctx->print(ctx, "bind-key -%st %s%s %*s %s",
+ cmdq_print(cmdq, "bind-key -%st %s%s %*s %s%s%s%s",
mode, any_mode && *mode == '\0' ? " " : "",
- mtab->name, (int) width, key, cmdstr);
+ mtab->name, (int) width, key, cmdstr,
+ mbind->arg != NULL ? " \"" : "",
+ mbind->arg != NULL ? mbind->arg : "",
+ mbind->arg != NULL ? "\"": "");
}
}
diff --git a/cmd-list-panes.c b/cmd-list-panes.c
index 4ce25a44..0d498e28 100644
--- a/cmd-list-panes.c
+++ b/cmd-list-panes.c
@@ -27,13 +27,13 @@
* List panes on given window.
*/
-enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_q *);
-void cmd_list_panes_server(struct cmd *, struct cmd_ctx *);
+void cmd_list_panes_server(struct cmd *, struct cmd_q *);
void cmd_list_panes_session(
- struct cmd *, struct session *, struct cmd_ctx *, int);
+ struct cmd *, struct session *, struct cmd_q *, int);
void cmd_list_panes_window(struct cmd *,
- struct session *, struct winlink *, struct cmd_ctx *, int);
+ struct session *, struct winlink *, struct cmd_q *, int);
const struct cmd_entry cmd_list_panes_entry = {
"list-panes", "lsp",
@@ -46,51 +46,51 @@ const struct cmd_entry cmd_list_panes_entry = {
};
enum cmd_retval
-cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
struct winlink *wl;
if (args_has(args, 'a'))
- cmd_list_panes_server(self, ctx);
+ cmd_list_panes_server(self, cmdq);
else if (args_has(args, 's')) {
- s = cmd_find_session(ctx, args_get(args, 't'), 0);
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
- cmd_list_panes_session(self, s, ctx, 1);
+ cmd_list_panes_session(self, s, cmdq, 1);
} else {
- wl = cmd_find_window(ctx, args_get(args, 't'), &s);
+ wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
if (wl == NULL)
return (CMD_RETURN_ERROR);
- cmd_list_panes_window(self, s, wl, ctx, 0);
+ cmd_list_panes_window(self, s, wl, cmdq, 0);
}
return (CMD_RETURN_NORMAL);
}
void
-cmd_list_panes_server(struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_panes_server(struct cmd *self, struct cmd_q *cmdq)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions)
- cmd_list_panes_session(self, s, ctx, 2);
+ cmd_list_panes_session(self, s, cmdq, 2);
}
void
cmd_list_panes_session(
- struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type)
+ struct cmd *self, struct session *s, struct cmd_q *cmdq, int type)
{
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows)
- cmd_list_panes_window(self, s, wl, ctx, type);
+ cmd_list_panes_window(self, s, wl, cmdq, type);
}
void
cmd_list_panes_window(struct cmd *self,
- struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type)
+ struct session *s, struct winlink *wl, struct cmd_q *cmdq, int type)
{
struct args *args = self->args;
struct window_pane *wp;
@@ -135,7 +135,7 @@ cmd_list_panes_window(struct cmd *self,
format_window_pane(ft, wp);
line = format_expand(ft, template);
- ctx->print(ctx, "%s", line);
+ cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c
index e8db83ed..61c12f4e 100644
--- a/cmd-list-sessions.c
+++ b/cmd-list-sessions.c
@@ -28,7 +28,7 @@
* List all sessions.
*/
-enum cmd_retval cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_list_sessions_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_list_sessions_entry = {
"list-sessions", "ls",
@@ -41,7 +41,7 @@ const struct cmd_entry cmd_list_sessions_entry = {
};
enum cmd_retval
-cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_sessions_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
@@ -60,7 +60,7 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx)
format_session(ft, s);
line = format_expand(ft, template);
- ctx->print(ctx, "%s", line);
+ cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
diff --git a/cmd-list-windows.c b/cmd-list-windows.c
index b36b5ee8..5c2a2b95 100644
--- a/cmd-list-windows.c
+++ b/cmd-list-windows.c
@@ -27,11 +27,11 @@
* List windows on given session.
*/
-enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_q *);
-void cmd_list_windows_server(struct cmd *, struct cmd_ctx *);
+void cmd_list_windows_server(struct cmd *, struct cmd_q *);
void cmd_list_windows_session(
- struct cmd *, struct session *, struct cmd_ctx *, int);
+ struct cmd *, struct session *, struct cmd_q *, int);
const struct cmd_entry cmd_list_windows_entry = {
"list-windows", "lsw",
@@ -44,35 +44,35 @@ const struct cmd_entry cmd_list_windows_entry = {
};
enum cmd_retval
-cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
if (args_has(args, 'a'))
- cmd_list_windows_server(self, ctx);
+ cmd_list_windows_server(self, cmdq);
else {
- s = cmd_find_session(ctx, args_get(args, 't'), 0);
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
- cmd_list_windows_session(self, s, ctx, 0);
+ cmd_list_windows_session(self, s, cmdq, 0);
}
return (CMD_RETURN_NORMAL);
}
void
-cmd_list_windows_server(struct cmd *self, struct cmd_ctx *ctx)
+cmd_list_windows_server(struct cmd *self, struct cmd_q *cmdq)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions)
- cmd_list_windows_session(self, s, ctx, 1);
+ cmd_list_windows_session(self, s, cmdq, 1);
}
void
cmd_list_windows_session(
- struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type)
+ struct cmd *self, struct session *s, struct cmd_q *cmdq, int type)
{
struct args *args = self->args;
struct winlink *wl;
@@ -102,7 +102,7 @@ cmd_list_windows_session(
format_window_pane(ft, wl->window->active);
line = format_expand(ft, template);
- ctx->print(ctx, "%s", line);
+ cmdq_print(cmdq, "%s", line);
free(line);
format_free(ft);
diff --git a/cmd-list.c b/cmd-list.c
index 1717ec3b..08e2067c 100644
--- a/cmd-list.c
+++ b/cmd-list.c
@@ -24,7 +24,8 @@
#include "tmux.h"
struct cmd_list *
-cmd_list_parse(int argc, char **argv, char **cause)
+cmd_list_parse(int argc, char **argv, const char* file, u_int line,
+ char **cause)
{
struct cmd_list *cmdlist;
struct cmd *cmd;
@@ -34,7 +35,7 @@ cmd_list_parse(int argc, char **argv, char **cause)
copy_argv = cmd_copy_argv(argc, argv);
- cmdlist = xmalloc(sizeof *cmdlist);
+ cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
TAILQ_INIT(&cmdlist->list);
@@ -55,7 +56,7 @@ cmd_list_parse(int argc, char **argv, char **cause)
if (arglen != 1)
new_argc++;
- cmd = cmd_parse(new_argc, new_argv, cause);
+ cmd = cmd_parse(new_argc, new_argv, file, line, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
@@ -64,7 +65,8 @@ cmd_list_parse(int argc, char **argv, char **cause)
}
if (lastsplit != argc) {
- cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit, cause);
+ cmd = cmd_parse(argc - lastsplit, copy_argv + lastsplit,
+ file, line, cause);
if (cmd == NULL)
goto bad;
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
@@ -79,75 +81,21 @@ bad:
return (NULL);
}
-enum cmd_retval
-cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
-{
- struct client *c = ctx->curclient;
- struct cmd *cmd;
- enum cmd_retval retval;
- int guards, n;
-
- guards = 0;
- if (c != NULL && c->session != NULL)
- guards = c->flags & CLIENT_CONTROL;
-
- notify_disable();
-
- retval = 0;
- TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
- if (guards)
- ctx->print(ctx, "%%begin");
- n = cmd_exec(cmd, ctx);
- if (guards)
- ctx->print(ctx, "%%end");
-
- switch (n)
- {
- case CMD_RETURN_ERROR:
- return (CMD_RETURN_ERROR);
- case CMD_RETURN_ATTACH:
- /* Client is being attached (send MSG_READY). */
- retval = CMD_RETURN_ATTACH;
-
- /*
- * Mangle the context to treat any following commands
- * as if they were called from inside.
- */
- if (ctx->curclient == NULL) {
- ctx->curclient = ctx->cmdclient;
- ctx->cmdclient = NULL;
-
- ctx->error = key_bindings_error;
- ctx->print = key_bindings_print;
- ctx->info = key_bindings_info;
- }
- break;
- case CMD_RETURN_YIELD:
- if (retval == CMD_RETURN_NORMAL)
- retval = CMD_RETURN_YIELD;
- break;
- case CMD_RETURN_NORMAL:
- break;
- }
- }
-
- notify_enable();
- return (retval);
-}
-
void
cmd_list_free(struct cmd_list *cmdlist)
{
- struct cmd *cmd;
+ struct cmd *cmd, *cmd1;
if (--cmdlist->references != 0)
return;
- while (!TAILQ_EMPTY(&cmdlist->list)) {
- cmd = TAILQ_FIRST(&cmdlist->list);
+ TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
- cmd_free(cmd);
+ args_free(cmd->args);
+ free(cmd->file);
+ free(cmd);
}
+
free(cmdlist);
}
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index aaf23d99..3be14d6a 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -30,7 +30,7 @@
* Loads a paste buffer from a file.
*/
-enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_q *);
void cmd_load_buffer_callback(struct client *, int, void *);
const struct cmd_entry cmd_load_buffer_entry = {
@@ -44,10 +44,10 @@ const struct cmd_entry cmd_load_buffer_entry = {
};
enum cmd_retval
-cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
- struct client *c = ctx->cmdclient;
+ struct client *c = cmdq->client;
struct session *s;
FILE *f;
const char *path, *newpath, *wd;
@@ -61,7 +61,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
- ctx->error(ctx, "buffer %s", cause);
+ cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
@@ -75,16 +75,16 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
error = server_set_stdin_callback (c, cmd_load_buffer_callback,
buffer_ptr, &cause);
if (error != 0) {
- ctx->error(ctx, "%s: %s", path, cause);
+ cmdq_error(cmdq, "%s: %s", path, cause);
free(cause);
return (CMD_RETURN_ERROR);
}
- return (CMD_RETURN_YIELD);
+ return (CMD_RETURN_WAIT);
}
if (c != NULL)
wd = c->cwd;
- else if ((s = cmd_current_session(ctx, 0)) != NULL) {
+ else if ((s = cmd_current_session(cmdq, 0)) != NULL) {
wd = options_get_string(&s->options, "default-path");
if (*wd == '\0')
wd = s->cwd;
@@ -96,7 +96,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
path = newpath;
}
if ((f = fopen(path, "rb")) == NULL) {
- ctx->error(ctx, "%s: %s", path, strerror(errno));
+ cmdq_error(cmdq, "%s: %s", path, strerror(errno));
return (CMD_RETURN_ERROR);
}
@@ -105,14 +105,14 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
while ((ch = getc(f)) != EOF) {
/* Do not let the server die due to memory exhaustion. */
if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
- ctx->error(ctx, "realloc error: %s", strerror(errno));
+ cmdq_error(cmdq, "realloc error: %s", strerror(errno));
goto error;
}
pdata = new_pdata;
pdata[psize++] = ch;
}
if (ferror(f)) {
- ctx->error(ctx, "%s: read error", path);
+ cmdq_error(cmdq, "%s: read error", path);
goto error;
}
if (pdata != NULL)
@@ -126,7 +126,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
return (CMD_RETURN_NORMAL);
}
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
- ctx->error(ctx, "no buffer %d", buffer);
+ cmdq_error(cmdq, "no buffer %d", buffer);
free(pdata);
return (CMD_RETURN_ERROR);
}
@@ -153,12 +153,13 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
c->stdin_callback = NULL;
c->references--;
- c->flags |= CLIENT_EXIT;
+ if (c->flags & CLIENT_DEAD)
+ return;
psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
free(data);
- return;
+ goto out;
}
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0';
@@ -174,4 +175,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
}
free(data);
+
+out:
+ cmdq_continue(c->cmdq);
}
diff --git a/cmd-lock-server.c b/cmd-lock-server.c
index 9d650275..0b6aafe8 100644
--- a/cmd-lock-server.c
+++ b/cmd-lock-server.c
@@ -28,7 +28,7 @@
* Lock commands.
*/
-enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_lock_server_entry = {
"lock-server", "lock",
@@ -60,9 +60,8 @@ const struct cmd_entry cmd_lock_client_entry = {
cmd_lock_server_exec
};
-/* ARGSUSED */
enum cmd_retval
-cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx)
+cmd_lock_server_exec(struct cmd *self, unused struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
@@ -71,11 +70,13 @@ cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx)
if (self->entry == &cmd_lock_server_entry)
server_lock();
else if (self->entry == &cmd_lock_session_entry) {
- if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+ if (s == NULL)
return (CMD_RETURN_ERROR);
server_lock_session(s);
} else {
- if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
+ c = cmd_find_client(cmdq, args_get(args, 't'), 0);
+ if (c == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
diff --git a/cmd-move-window.c b/cmd-move-window.c
index 8bd9ffee..1a147c7e 100644
--- a/cmd-move-window.c
+++ b/cmd-move-window.c
@@ -26,7 +26,7 @@
* Move a window.
*/
-enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_move_window_entry = {
"move-window", "movew",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_move_window_entry = {
};
enum cmd_retval
-cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *src, *dst, *s;
@@ -48,7 +48,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
int idx, kflag, dflag;
if (args_has(args, 'r')) {
- if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
session_renumber_windows(s);
@@ -57,15 +57,15 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
return (CMD_RETURN_NORMAL);
}
- if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 's'), &src)) == NULL)
return (CMD_RETURN_ERROR);
- if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
+ if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &dst)) == -2)
return (CMD_RETURN_ERROR);
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
- ctx->error(ctx, "can't move window: %s", cause);
+ cmdq_error(cmdq, "can't move window: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-new-session.c b/cmd-new-session.c
index bb4cdcac..4eebe632 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -31,13 +31,13 @@
*/
enum cmd_retval cmd_new_session_check(struct args *);
-enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_session_entry = {
"new-session", "new",
- "dn:s:t:x:y:", 0, 1,
- "[-d] [-n window-name] [-s session-name] " CMD_TARGET_SESSION_USAGE
- " [-x width] [-y height] [command]",
+ "AdDF:n:Ps:t:x:y:", 0, 1,
+ "[-AdDP] [-F format] [-n window-name] [-s session-name] "
+ CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]",
CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON,
NULL,
cmd_new_session_check,
@@ -53,62 +53,57 @@ cmd_new_session_check(struct args *args)
}
enum cmd_retval
-cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
- struct session *s, *old_s, *groupwith;
+ struct client *c = cmdq->client;
+ struct session *s, *groupwith;
struct window *w;
struct environ env;
struct termios tio, *tiop;
struct passwd *pw;
const char *newname, *target, *update, *cwd, *errstr;
- char *cmd, *cause;
+ const char *template;
+ char *cmd, *cause, *cp;
int detached, idx;
u_int sx, sy;
+ int already_attached;
+ struct format_tree *ft;
newname = args_get(args, 's');
if (newname != NULL) {
if (!session_check_name(newname)) {
- ctx->error(ctx, "bad session name: %s", newname);
+ cmdq_error(cmdq, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
}
if (session_find(newname) != NULL) {
- ctx->error(ctx, "duplicate session: %s", newname);
+ if (args_has(args, 'A')) {
+ return (cmd_attach_session(cmdq, newname,
+ args_has(args, 'D'), 0));
+ }
+ cmdq_error(cmdq, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
}
}
target = args_get(args, 't');
if (target != NULL) {
- groupwith = cmd_find_session(ctx, target, 0);
+ groupwith = cmd_find_session(cmdq, target, 0);
if (groupwith == NULL)
return (CMD_RETURN_ERROR);
} else
groupwith = NULL;
- /*
- * There are three cases:
- *
- * 1. If cmdclient is non-NULL, new-session has been called from the
- * command-line - cmdclient is to become a new attached, interactive
- * client. Unless -d is given, the terminal must be opened and then
- * the client sent MSG_READY.
- *
- * 2. If cmdclient is NULL, new-session has been called from an
- * existing client (such as a key binding).
- *
- * 3. Both are NULL, the command was in the configuration file. Treat
- * this as if -d was given even if it was not.
- *
- * In all cases, a new additional session needs to be created and
- * (unless -d) set as the current session for the client.
- */
-
/* Set -d if no client. */
detached = args_has(args, 'd');
- if (ctx->cmdclient == NULL && ctx->curclient == NULL)
+ if (c == NULL)
detached = 1;
+ /* Is this client already attached? */
+ already_attached = 0;
+ if (c != NULL && c->session != NULL)
+ already_attached = 1;
+
/*
* Save the termios settings, part of which is used for new windows in
* this session.
@@ -118,25 +113,25 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
* before opening the terminal as that calls tcsetattr() to prepare for
* tmux taking over.
*/
- if (ctx->cmdclient != NULL && ctx->cmdclient->tty.fd != -1) {
- if (tcgetattr(ctx->cmdclient->tty.fd, &tio) != 0)
+ if (!detached && !already_attached && c->tty.fd != -1) {
+ if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed");
tiop = &tio;
} else
tiop = NULL;
/* Open the terminal if necessary. */
- if (!detached && ctx->cmdclient != NULL) {
- if (server_client_open(ctx->cmdclient, NULL, &cause) != 0) {
- ctx->error(ctx, "open terminal failed: %s", cause);
+ if (!detached && !already_attached) {
+ if (server_client_open(c, NULL, &cause) != 0) {
+ cmdq_error(cmdq, "open terminal failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
/* Get the new session working directory. */
- if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
- cwd = ctx->cmdclient->cwd;
+ if (c != NULL && c->cwd != NULL)
+ cwd = c->cwd;
else {
pw = getpwuid(getuid());
if (pw->pw_dir != NULL && *pw->pw_dir != '\0')
@@ -146,32 +141,25 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
}
/* Find new session size. */
- if (ctx->cmdclient != NULL) {
- sx = ctx->cmdclient->tty.sx;
- sy = ctx->cmdclient->tty.sy;
- } else if (ctx->curclient != NULL) {
- sx = ctx->curclient->tty.sx;
- sy = ctx->curclient->tty.sy;
+ if (c != NULL) {
+ sx = c->tty.sx;
+ sy = c->tty.sy;
} else {
sx = 80;
sy = 24;
}
- if (detached) {
- if (args_has(args, 'x')) {
- sx = strtonum(
- args_get(args, 'x'), 1, USHRT_MAX, &errstr);
- if (errstr != NULL) {
- ctx->error(ctx, "width %s", errstr);
- return (CMD_RETURN_ERROR);
- }
+ if (detached && args_has(args, 'x')) {
+ sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
+ if (errstr != NULL) {
+ cmdq_error(cmdq, "width %s", errstr);
+ return (CMD_RETURN_ERROR);
}
- if (args_has(args, 'y')) {
- sy = strtonum(
- args_get(args, 'y'), 1, USHRT_MAX, &errstr);
- if (errstr != NULL) {
- ctx->error(ctx, "height %s", errstr);
- return (CMD_RETURN_ERROR);
- }
+ }
+ if (detached && args_has(args, 'y')) {
+ sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
+ if (errstr != NULL) {
+ cmdq_error(cmdq, "height %s", errstr);
+ return (CMD_RETURN_ERROR);
}
}
if (sy > 0 && options_get_number(&global_s_options, "status"))
@@ -192,14 +180,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
/* Construct the environment. */
environ_init(&env);
update = options_get_string(&global_s_options, "update-environment");
- if (ctx->cmdclient != NULL)
- environ_update(update, &ctx->cmdclient->environ, &env);
+ if (c != NULL)
+ environ_update(update, &c->environ, &env);
/* Create the new session. */
idx = -1 - options_get_number(&global_s_options, "base-index");
s = session_create(newname, cmd, cwd, &env, tiop, idx, sx, sy, &cause);
if (s == NULL) {
- ctx->error(ctx, "create session failed: %s", cause);
+ cmdq_error(cmdq, "create session failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
@@ -208,9 +196,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
/* Set the initial window name if one given. */
if (cmd != NULL && args_has(args, 'n')) {
w = s->curw->window;
-
window_set_name(w, args_get(args, 'n'));
-
options_set_number(&w->options, "automatic-rename", 0);
}
@@ -229,25 +215,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
* taking this session and needs to get MSG_READY and stay around.
*/
if (!detached) {
- if (ctx->cmdclient != NULL) {
- server_write_ready(ctx->cmdclient);
-
- old_s = ctx->cmdclient->session;
- if (old_s != NULL)
- ctx->cmdclient->last_session = old_s;
- ctx->cmdclient->session = s;
- notify_attached_session_changed(ctx->cmdclient);
- session_update_activity(s);
- server_redraw_client(ctx->cmdclient);
- } else {
- old_s = ctx->curclient->session;
- if (old_s != NULL)
- ctx->curclient->last_session = old_s;
- ctx->curclient->session = s;
- notify_attached_session_changed(ctx->curclient);
- session_update_activity(s);
- server_redraw_client(ctx->curclient);
- }
+ if (!already_attached)
+ server_write_ready(c);
+ else if (c->session != NULL)
+ c->last_session = c->session;
+ c->session = s;
+ notify_attached_session_changed(c);
+ session_update_activity(s);
+ server_redraw_client(c);
}
recalculate_sizes();
server_update_socket();
@@ -257,7 +232,26 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
* session's current window into more mode and display them now.
*/
if (cfg_finished)
- show_cfg_causes(s);
+ cfg_show_causes(s);
- return (detached ? CMD_RETURN_NORMAL : CMD_RETURN_ATTACH);
+ /* Print if requested. */
+ if (args_has(args, 'P')) {
+ if ((template = args_get(args, 'F')) == NULL)
+ template = NEW_SESSION_TEMPLATE;
+
+ ft = format_create();
+ if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
+ format_client(ft, c);
+ format_session(ft, s);
+
+ cp = format_expand(ft, template);
+ cmdq_print(cmdq, "%s", cp);
+ free(cp);
+
+ format_free(ft);
+ }
+
+ if (!detached)
+ cmdq->client_exit = 0;
+ return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-new-window.c b/cmd-new-window.c
index d8c576af..cfc0b8bd 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -26,7 +26,7 @@
* Create a new window.
*/
-enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
@@ -40,21 +40,19 @@ const struct cmd_entry cmd_new_window_entry = {
};
enum cmd_retval
-cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
struct winlink *wl;
struct client *c;
- const char *cmd, *cwd;
- const char *template;
- char *cause;
+ const char *cmd, *cwd, *template;
+ char *cause, *cp;
int idx, last, detached;
struct format_tree *ft;
- char *cp;
if (args_has(args, 'a')) {
- wl = cmd_find_window(ctx, args_get(args, 't'), &s);
+ wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
if (wl == NULL)
return (CMD_RETURN_ERROR);
idx = wl->idx + 1;
@@ -65,7 +63,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
break;
}
if (last == INT_MAX) {
- ctx->error(ctx, "no free window indexes");
+ cmdq_error(cmdq, "no free window indexes");
return (CMD_RETURN_ERROR);
}
@@ -76,7 +74,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
server_unlink_window(s, wl);
}
} else {
- if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2)
+ if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &s)) == -2)
return (CMD_RETURN_ERROR);
}
detached = args_has(args, 'd');
@@ -105,13 +103,13 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd = options_get_string(&s->options, "default-command");
else
cmd = args->argv[0];
- cwd = cmd_get_default_path(ctx, args_get(args, 'c'));
+ cwd = cmd_get_default_path(cmdq, args_get(args, 'c'));
if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
if (wl == NULL) {
- ctx->error(ctx, "create window failed: %s", cause);
+ cmdq_error(cmdq, "create window failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
@@ -126,14 +124,14 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
template = NEW_WINDOW_TEMPLATE;
ft = format_create();
- if ((c = cmd_find_client(ctx, NULL)) != NULL)
- format_client(ft, c);
+ 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, wl->window->active);
cp = format_expand(ft, template);
- ctx->print(ctx, "%s", cp);
+ cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c
index 05bee5c7..b07c9faf 100644
--- a/cmd-paste-buffer.c
+++ b/cmd-paste-buffer.c
@@ -27,7 +27,7 @@
* Paste paste buffer if present.
*/
-enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_paste_buffer_exec(struct cmd *, struct cmd_q *);
void cmd_paste_buffer_filter(struct window_pane *,
const char *, size_t, const char *, int);
@@ -43,7 +43,7 @@ const struct cmd_entry cmd_paste_buffer_entry = {
};
enum cmd_retval
-cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct window_pane *wp;
@@ -54,7 +54,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
int buffer;
int pflag;
- if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
+ if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
return (CMD_RETURN_ERROR);
if (!args_has(args, 'b'))
@@ -62,7 +62,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
- ctx->error(ctx, "buffer %s", cause);
+ cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
@@ -73,7 +73,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
else {
pb = paste_get_index(&global_buffers, buffer);
if (pb == NULL) {
- ctx->error(ctx, "no buffer %d", buffer);
+ cmdq_error(cmdq, "no buffer %d", buffer);
return (CMD_RETURN_ERROR);
}
}
diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c
index d2d85003..aa72c699 100644
--- a/cmd-pipe-pane.c
+++ b/cmd-pipe-pane.c
@@ -31,7 +31,7 @@
* Open pipe to redirect pane output. If already open, close first.
*/
-enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_pipe_pane_exec(struct cmd *, struct cmd_q *);
void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_pipe_pane_entry = {
};
enum cmd_retval
-cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
@@ -54,9 +54,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
char *command;
int old_fd, pipe_fd[2], null_fd;
- if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
+ if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
return (CMD_RETURN_ERROR);
- c = cmd_find_client(ctx, NULL);
+ c = cmd_find_client(cmdq, NULL, 1);
/* Destroy the old pipe. */
old_fd = wp->pipe_fd;
@@ -81,14 +81,14 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
/* Open the new pipe. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
- ctx->error(ctx, "socketpair error: %s", strerror(errno));
+ cmdq_error(cmdq, "socketpair error: %s", strerror(errno));
return (CMD_RETURN_ERROR);
}
/* Fork the child. */
switch (fork()) {
case -1:
- ctx->error(ctx, "fork error: %s", strerror(errno));
+ cmdq_error(cmdq, "fork error: %s", strerror(errno));
return (CMD_RETURN_ERROR);
case 0:
/* Child process. */
@@ -130,7 +130,6 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
}
}
-/* ARGSUSED */
void
cmd_pipe_pane_error_callback(
unused struct bufferevent *bufev, unused short what, void *data)
diff --git a/cmd-queue.c b/cmd-queue.c
new file mode 100644
index 00000000..8bcc9192
--- /dev/null
+++ b/cmd-queue.c
@@ -0,0 +1,281 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "tmux.h"
+
+/* Create new command queue. */
+struct cmd_q *
+cmdq_new(struct client *c)
+{
+ struct cmd_q *cmdq;
+
+ cmdq = xcalloc(1, sizeof *cmdq);
+ cmdq->references = 1;
+ cmdq->dead = 0;
+
+ cmdq->client = c;
+ cmdq->client_exit = 0;
+
+ TAILQ_INIT(&cmdq->queue);
+ cmdq->item = NULL;
+ cmdq->cmd = NULL;
+
+ return (cmdq);
+}
+
+/* Free command queue */
+int
+cmdq_free(struct cmd_q *cmdq)
+{
+ if (--cmdq->references != 0)
+ return (cmdq->dead);
+
+ cmdq_flush(cmdq);
+ free(cmdq);
+ return (1);
+}
+
+/* Show message from command. */
+void printflike2
+cmdq_print(struct cmd_q *cmdq, const char *fmt, ...)
+{
+ struct client *c = cmdq->client;
+ struct window *w;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if (c == NULL)
+ /* nothing */;
+ else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
+ va_start(ap, fmt);
+ evbuffer_add_vprintf(c->stdout_data, fmt, ap);
+ va_end(ap);
+
+ evbuffer_add(c->stdout_data, "\n", 1);
+ server_push_stdout(c);
+ } else {
+ w = c->session->curw->window;
+ if (w->active->mode != &window_copy_mode) {
+ window_pane_reset_mode(w->active);
+ window_pane_set_mode(w->active, &window_copy_mode);
+ window_copy_init_for_output(w->active);
+ }
+ window_copy_vadd(w->active, fmt, ap);
+ }
+
+ va_end(ap);
+}
+
+/* Show info from command. */
+void printflike2
+cmdq_info(struct cmd_q *cmdq, const char *fmt, ...)
+{
+ struct client *c = cmdq->client;
+ va_list ap;
+ char *msg;
+
+ if (options_get_number(&global_options, "quiet"))
+ return;
+
+ va_start(ap, fmt);
+
+ if (c == NULL)
+ /* nothing */;
+ else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
+ va_start(ap, fmt);
+ evbuffer_add_vprintf(c->stdout_data, fmt, ap);
+ va_end(ap);
+
+ evbuffer_add(c->stdout_data, "\n", 1);
+ server_push_stdout(c);
+ } else {
+ xvasprintf(&msg, fmt, ap);
+ *msg = toupper((u_char) *msg);
+ status_message_set(c, "%s", msg);
+ free(msg);
+ }
+
+ va_end(ap);
+
+}
+
+/* Show error from command. */
+void printflike2
+cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
+{
+ struct client *c = cmdq->client;
+ struct cmd *cmd = cmdq->cmd;
+ va_list ap;
+ char *msg, *cause;
+ size_t msglen;
+
+ va_start(ap, fmt);
+ msglen = xvasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ if (c == NULL) {
+ xasprintf(&cause, "%s:%u: %s", cmd->file, cmd->line, msg);
+ ARRAY_ADD(&cfg_causes, cause);
+ } else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
+ evbuffer_add(c->stderr_data, msg, msglen);
+ evbuffer_add(c->stderr_data, "\n", 1);
+
+ server_push_stderr(c);
+ c->retcode = 1;
+ } else {
+ *msg = toupper((u_char) *msg);
+ status_message_set(c, "%s", msg);
+ }
+
+ free(msg);
+}
+
+/* Print a guard line. */
+int
+cmdq_guard(struct cmd_q *cmdq, const char *guard)
+{
+ struct client *c = cmdq->client;
+
+ if (c == NULL || c->session == NULL)
+ return 0;
+ if (!(c->flags & CLIENT_CONTROL))
+ return 0;
+
+ evbuffer_add_printf(c->stdout_data, "%%%s %ld %u\n", guard,
+ (long) cmdq->time, cmdq->number);
+ server_push_stdout(c);
+ return 1;
+}
+
+/* Add command list to queue and begin processing if needed. */
+void
+cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
+{
+ cmdq_append(cmdq, cmdlist);
+
+ 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 cmd_q_item *item;
+
+ item = xcalloc(1, sizeof *item);
+ item->cmdlist = cmdlist;
+ TAILQ_INSERT_TAIL(&cmdq->queue, item, qentry);
+ cmdlist->references++;
+}
+
+/* Continue processing command queue. Returns 1 if finishes empty. */
+int
+cmdq_continue(struct cmd_q *cmdq)
+{
+ struct cmd_q_item *next;
+ enum cmd_retval retval;
+ int empty, guard;
+ char s[1024];
+
+ notify_disable();
+
+ 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 {
+ next = TAILQ_NEXT(cmdq->item, qentry);
+
+ while (cmdq->cmd != NULL) {
+ cmd_print(cmdq->cmd, s, sizeof s);
+ log_debug("cmdq %p: %s (client %d)", cmdq, s,
+ cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
+
+ cmdq->time = time(NULL);
+ cmdq->number++;
+
+ guard = cmdq_guard(cmdq, "begin");
+ retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
+ if (guard) {
+ if (retval == CMD_RETURN_ERROR)
+ cmdq_guard(cmdq, "error");
+ else
+ cmdq_guard(cmdq, "end");
+ }
+
+ 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);
+ }
+
+ 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:
+ if (cmdq->client_exit)
+ cmdq->client->flags |= CLIENT_EXIT;
+ if (cmdq->emptyfn != NULL)
+ cmdq->emptyfn(cmdq); /* may free cmdq */
+ empty = 1;
+
+out:
+ notify_enable();
+ return (empty);
+}
+
+/* Flush command queue. */
+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;
+}
diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c
index 52518122..7d9d539f 100644
--- a/cmd-refresh-client.c
+++ b/cmd-refresh-client.c
@@ -24,12 +24,12 @@
* Refresh client.
*/
-enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_refresh_client_entry = {
"refresh-client", "refresh",
- "St:", 0, 0,
- "[-S] " CMD_TARGET_CLIENT_USAGE,
+ "C:St:", 0, 0,
+ "[-S] [-C size]" CMD_TARGET_CLIENT_USAGE,
0,
NULL,
NULL,
@@ -37,15 +37,37 @@ const struct cmd_entry cmd_refresh_client_entry = {
};
enum cmd_retval
-cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
+ const char *size;
+ u_int w, h;
- if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
+ if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
- if (args_has(args, 'S')) {
+ if (args_has(args, 'C')) {
+ if ((size = args_get(args, 'C')) == NULL) {
+ cmdq_error(cmdq, "missing size");
+ return (CMD_RETURN_ERROR);
+ }
+ if (sscanf(size, "%u,%u", &w, &h) != 2) {
+ cmdq_error(cmdq, "bad size argument");
+ return (CMD_RETURN_ERROR);
+ }
+ if (w < PANE_MINIMUM || w > 5000 ||
+ h < PANE_MINIMUM || h > 5000) {
+ cmdq_error(cmdq, "size too small or too big");
+ return (CMD_RETURN_ERROR);
+ }
+ if (!(c->flags & CLIENT_CONTROL)) {
+ cmdq_error(cmdq, "not a control client");
+ return (CMD_RETURN_ERROR);
+ }
+ if (tty_set_size(&c->tty, w, h))
+ recalculate_sizes();
+ } else if (args_has(args, 'S')) {
status_update_jobs(c);
server_status_client(c);
} else
diff --git a/cmd-rename-session.c b/cmd-rename-session.c
index 74443bc2..3f8a9d8f 100644
--- a/cmd-rename-session.c
+++ b/cmd-rename-session.c
@@ -26,7 +26,7 @@
* Change session name.
*/
-enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_rename_session_entry = {
"rename-session", "rename",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_rename_session_entry = {
};
enum cmd_retval
-cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
@@ -47,15 +47,15 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
newname = args->argv[0];
if (!session_check_name(newname)) {
- ctx->error(ctx, "bad session name: %s", newname);
+ cmdq_error(cmdq, "bad session name: %s", newname);
return (CMD_RETURN_ERROR);
}
if (session_find(newname) != NULL) {
- ctx->error(ctx, "duplicate session: %s", newname);
+ cmdq_error(cmdq, "duplicate session: %s", newname);
return (CMD_RETURN_ERROR);
}
- if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
RB_REMOVE(sessions, &sessions, s);
diff --git a/cmd-rename-window.c b/cmd-rename-window.c
index e42dd52f..c756ba1f 100644
--- a/cmd-rename-window.c
+++ b/cmd-rename-window.c
@@ -26,7 +26,7 @@
* Rename a window.
*/
-enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_rename_window_entry = {
"rename-window", "renamew",
@@ -39,13 +39,13 @@ const struct cmd_entry cmd_rename_window_entry = {
};
enum cmd_retval
-cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_rename_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
struct winlink *wl;
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR);
window_set_name(wl->window, args->argv[0]);
diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c
index 74f6354c..ca2a6cd3 100644
--- a/cmd-resize-pane.c
+++ b/cmd-resize-pane.c
@@ -27,12 +27,12 @@
*/
void cmd_resize_pane_key_binding(struct cmd *, int);
-enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_resize_pane_entry = {
"resize-pane", "resizep",
- "DLRt:U", 0, 1,
- "[-DLRU] " CMD_TARGET_PANE_USAGE " [adjustment]",
+ "DLRt:Ux:y:Z", 0, 1,
+ "[-DLRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]",
0,
cmd_resize_pane_key_binding,
NULL,
@@ -75,6 +75,10 @@ cmd_resize_pane_key_binding(struct cmd *self, int key)
self->args = args_create(1, "5");
args_set(self->args, 'R', NULL);
break;
+ case 'z':
+ self->args = args_create(0);
+ args_set(self->args, 'Z', NULL);
+ break;
default:
self->args = args_create(0);
break;
@@ -82,25 +86,61 @@ cmd_resize_pane_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
+ struct window *w;
const char *errstr;
+ char *cause;
struct window_pane *wp;
u_int adjust;
+ int x, y;
- if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
+ if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
return (CMD_RETURN_ERROR);
+ w = wl->window;
+
+ if (args_has(args, 'Z')) {
+ if (w->flags & WINDOW_ZOOMED)
+ window_unzoom(w);
+ else
+ window_zoom(wp);
+ server_redraw_window(w);
+ server_status_window(w);
+ return (CMD_RETURN_NORMAL);
+ }
+ server_unzoom_window(w);
if (args->argc == 0)
adjust = 1;
else {
adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) {
- ctx->error(ctx, "adjustment %s", errstr);
+ cmdq_error(cmdq, "adjustment %s", errstr);
+ return (CMD_RETURN_ERROR);
+ }
+ }
+
+ if (args_has(self->args, 'x')) {
+ x = args_strtonum(self->args, 'x', PANE_MINIMUM, INT_MAX,
+ &cause);
+ if (cause != NULL) {
+ cmdq_error(cmdq, "width %s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
+ layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
+ }
+ if (args_has(self->args, 'y')) {
+ y = args_strtonum(self->args, 'y', PANE_MINIMUM, INT_MAX,
+ &cause);
+ if (cause != NULL) {
+ cmdq_error(cmdq, "height %s", cause);
+ free(cause);
return (CMD_RETURN_ERROR);
}
+ layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}
if (args_has(self->args, 'L'))
diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c
index cf3d9303..4486c91f 100644
--- a/cmd-respawn-pane.c
+++ b/cmd-respawn-pane.c
@@ -28,7 +28,7 @@
* Respawn a pane (restart the command). Kill existing if -k given.
*/
-enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_pane_entry = {
"respawn-pane", "respawnp",
@@ -41,7 +41,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
};
enum cmd_retval
-cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
@@ -53,14 +53,14 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
char *cause;
u_int idx;
- 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);
w = wl->window;
if (!args_has(self->args, 'k') && wp->fd != -1) {
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
- ctx->error(ctx, "pane still active: %s:%u.%u",
+ cmdq_error(cmdq, "pane still active: %s:%u.%u",
s->name, wl->idx, idx);
return (CMD_RETURN_ERROR);
}
@@ -79,7 +79,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
else
cmd = NULL;
if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) {
- ctx->error(ctx, "respawn pane failed: %s", cause);
+ cmdq_error(cmdq, "respawn pane failed: %s", cause);
free(cause);
environ_free(&env);
return (CMD_RETURN_ERROR);
diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c
index 46d6b0d0..35bd3471 100644
--- a/cmd-respawn-window.c
+++ b/cmd-respawn-window.c
@@ -27,7 +27,7 @@
* Respawn a window (restart the command). Kill existing if -k given.
*/
-enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_window_entry = {
"respawn-window", "respawnw",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_respawn_window_entry = {
};
enum cmd_retval
-cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
@@ -51,7 +51,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
const char *cmd;
char *cause;
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;
@@ -59,7 +59,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd == -1)
continue;
- ctx->error(ctx,
+ cmdq_error(cmdq,
"window still active: %s:%d", s->name, wl->idx);
return (CMD_RETURN_ERROR);
}
@@ -81,13 +81,13 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
else
cmd = NULL;
if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) {
- ctx->error(ctx, "respawn window failed: %s", cause);
+ cmdq_error(cmdq, "respawn window failed: %s", cause);
free(cause);
environ_free(&env);
server_destroy_pane(wp);
return (CMD_RETURN_ERROR);
}
- layout_init(w);
+ layout_init(w, wp);
window_pane_reset_mode(wp);
screen_reinit(&wp->base);
input_init(wp);
diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c
index 74f4c066..75ca7292 100644
--- a/cmd-rotate-window.c
+++ b/cmd-rotate-window.c
@@ -25,7 +25,7 @@
*/
void cmd_rotate_window_key_binding(struct cmd *, int);
-enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_rotate_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_rotate_window_entry = {
"rotate-window", "rotatew",
@@ -46,7 +46,7 @@ cmd_rotate_window_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
@@ -55,7 +55,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index 44e796df..4df21ff1 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -29,7 +29,7 @@
* Runs a command without a window.
*/
-enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_q *);
void cmd_run_shell_callback(struct job *);
void cmd_run_shell_free(void *);
@@ -37,8 +37,8 @@ void cmd_run_shell_print(struct job *, const char *);
const struct cmd_entry cmd_run_shell_entry = {
"run-shell", "run",
- "t:", 1, 1,
- CMD_TARGET_PANE_USAGE " command",
+ "bt:", 1, 1,
+ "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
0,
NULL,
NULL,
@@ -47,20 +47,21 @@ const struct cmd_entry cmd_run_shell_entry = {
struct cmd_run_shell_data {
char *cmd;
- struct cmd_ctx ctx;
- u_int wp_id;
+ struct cmd_q *cmdq;
+ int bflag;
+ int wp_id;
};
void
cmd_run_shell_print(struct job *job, const char *msg)
{
struct cmd_run_shell_data *cdata = job->data;
- struct cmd_ctx *ctx = &cdata->ctx;
- struct window_pane *wp;
+ struct window_pane *wp = NULL;
- wp = window_pane_find_by_id(cdata->wp_id);
+ if (cdata->wp_id != -1)
+ wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL) {
- ctx->print(ctx, "%s", msg);
+ cmdq_print(cdata->cmdq, "%s", msg);
return;
}
@@ -71,50 +72,63 @@ cmd_run_shell_print(struct job *job, const char *msg)
}
enum cmd_retval
-cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
- const char *shellcmd = args->argv[0];
- struct window_pane *wp;
-
- if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
- return (CMD_RETURN_ERROR);
+ char *shellcmd;
+ struct session *s = NULL;
+ struct winlink *wl = NULL;
+ struct window_pane *wp = NULL;
+ struct format_tree *ft;
+
+ if (args_has(args, 't'))
+ wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
+
+ ft = format_create();
+ if (s != NULL)
+ format_session(ft, s);
+ if (s != NULL && wl != NULL)
+ format_winlink(ft, s, wl);
+ if (wp != NULL)
+ format_window_pane(ft, wp);
+ shellcmd = format_expand(ft, args->argv[0]);
+ format_free(ft);
cdata = xmalloc(sizeof *cdata);
- cdata->cmd = xstrdup(args->argv[0]);
- cdata->wp_id = wp->id;
- memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
+ cdata->cmd = shellcmd;
+ cdata->bflag = args_has(args, 'b');
+ cdata->wp_id = wp != NULL ? (int) wp->id : -1;
- if (ctx->cmdclient != NULL)
- ctx->cmdclient->references++;
- if (ctx->curclient != NULL)
- ctx->curclient->references++;
+ cdata->cmdq = cmdq;
+ cmdq->references++;
- job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata);
+ job_run(shellcmd, s, cmd_run_shell_callback, cmd_run_shell_free, cdata);
- return (CMD_RETURN_YIELD); /* don't let client exit */
+ if (cdata->bflag)
+ return (CMD_RETURN_NORMAL);
+ return (CMD_RETURN_WAIT);
}
void
cmd_run_shell_callback(struct job *job)
{
struct cmd_run_shell_data *cdata = job->data;
- struct cmd_ctx *ctx = &cdata->ctx;
+ struct cmd_q *cmdq = cdata->cmdq;
char *cmd, *msg, *line;
size_t size;
int retcode;
u_int lines;
- if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD)
- return;
- if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD)
+ if (cmdq->dead)
return;
+ cmd = cdata->cmd;
lines = 0;
do {
if ((line = evbuffer_readline(job->event->input)) != NULL) {
- cmd_run_shell_print (job, line);
+ cmd_run_shell_print(job, line);
+ free(line);
lines++;
}
} while (line != NULL);
@@ -131,8 +145,6 @@ cmd_run_shell_callback(struct job *job)
free(line);
}
- cmd = cdata->cmd;
-
msg = NULL;
if (WIFEXITED(job->status)) {
if ((retcode = WEXITSTATUS(job->status)) != 0)
@@ -143,7 +155,7 @@ cmd_run_shell_callback(struct job *job)
}
if (msg != NULL) {
if (lines == 0)
- ctx->info(ctx, "%s", msg);
+ cmdq_info(cmdq, "%s", msg);
else
cmd_run_shell_print(job, msg);
free(msg);
@@ -154,14 +166,10 @@ void
cmd_run_shell_free(void *data)
{
struct cmd_run_shell_data *cdata = data;
- struct cmd_ctx *ctx = &cdata->ctx;
+ struct cmd_q *cmdq = cdata->cmdq;
- if (ctx->cmdclient != NULL) {
- ctx->cmdclient->references--;
- ctx->cmdclient->flags |= CLIENT_EXIT;
- }
- if (ctx->curclient != NULL)
- ctx->curclient->references--;
+ if (!cmdq_free(cmdq) && !cdata->bflag)
+ cmdq_continue(cmdq);
free(cdata->cmd);
free(cdata);
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 638c5742..f1d2808b 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -22,6 +22,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <vis.h>
#include "tmux.h"
@@ -29,7 +30,7 @@
* Saves a paste buffer to a file.
*/
-enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_save_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_save_buffer_entry = {
"save-buffer", "saveb",
@@ -41,79 +42,132 @@ const struct cmd_entry cmd_save_buffer_entry = {
cmd_save_buffer_exec
};
+const struct cmd_entry cmd_show_buffer_entry = {
+ "show-buffer", "showb",
+ "b:", 0, 0,
+ CMD_BUFFER_USAGE,
+ 0,
+ NULL,
+ NULL,
+ cmd_save_buffer_exec
+};
+
enum cmd_retval
-cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
- struct client *c = ctx->cmdclient;
+ struct client *c;
struct session *s;
struct paste_buffer *pb;
const char *path, *newpath, *wd;
- char *cause;
+ char *cause, *start, *end;
+ size_t size, used;
int buffer;
mode_t mask;
FILE *f;
+ char *msg;
+ size_t msglen;
if (!args_has(args, 'b')) {
if ((pb = paste_get_top(&global_buffers)) == NULL) {
- ctx->error(ctx, "no buffers");
+ cmdq_error(cmdq, "no buffers");
return (CMD_RETURN_ERROR);
}
} else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
- ctx->error(ctx, "buffer %s", cause);
+ cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
pb = paste_get_index(&global_buffers, buffer);
if (pb == NULL) {
- ctx->error(ctx, "no buffer %d", buffer);
+ cmdq_error(cmdq, "no buffer %d", buffer);
return (CMD_RETURN_ERROR);
}
}
- path = args->argv[0];
+ if (self->entry == &cmd_show_buffer_entry)
+ path = "-";
+ else
+ path = args->argv[0];
if (strcmp(path, "-") == 0) {
+ c = cmdq->client;
if (c == NULL) {
- ctx->error(ctx, "%s: can't write to stdout", path);
+ cmdq_error(cmdq, "can't write to stdout");
return (CMD_RETURN_ERROR);
}
- evbuffer_add(c->stdout_data, pb->data, pb->size);
- server_push_stdout(c);
- } else {
- if (c != NULL)
- wd = c->cwd;
- else if ((s = cmd_current_session(ctx, 0)) != NULL) {
- wd = options_get_string(&s->options, "default-path");
- if (*wd == '\0')
- wd = s->cwd;
- } else
- wd = NULL;
- if (wd != NULL && *wd != '\0') {
- newpath = get_full_path(wd, path);
- if (newpath != NULL)
- path = newpath;
- }
+ if (c->session == NULL || (c->flags & CLIENT_CONTROL))
+ goto do_stdout;
+ goto do_print;
+ }
- mask = umask(S_IRWXG | S_IRWXO);
- if (args_has(self->args, 'a'))
- f = fopen(path, "ab");
- else
- f = fopen(path, "wb");
- umask(mask);
- if (f == NULL) {
- ctx->error(ctx, "%s: %s", path, strerror(errno));
- return (CMD_RETURN_ERROR);
- }
- if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
- ctx->error(ctx, "%s: fwrite error", path);
- fclose(f);
- return (CMD_RETURN_ERROR);
- }
+ c = cmdq->client;
+ if (c != NULL)
+ wd = c->cwd;
+ else if ((s = cmd_current_session(cmdq, 0)) != NULL) {
+ wd = options_get_string(&s->options, "default-path");
+ if (*wd == '\0')
+ wd = s->cwd;
+ } else
+ wd = NULL;
+ if (wd != NULL && *wd != '\0') {
+ newpath = get_full_path(wd, path);
+ if (newpath != NULL)
+ path = newpath;
+ }
+
+ mask = umask(S_IRWXG | S_IRWXO);
+ if (args_has(self->args, 'a'))
+ f = fopen(path, "ab");
+ else
+ f = fopen(path, "wb");
+ umask(mask);
+ if (f == NULL) {
+ cmdq_error(cmdq, "%s: %s", path, strerror(errno));
+ return (CMD_RETURN_ERROR);
+ }
+ if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
+ cmdq_error(cmdq, "%s: fwrite error", path);
fclose(f);
+ return (CMD_RETURN_ERROR);
+ }
+ fclose(f);
+
+ return (CMD_RETURN_NORMAL);
+
+do_stdout:
+ evbuffer_add(c->stdout_data, pb->data, pb->size);
+ server_push_stdout(c);
+ return (CMD_RETURN_NORMAL);
+
+do_print:
+ if (pb->size > (INT_MAX / 4) - 1) {
+ cmdq_error(cmdq, "buffer too big");
+ return (CMD_RETURN_ERROR);
+ }
+ msg = NULL;
+ msglen = 0;
+
+ used = 0;
+ while (used != pb->size) {
+ start = pb->data + used;
+ end = memchr(start, '\n', pb->size - used);
+ if (end != NULL)
+ size = end - start;
+ else
+ size = pb->size - used;
+
+ msglen = size * 4 + 1;
+ msg = xrealloc(msg, 1, msglen);
+
+ strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
+ cmdq_print(cmdq, "%s", msg);
+
+ used += size + (end != NULL);
}
+ free(msg);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-select-layout.c b/cmd-select-layout.c
index b2423e9c..ae1be4c4 100644
--- a/cmd-select-layout.c
+++ b/cmd-select-layout.c
@@ -25,7 +25,7 @@
*/
void cmd_select_layout_key_binding(struct cmd *, int);
-enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_layout_entry = {
"select-layout", "selectl",
@@ -83,15 +83,16 @@ cmd_select_layout_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
const char *layoutname;
int next, previous, layout;
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
return (CMD_RETURN_ERROR);
+ server_unzoom_window(wl->window);
next = self->entry == &cmd_next_layout_entry;
if (args_has(self->args, 'n'))
@@ -106,7 +107,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
else
layout = layout_set_previous(wl->window);
server_redraw_window(wl->window);
- ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
+ cmdq_info(cmdq, "arranging in: %s", layout_set_name(layout));
return (CMD_RETURN_NORMAL);
}
@@ -117,18 +118,18 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
if (layout != -1) {
layout = layout_set_select(wl->window, layout);
server_redraw_window(wl->window);
- ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
+ cmdq_info(cmdq, "arranging in: %s", layout_set_name(layout));
return (CMD_RETURN_NORMAL);
}
if (args->argc != 0) {
layoutname = args->argv[0];
if (layout_parse(wl->window, layoutname) == -1) {
- ctx->error(ctx, "can't set layout: %s", layoutname);
+ cmdq_error(cmdq, "can't set layout: %s", layoutname);
return (CMD_RETURN_ERROR);
}
server_redraw_window(wl->window);
- ctx->info(ctx, "arranging in: %s", layoutname);
+ cmdq_info(cmdq, "arranging in: %s", layoutname);
}
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index 8ebae5fb..b8a12671 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -25,7 +25,7 @@
*/
void cmd_select_pane_key_binding(struct cmd *, int);
-enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_pane_entry = {
"select-pane", "selectp",
@@ -64,22 +64,23 @@ cmd_select_pane_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
struct window_pane *wp;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
- wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
+ wl = cmd_find_window(cmdq, args_get(args, 't'), NULL);
if (wl == NULL)
return (CMD_RETURN_ERROR);
if (wl->window->last == NULL) {
- ctx->error(ctx, "no last pane");
+ cmdq_error(cmdq, "no last pane");
return (CMD_RETURN_ERROR);
}
+ server_unzoom_window(wl->window);
window_set_active_pane(wl->window, wl->window->last);
server_status_window(wl->window);
server_redraw_window_borders(wl->window);
@@ -87,11 +88,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
return (CMD_RETURN_NORMAL);
}
- if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
+ if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
return (CMD_RETURN_ERROR);
+ server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) {
- ctx->error(ctx, "pane not visible");
+ cmdq_error(cmdq, "pane not visible");
return (CMD_RETURN_ERROR);
}
@@ -104,7 +106,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
else if (args_has(self->args, 'D'))
wp = window_pane_find_down(wp);
if (wp == NULL) {
- ctx->error(ctx, "pane not found");
+ cmdq_error(cmdq, "pane not found");
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-select-window.c b/cmd-select-window.c
index aecb5b5a..c15d5858 100644
--- a/cmd-select-window.c
+++ b/cmd-select-window.c
@@ -27,7 +27,7 @@
*/
void cmd_select_window_key_binding(struct cmd *, int);
-enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_window_entry = {
"select-window", "selectw",
@@ -84,7 +84,7 @@ cmd_select_window_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
@@ -102,31 +102,31 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
last = 1;
if (next || previous || last) {
- s = cmd_find_session(ctx, args_get(args, 't'), 0);
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
activity = args_has(self->args, 'a');
if (next) {
if (session_next(s, activity) != 0) {
- ctx->error(ctx, "no next window");
+ cmdq_error(cmdq, "no next window");
return (CMD_RETURN_ERROR);
}
} else if (previous) {
if (session_previous(s, activity) != 0) {
- ctx->error(ctx, "no previous window");
+ cmdq_error(cmdq, "no previous window");
return (CMD_RETURN_ERROR);
}
} else {
if (session_last(s) != 0) {
- ctx->error(ctx, "no last window");
+ cmdq_error(cmdq, "no last window");
return (CMD_RETURN_ERROR);
}
}
server_redraw_session(s);
} else {
- wl = cmd_find_window(ctx, args_get(args, 't'), &s);
+ wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
if (wl == NULL)
return (CMD_RETURN_ERROR);
@@ -136,7 +136,7 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
*/
if (args_has(self->args, 'T') && wl == s->curw) {
if (session_last(s) != 0) {
- ctx->error(ctx, "no last window");
+ cmdq_error(cmdq, "no last window");
return (-1);
}
server_redraw_session(s);
diff --git a/cmd-send-keys.c b/cmd-send-keys.c
index e19ca3b0..37d4fd2b 100644
--- a/cmd-send-keys.c
+++ b/cmd-send-keys.c
@@ -27,7 +27,7 @@
* Send keys to client.
*/
-enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_send_keys_entry = {
"send-keys", "send",
@@ -39,8 +39,18 @@ const struct cmd_entry cmd_send_keys_entry = {
cmd_send_keys_exec
};
+const struct cmd_entry cmd_send_prefix_entry = {
+ "send-prefix", NULL,
+ "2t:", 0, 0,
+ "[-2] " CMD_TARGET_PANE_USAGE,
+ 0,
+ NULL,
+ NULL,
+ cmd_send_keys_exec
+};
+
enum cmd_retval
-cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct window_pane *wp;
@@ -49,9 +59,18 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
const char *str;
int i, key;
- if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
+ if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
return (CMD_RETURN_ERROR);
+ if (self->entry == &cmd_send_prefix_entry) {
+ if (args_has(args, '2'))
+ key = options_get_number(&s->options, "prefix2");
+ else
+ key = options_get_number(&s->options, "prefix");
+ window_pane_key(wp, s, key);
+ return (CMD_RETURN_NORMAL);
+ }
+
if (args_has(args, 'R')) {
ictx = &wp->ictx;
diff --git a/cmd-server-info.c b/cmd-server-info.c
index 79310664..1e9bf29d 100644
--- a/cmd-server-info.c
+++ b/cmd-server-info.c
@@ -30,7 +30,7 @@
* Show various information about server.
*/
-enum cmd_retval cmd_server_info_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_server_info_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_server_info_entry = {
"server-info", "info",
@@ -42,9 +42,8 @@ const struct cmd_entry cmd_server_info_entry = {
cmd_server_info_exec
};
-/* ARGSUSED */
enum cmd_retval
-cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
+cmd_server_info_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
struct tty_term *term;
struct client *c;
@@ -66,48 +65,47 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
tim = ctime(&start_time);
*strchr(tim, '\n') = '\0';
- ctx->print(ctx,
- "tmux " VERSION ", pid %ld, started %s", (long) getpid(), tim);
- ctx->print(
- ctx, "socket path %s, debug level %d", socket_path, debug_level);
+ cmdq_print(cmdq, "pid %ld, started %s", (long) getpid(), tim);
+ cmdq_print(cmdq, "socket path %s, debug level %d", socket_path,
+ debug_level);
if (uname(&un) >= 0) {
- ctx->print(ctx, "system is %s %s %s %s",
+ cmdq_print(cmdq, "system is %s %s %s %s",
un.sysname, un.release, un.version, un.machine);
}
if (cfg_file != NULL)
- ctx->print(ctx, "configuration file is %s", cfg_file);
+ cmdq_print(cmdq, "configuration file is %s", cfg_file);
else
- ctx->print(ctx, "configuration file not specified");
- ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION);
- ctx->print(ctx, "%s", "");
+ cmdq_print(cmdq, "configuration file not specified");
+ cmdq_print(cmdq, "protocol version is %d", PROTOCOL_VERSION);
+ cmdq_print(cmdq, "%s", "");
- ctx->print(ctx, "Clients:");
+ cmdq_print(cmdq, "Clients:");
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
- ctx->print(ctx,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho "
+ cmdq_print(cmdq,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho "
"class=%u] [flags=0x%x/0x%x, references=%u]", i,
c->tty.path, c->ibuf.fd, c->tty.fd, c->session->name,
c->tty.sx, c->tty.sy, c->tty.termname,
c->tty.tio.c_cc[VERASE], c->tty.class,
c->flags, c->tty.flags, c->references);
}
- ctx->print(ctx, "%s", "");
+ cmdq_print(cmdq, "%s", "");
- ctx->print(ctx, "Sessions: [%zu]", sizeof (struct grid_cell));
+ cmdq_print(cmdq, "Sessions: [%zu]", sizeof (struct grid_cell));
RB_FOREACH(s, sessions, &sessions) {
t = s->creation_time.tv_sec;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
- ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] "
- "[flags=0x%x]", s->idx, s->name,
+ cmdq_print(cmdq, "%2u: %s: %u windows (created %s) [%ux%u] "
+ "[flags=0x%x]", s->id, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags);
RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window;
- ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, "
+ cmdq_print(cmdq, "%4u: %s [%ux%u] [flags=0x%x, "
"references=%u, last layout=%d]", wl->idx, w->name,
w->sx, w->sy, w->flags, w->references,
w->lastlayout);
@@ -123,7 +121,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
size += gl->cellsize *
sizeof *gl->celldata;
}
- ctx->print(ctx,
+ cmdq_print(cmdq,
"%6u: %s %lu %d %u/%u, %zu bytes", j,
wp->tty, (u_long) wp->pid, wp->fd, lines,
gd->hsize + gd->sy, size);
@@ -131,43 +129,43 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
}
}
}
- ctx->print(ctx, "%s", "");
+ cmdq_print(cmdq, "%s", "");
- ctx->print(ctx, "Terminals:");
+ cmdq_print(cmdq, "Terminals:");
LIST_FOREACH(term, &tty_terms, entry) {
- ctx->print(ctx, "%s [references=%u, flags=0x%x]:",
+ cmdq_print(cmdq, "%s [references=%u, flags=0x%x]:",
term->name, term->references, term->flags);
for (i = 0; i < NTTYCODE; i++) {
ent = &tty_term_codes[i];
code = &term->codes[ent->code];
switch (code->type) {
case TTYCODE_NONE:
- ctx->print(ctx, "%2u: %s: [missing]",
+ cmdq_print(cmdq, "%2u: %s: [missing]",
ent->code, ent->name);
break;
case TTYCODE_STRING:
strnvis(out, code->value.string, sizeof out,
VIS_OCTAL|VIS_TAB|VIS_NL);
- ctx->print(ctx, "%2u: %s: (string) %s",
+ cmdq_print(cmdq, "%2u: %s: (string) %s",
ent->code, ent->name, out);
break;
case TTYCODE_NUMBER:
- ctx->print(ctx, "%2u: %s: (number) %d",
+ cmdq_print(cmdq, "%2u: %s: (number) %d",
ent->code, ent->name, code->value.number);
break;
case TTYCODE_FLAG:
- ctx->print(ctx, "%2u: %s: (flag) %s",
+ cmdq_print(cmdq, "%2u: %s: (flag) %s",
ent->code, ent->name,
code->value.flag ? "true" : "false");
break;
}
}
}
- ctx->print(ctx, "%s", "");
+ cmdq_print(cmdq, "%s", "");
- ctx->print(ctx, "Jobs:");
+ cmdq_print(cmdq, "Jobs:");
LIST_FOREACH(job, &all_jobs, lentry) {
- ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d]",
+ cmdq_print(cmdq, "%s [fd=%d, pid=%d, status=%d]",
job->cmd, job->fd, job->pid, job->status);
}
diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index 1eeaead5..46d28ff2 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -27,7 +27,7 @@
* Add or set a paste buffer.
*/
-enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_buffer_entry = {
"set-buffer", "setb",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_set_buffer_entry = {
};
enum cmd_retval
-cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
u_int limit;
@@ -60,14 +60,14 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
if (cause != NULL) {
- ctx->error(ctx, "buffer %s", cause);
+ cmdq_error(cmdq, "buffer %s", cause);
free(cause);
free(pdata);
return (CMD_RETURN_ERROR);
}
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
- ctx->error(ctx, "no buffer %d", buffer);
+ cmdq_error(cmdq, "no buffer %d", buffer);
free(pdata);
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-set-environment.c b/cmd-set-environment.c
index c7a4fc51..0f0365aa 100644
--- a/cmd-set-environment.c
+++ b/cmd-set-environment.c
@@ -27,7 +27,7 @@
* Set an environment variable.
*/
-enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_environment_entry = {
"set-environment", "setenv",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_set_environment_entry = {
};
enum cmd_retval
-cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
@@ -49,11 +49,11 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
name = args->argv[0];
if (*name == '\0') {
- ctx->error(ctx, "empty variable name");
+ cmdq_error(cmdq, "empty variable name");
return (CMD_RETURN_ERROR);
}
if (strchr(name, '=') != NULL) {
- ctx->error(ctx, "variable name contains =");
+ cmdq_error(cmdq, "variable name contains =");
return (CMD_RETURN_ERROR);
}
@@ -65,26 +65,26 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
if (args_has(self->args, 'g'))
env = &global_environ;
else {
- if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
env = &s->environ;
}
if (args_has(self->args, 'u')) {
if (value != NULL) {
- ctx->error(ctx, "can't specify a value with -u");
+ cmdq_error(cmdq, "can't specify a value with -u");
return (CMD_RETURN_ERROR);
}
environ_unset(env, name);
} else if (args_has(self->args, 'r')) {
if (value != NULL) {
- ctx->error(ctx, "can't specify a value with -r");
+ cmdq_error(cmdq, "can't specify a value with -r");
return (CMD_RETURN_ERROR);
}
environ_set(env, name, NULL);
} else {
if (value == NULL) {
- ctx->error(ctx, "no value specified");
+ cmdq_error(cmdq, "no value specified");
return (CMD_RETURN_ERROR);
}
environ_set(env, name, value);
diff --git a/cmd-set-option.c b/cmd-set-option.c
index ca99a977..a46460a8 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -27,41 +27,44 @@
* Set an option.
*/
-enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmd_q *);
-int cmd_set_option_unset(struct cmd *, struct cmd_ctx *,
+enum cmd_retval cmd_set_option_user(struct cmd *, struct cmd_q *,
+ const char *, const char *);
+
+int cmd_set_option_unset(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
-int cmd_set_option_set(struct cmd *, struct cmd_ctx *,
+int cmd_set_option_set(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
-struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *,
+struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
-struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *,
+struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
-struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_ctx *,
+struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
-struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *,
+struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
-struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_ctx *,
+struct options_entry *cmd_set_option_attributes(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
-struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_ctx *,
+struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
-struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_ctx *,
+struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *,
const struct options_table_entry *, struct options *,
const char *);
const struct cmd_entry cmd_set_option_entry = {
"set-option", "set",
- "agqst:uw", 1, 2,
- "[-agsquw] [-t target-session|target-window] option [value]",
+ "agoqst:uw", 1, 2,
+ "[-agosquw] [-t target-session|target-window] option [value]",
0,
NULL,
NULL,
@@ -70,8 +73,8 @@ const struct cmd_entry cmd_set_option_entry = {
const struct cmd_entry cmd_set_window_option_entry = {
"set-window-option", "setw",
- "agqt:u", 1, 2,
- "[-agqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
+ "agoqt:u", 1, 2,
+ "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
0,
NULL,
NULL,
@@ -79,7 +82,7 @@ const struct cmd_entry cmd_set_window_option_entry = {
};
enum cmd_retval
-cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const struct options_table_entry *table, *oe;
@@ -94,7 +97,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
/* Get the option name and value. */
optstr = args->argv[0];
if (*optstr == '\0') {
- ctx->error(ctx, "invalid option");
+ cmdq_error(cmdq, "invalid option");
return (CMD_RETURN_ERROR);
}
if (args->argc < 2)
@@ -102,14 +105,18 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
else
valstr = args->argv[1];
+ /* Is this a user option? */
+ if (*optstr == '@')
+ return (cmd_set_option_user(self, cmdq, optstr, valstr));
+
/* Find the option entry, try each table. */
table = oe = NULL;
if (options_table_find(optstr, &table, &oe) != 0) {
- ctx->error(ctx, "ambiguous option: %s", optstr);
+ cmdq_error(cmdq, "ambiguous option: %s", optstr);
return (CMD_RETURN_ERROR);
}
if (oe == NULL) {
- ctx->error(ctx, "unknown option: %s", optstr);
+ cmdq_error(cmdq, "unknown option: %s", optstr);
return (CMD_RETURN_ERROR);
}
@@ -120,7 +127,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
if (args_has(self->args, 'g'))
oo = &global_w_options;
else {
- wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
+ wl = cmd_find_window(cmdq, args_get(args, 't'), NULL);
if (wl == NULL)
return (CMD_RETURN_ERROR);
oo = &wl->window->options;
@@ -129,22 +136,27 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
if (args_has(self->args, 'g'))
oo = &global_s_options;
else {
- s = cmd_find_session(ctx, args_get(args, 't'), 0);
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
oo = &s->options;
}
} else {
- ctx->error(ctx, "unknown table");
+ cmdq_error(cmdq, "unknown table");
return (CMD_RETURN_ERROR);
}
/* Unset or set the option. */
if (args_has(args, 'u')) {
- if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0)
+ if (cmd_set_option_unset(self, cmdq, oe, oo, valstr) != 0)
return (CMD_RETURN_ERROR);
} else {
- if (cmd_set_option_set(self, ctx, oe, oo, valstr) != 0)
+ if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) {
+ if (!args_has(args, 'q'))
+ cmdq_print(cmdq, "already set: %s", optstr);
+ return (CMD_RETURN_NORMAL);
+ }
+ if (cmd_set_option_set(self, cmdq, oe, oo, valstr) != 0)
return (CMD_RETURN_ERROR);
}
@@ -171,31 +183,95 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
return (CMD_RETURN_NORMAL);
}
+/* Set user option. */
+enum cmd_retval
+cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char* optstr,
+ const char *valstr)
+{
+ struct args *args = self->args;
+ struct session *s;
+ struct winlink *wl;
+ struct options *oo;
+
+ if (args_has(args, 's'))
+ oo = &global_options;
+ else if (args_has(self->args, 'w') ||
+ self->entry == &cmd_set_window_option_entry) {
+ if (args_has(self->args, 'g'))
+ oo = &global_w_options;
+ else {
+ wl = cmd_find_window(cmdq, args_get(args, 't'), NULL);
+ if (wl == NULL)
+ return (CMD_RETURN_ERROR);
+ oo = &wl->window->options;
+ }
+ } else {
+ if (args_has(self->args, 'g'))
+ oo = &global_s_options;
+ else {
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+ if (s == NULL)
+ return (CMD_RETURN_ERROR);
+ oo = &s->options;
+ }
+ }
+
+ if (args_has(args, 'u')) {
+ if (options_find1(oo, optstr) == NULL) {
+ cmdq_error(cmdq, "unknown option: %s", optstr);
+ return (CMD_RETURN_ERROR);
+ }
+ if (valstr != NULL) {
+ cmdq_error(cmdq, "value passed to unset option: %s",
+ optstr);
+ return (CMD_RETURN_ERROR);
+ }
+ options_remove(oo, optstr);
+ } else {
+ if (valstr == NULL) {
+ cmdq_error(cmdq, "empty value");
+ return (CMD_RETURN_ERROR);
+ }
+ if (args_has(args, 'o') && options_find1(oo, optstr) != NULL) {
+ if (!args_has(args, 'q'))
+ cmdq_print(cmdq, "already set: %s", optstr);
+ return (CMD_RETURN_NORMAL);
+ }
+ options_set_string(oo, optstr, "%s", valstr);
+ if (!args_has(args, 'q')) {
+ cmdq_info(cmdq, "set option: %s -> %s", optstr,
+ valstr);
+ }
+ }
+ return (CMD_RETURN_NORMAL);
+}
+
+
/* Unset an option. */
int
-cmd_set_option_unset(struct cmd *self, struct cmd_ctx *ctx,
+cmd_set_option_unset(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
struct args *args = self->args;
if (args_has(args, 'g')) {
- ctx->error(ctx, "can't unset global option: %s", oe->name);
+ cmdq_error(cmdq, "can't unset global option: %s", oe->name);
return (-1);
}
if (value != NULL) {
- ctx->error(ctx, "value passed to unset option: %s", oe->name);
+ cmdq_error(cmdq, "value passed to unset option: %s", oe->name);
return (-1);
}
options_remove(oo, oe->name);
if (!args_has(args, 'q'))
- ctx->info(ctx, "unset option: %s", oe->name);
+ cmdq_info(cmdq, "unset option: %s", oe->name);
return (0);
}
/* Set an option. */
int
-cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx,
+cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
struct args *args = self->args;
@@ -203,46 +279,46 @@ cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx,
const char *s;
if (oe->type != OPTIONS_TABLE_FLAG && value == NULL) {
- ctx->error(ctx, "empty value");
+ cmdq_error(cmdq, "empty value");
return (-1);
}
o = NULL;
switch (oe->type) {
case OPTIONS_TABLE_STRING:
- o = cmd_set_option_string(self, ctx, oe, oo, value);
+ o = cmd_set_option_string(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_NUMBER:
- o = cmd_set_option_number(self, ctx, oe, oo, value);
+ o = cmd_set_option_number(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_KEY:
- o = cmd_set_option_key(self, ctx, oe, oo, value);
+ o = cmd_set_option_key(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_COLOUR:
- o = cmd_set_option_colour(self, ctx, oe, oo, value);
+ o = cmd_set_option_colour(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_ATTRIBUTES:
- o = cmd_set_option_attributes(self, ctx, oe, oo, value);
+ o = cmd_set_option_attributes(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_FLAG:
- o = cmd_set_option_flag(self, ctx, oe, oo, value);
+ o = cmd_set_option_flag(self, cmdq, oe, oo, value);
break;
case OPTIONS_TABLE_CHOICE:
- o = cmd_set_option_choice(self, ctx, oe, oo, value);
+ o = cmd_set_option_choice(self, cmdq, oe, oo, value);
break;
}
if (o == NULL)
return (-1);
- s = options_table_print_entry(oe, o);
+ s = options_table_print_entry(oe, o, 0);
if (!args_has(args, 'q'))
- ctx->info(ctx, "set option: %s -> %s", oe->name, s);
+ cmdq_info(cmdq, "set option: %s -> %s", oe->name, s);
return (0);
}
/* Set a string option. */
struct options_entry *
-cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx,
+cmd_set_option_string(struct cmd *self, unused struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
struct args *args = self->args;
@@ -263,7 +339,7 @@ cmd_set_option_string(struct cmd *self, unused struct cmd_ctx *ctx,
/* Set a number option. */
struct options_entry *
-cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx,
+cmd_set_option_number(unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
long long ll;
@@ -271,7 +347,7 @@ cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx,
ll = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) {
- ctx->error(ctx, "value is %s: %s", errstr, value);
+ cmdq_error(cmdq, "value is %s: %s", errstr, value);
return (NULL);
}
@@ -280,13 +356,13 @@ cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx,
/* Set a key option. */
struct options_entry *
-cmd_set_option_key(unused struct cmd *self, struct cmd_ctx *ctx,
+cmd_set_option_key(unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
int key;
if ((key = key_string_lookup_string(value)) == KEYC_NONE) {
- ctx->error(ctx, "bad key: %s", value);
+ cmdq_error(cmdq, "bad key: %s", value);
return (NULL);
}
@@ -295,13 +371,13 @@ cmd_set_option_key(unused struct cmd *self, struct cmd_ctx *ctx,
/* Set a colour option. */
struct options_entry *
-cmd_set_option_colour(unused struct cmd *self, struct cmd_ctx *ctx,
+cmd_set_option_colour(unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
int colour;
if ((colour = colour_fromstring(value)) == -1) {
- ctx->error(ctx, "bad colour: %s", value);
+ cmdq_error(cmdq, "bad colour: %s", value);
return (NULL);
}
@@ -310,13 +386,13 @@ cmd_set_option_colour(unused struct cmd *self, struct cmd_ctx *ctx,
/* Set an attributes option. */
struct options_entry *
-cmd_set_option_attributes(unused struct cmd *self, struct cmd_ctx *ctx,
+cmd_set_option_attributes(unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
int attr;
if ((attr = attributes_fromstring(value)) == -1) {
- ctx->error(ctx, "bad attributes: %s", value);
+ cmdq_error(cmdq, "bad attributes: %s", value);
return (NULL);
}
@@ -325,7 +401,7 @@ cmd_set_option_attributes(unused struct cmd *self, struct cmd_ctx *ctx,
/* Set a flag option. */
struct options_entry *
-cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx,
+cmd_set_option_flag(unused struct cmd *self, struct cmd_q *cmdq,
const struct options_table_entry *oe, struct options *oo, const char *value)
{
int flag;
@@ -342,7 +418,7 @@ cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx,
strcasecmp(value, "no") == 0)
flag = 0;
else {
- ctx->error(ctx, "bad value: %s", value);
+ cmdq_error(cmdq, "bad value: %s", value);
return (NULL);
}
}
@@ -352,8 +428,9 @@ cmd_set_option_flag(unused struct cmd *self, struct cmd_ctx *ctx,
/* Set a choice option. */
struct options_entry *
-cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx,
- const struct options_table_entry *oe, struct options *oo, const char *value)
+cmd_set_option_choice(unused struct cmd *self, struct cmd_q *cmdq,
+ const struct options_table_entry *oe, struct options *oo,
+ const char *value)
{
const char **choicep;
int n, choice = -1;
@@ -365,13 +442,13 @@ cmd_set_option_choice(unused struct cmd *self, struct cmd_ctx *ctx,
continue;
if (choice != -1) {
- ctx->error(ctx, "ambiguous value: %s", value);
+ cmdq_error(cmdq, "ambiguous value: %s", value);
return (NULL);
}
choice = n - 1;
}
if (choice == -1) {
- ctx->error(ctx, "unknown value: %s", value);
+ cmdq_error(cmdq, "unknown value: %s", value);
return (NULL);
}
diff --git a/cmd-show-environment.c b/cmd-show-environment.c
index 679d5d4a..ffe98bcc 100644
--- a/cmd-show-environment.c
+++ b/cmd-show-environment.c
@@ -27,7 +27,7 @@
* Show environment.
*/
-enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_show_environment_entry = {
"show-environment", "showenv",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_show_environment_entry = {
};
enum cmd_retval
-cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
@@ -50,7 +50,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
if (args_has(self->args, 'g'))
env = &global_environ;
else {
- if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
env = &s->environ;
}
@@ -58,21 +58,21 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
if (args->argc != 0) {
envent = environ_find(env, args->argv[0]);
if (envent == NULL) {
- ctx->error(ctx, "unknown variable: %s", args->argv[0]);
+ cmdq_error(cmdq, "unknown variable: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
if (envent->value != NULL)
- ctx->print(ctx, "%s=%s", envent->name, envent->value);
+ cmdq_print(cmdq, "%s=%s", envent->name, envent->value);
else
- ctx->print(ctx, "-%s", envent->name);
+ cmdq_print(cmdq, "-%s", envent->name);
return (CMD_RETURN_NORMAL);
}
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL)
- ctx->print(ctx, "%s=%s", envent->name, envent->value);
+ cmdq_print(cmdq, "%s=%s", envent->name, envent->value);
else
- ctx->print(ctx, "-%s", envent->name);
+ cmdq_print(cmdq, "-%s", envent->name);
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-show-messages.c b/cmd-show-messages.c
index d8c18519..bc2424ad 100644
--- a/cmd-show-messages.c
+++ b/cmd-show-messages.c
@@ -27,7 +27,7 @@
* Show client message log.
*/
-enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_show_messages_entry = {
"show-messages", "showmsgs",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_show_messages_entry = {
};
enum cmd_retval
-cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
@@ -48,7 +48,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
char *tim;
u_int i;
- if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
+ if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
@@ -57,7 +57,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
tim = ctime(&msg->msg_time);
*strchr(tim, '\n') = '\0';
- ctx->print(ctx, "%s %s", tim, msg->msg);
+ cmdq_print(cmdq, "%s %s", tim, msg->msg);
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-show-options.c b/cmd-show-options.c
index d37b791e..e2f78e12 100644
--- a/cmd-show-options.c
+++ b/cmd-show-options.c
@@ -27,12 +27,17 @@
* Show options.
*/
-enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_q *);
+
+enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_q *,
+ struct options *, int);
+enum cmd_retval cmd_show_options_all(struct cmd *, struct cmd_q *,
+ const struct options_table_entry *, struct options *);
const struct cmd_entry cmd_show_options_entry = {
"show-options", "show",
- "gst:w", 0, 1,
- "[-gsw] [-t target-session|target-window] [option]",
+ "gqst:vw", 0, 1,
+ "[-gqsvw] [-t target-session|target-window] [option]",
0,
NULL,
NULL,
@@ -41,8 +46,8 @@ const struct cmd_entry cmd_show_options_entry = {
const struct cmd_entry cmd_show_window_options_entry = {
"show-window-options", "showw",
- "gt:", 0, 1,
- "[-g] " CMD_TARGET_WINDOW_USAGE " [option]",
+ "gvt:", 0, 1,
+ "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
0,
NULL,
NULL,
@@ -50,15 +55,14 @@ const struct cmd_entry cmd_show_window_options_entry = {
};
enum cmd_retval
-cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
- const struct options_table_entry *table, *oe;
struct session *s;
struct winlink *wl;
+ const struct options_table_entry *table;
struct options *oo;
- struct options_entry *o;
- const char *optval;
+ int quiet;
if (args_has(self->args, 's')) {
oo = &global_options;
@@ -69,7 +73,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
if (args_has(self->args, 'g'))
oo = &global_w_options;
else {
- wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
+ wl = cmd_find_window(cmdq, args_get(args, 't'), NULL);
if (wl == NULL)
return (CMD_RETURN_ERROR);
oo = &wl->window->options;
@@ -79,34 +83,90 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
if (args_has(self->args, 'g'))
oo = &global_s_options;
else {
- s = cmd_find_session(ctx, args_get(args, 't'), 0);
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
oo = &s->options;
}
}
- if (args->argc != 0) {
- table = oe = NULL;
- if (options_table_find(args->argv[0], &table, &oe) != 0) {
- ctx->error(ctx, "ambiguous option: %s", args->argv[0]);
+ quiet = args_has(self->args, 'q');
+ if (args->argc == 0)
+ return (cmd_show_options_all(self, cmdq, table, oo));
+ else
+ return (cmd_show_options_one(self, cmdq, oo, quiet));
+}
+
+enum cmd_retval
+cmd_show_options_one(struct cmd *self, struct cmd_q *cmdq,
+ struct options *oo, int quiet)
+{
+ struct args *args = self->args;
+ const struct options_table_entry *table, *oe;
+ struct options_entry *o;
+ const char *optval;
+
+ if (*args->argv[0] == '@') {
+ if ((o = options_find1(oo, args->argv[0])) == NULL) {
+ if (quiet)
+ return (CMD_RETURN_NORMAL);
+ cmdq_error(cmdq, "unknown option: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
- if (oe == NULL) {
- ctx->error(ctx, "unknown option: %s", args->argv[0]);
- return (CMD_RETURN_ERROR);
+ if (args_has(self->args, 'v'))
+ cmdq_print(cmdq, "%s", o->str);
+ else
+ cmdq_print(cmdq, "%s \"%s\"", o->name, o->str);
+ return (CMD_RETURN_NORMAL);
+ }
+
+ table = oe = NULL;
+ if (options_table_find(args->argv[0], &table, &oe) != 0) {
+ cmdq_error(cmdq, "ambiguous option: %s", args->argv[0]);
+ return (CMD_RETURN_ERROR);
+ }
+ if (oe == NULL) {
+ if (quiet)
+ return (CMD_RETURN_NORMAL);
+ cmdq_error(cmdq, "unknown option: %s", args->argv[0]);
+ return (CMD_RETURN_ERROR);
+ }
+ if ((o = options_find1(oo, oe->name)) == NULL)
+ return (CMD_RETURN_NORMAL);
+ optval = options_table_print_entry(oe, o, args_has(self->args, 'v'));
+ if (args_has(self->args, 'v'))
+ cmdq_print(cmdq, "%s", optval);
+ else
+ cmdq_print(cmdq, "%s %s", oe->name, optval);
+ return (CMD_RETURN_NORMAL);
+}
+
+enum cmd_retval
+cmd_show_options_all(struct cmd *self, struct cmd_q *cmdq,
+ const struct options_table_entry *table, struct options *oo)
+{
+ const struct options_table_entry *oe;
+ struct options_entry *o;
+ const char *optval;
+
+ RB_FOREACH(o, options_tree, &oo->tree) {
+ if (*o->name == '@') {
+ if (args_has(self->args, 'v'))
+ cmdq_print(cmdq, "%s", o->str);
+ else
+ cmdq_print(cmdq, "%s \"%s\"", o->name, o->str);
}
+ }
+
+ for (oe = table; oe->name != NULL; oe++) {
if ((o = options_find1(oo, oe->name)) == NULL)
- return (CMD_RETURN_NORMAL);
- optval = options_table_print_entry(oe, o);
- ctx->print(ctx, "%s %s", oe->name, optval);
- } else {
- for (oe = table; oe->name != NULL; oe++) {
- if ((o = options_find1(oo, oe->name)) == NULL)
- continue;
- optval = options_table_print_entry(oe, o);
- ctx->print(ctx, "%s %s", oe->name, optval);
- }
+ continue;
+ optval = options_table_print_entry(oe, o,
+ args_has(self->args, 'v'));
+ if (args_has(self->args, 'v'))
+ cmdq_print(cmdq, "%s", optval);
+ else
+ cmdq_print(cmdq, "%s %s", oe->name, optval);
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-source-file.c b/cmd-source-file.c
index 220ec89c..827d4c00 100644
--- a/cmd-source-file.c
+++ b/cmd-source-file.c
@@ -26,7 +26,10 @@
* Sources a configuration file.
*/
-enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmd_q *);
+
+void cmd_source_file_show(struct cmd_q *);
+void cmd_source_file_done(struct cmd_q *);
const struct cmd_entry cmd_source_file_entry = {
"source-file", "source",
@@ -39,35 +42,67 @@ const struct cmd_entry cmd_source_file_entry = {
};
enum cmd_retval
-cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ struct cmd_q *cmdq1;
+ char *cause;
+
+ cmdq1 = cmdq_new(NULL);
+ cmdq1->emptyfn = cmd_source_file_done;
+ cmdq1->data = cmdq;
+
+ switch (load_cfg(args->argv[0], cmdq1, &cause)) {
+ case -1:
+ if (cfg_references == 0) {
+ cmdq_free(cmdq1);
+ cmdq_error(cmdq, "%s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
+ ARRAY_ADD(&cfg_causes, cause);
+ /* FALLTHROUGH */
+ case 0:
+ if (cfg_references == 0)
+ cmd_source_file_show(cmdq);
+ cmdq_free(cmdq1);
+ return (CMD_RETURN_NORMAL);
+ }
+
+ cmdq->references++;
+ cfg_references++;
+
+ cmdq_continue(cmdq1);
+ return (CMD_RETURN_WAIT);
+}
+
+void
+cmd_source_file_show(struct cmd_q *cmdq)
{
- struct args *args = self->args;
- int retval;
- u_int i;
- char *cause;
-
- retval = load_cfg(args->argv[0], ctx, &cfg_causes);
-
- /*
- * If the context for the cmdclient came from tmux's configuration
- * file, then return the status of this command now, regardless of the
- * error condition. Any errors from parsing a configuration file at
- * startup will be handled for us by the server.
- */
- if (cfg_references > 0 ||
- (ctx->curclient == NULL && ctx->cmdclient == NULL))
- return (retval);
-
- /*
- * We were called from the command-line in which case print the errors
- * gathered here directly.
- */
+ u_int i;
+ char *cause;
+
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
- ctx->print(ctx, "%s", cause);
+ cmdq_print(cmdq, "%s", cause);
free(cause);
}
ARRAY_FREE(&cfg_causes);
+}
+
+void
+cmd_source_file_done(struct cmd_q *cmdq1)
+{
+ struct cmd_q *cmdq = cmdq1->data;
+
+ cmdq_free(cmdq1);
+
+ cfg_references--;
+
+ if (cmdq_free(cmdq))
+ return;
- return (retval);
+ if (cfg_references == 0)
+ cmd_source_file_show(cmdq);
+ cmdq_continue(cmdq);
}
diff --git a/cmd-split-window.c b/cmd-split-window.c
index cac8095e..139f7e50 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -28,7 +28,7 @@
*/
void cmd_split_window_key_binding(struct cmd *, int);
-enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_split_window_entry = {
"split-window", "splitw",
@@ -50,7 +50,7 @@ cmd_split_window_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct session *s;
@@ -58,8 +58,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct window *w;
struct window_pane *wp, *new_wp = NULL;
struct environ env;
- const char *cmd, *cwd, *shell;
- char *cause, *new_cause;
+ const char *cmd, *cwd, *shell, *prefix;
+ char *cause, *new_cause, *cmd1;
u_int hlimit;
int size, percentage;
enum layout_type type;
@@ -69,9 +69,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct format_tree *ft;
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);
w = wl->window;
+ server_unzoom_window(w);
environ_init(&env);
environ_copy(&global_environ, &env);
@@ -82,7 +83,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cmd = options_get_string(&s->options, "default-command");
else
cmd = args->argv[0];
- cwd = cmd_get_default_path(ctx, args_get(args, 'c'));
+ cwd = cmd_get_default_path(cmdq, args_get(args, 'c'));
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
@@ -121,9 +122,18 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
goto error;
}
new_wp = window_add_pane(w, hlimit);
- if (window_pane_spawn(
- new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0)
+
+ if (*cmd != '\0') {
+ prefix = options_get_string(&w->options, "command-prefix");
+ xasprintf(&cmd1, "%s%s", prefix, cmd);
+ } else
+ cmd1 = xstrdup("");
+ if (window_pane_spawn(new_wp, cmd1, shell, cwd, &env, s->tio,
+ &cause) != 0) {
+ free(cmd1);
goto error;
+ }
+ free(cmd1);
layout_assign_pane(lc, new_wp);
server_redraw_window(w);
@@ -142,14 +152,14 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
template = SPLIT_WINDOW_TEMPLATE;
ft = format_create();
- if ((c = cmd_find_client(ctx, NULL)) != NULL)
- format_client(ft, c);
+ 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, new_wp);
cp = format_expand(ft, template);
- ctx->print(ctx, "%s", cp);
+ cmdq_print(cmdq, "%s", cp);
free(cp);
format_free(ft);
@@ -161,7 +171,7 @@ error:
environ_free(&env);
if (new_wp != NULL)
window_remove_pane(w, new_wp);
- ctx->error(ctx, "create pane failed: %s", cause);
+ cmdq_error(cmdq, "create pane failed: %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-start-server.c b/cmd-start-server.c
index 7da13375..cba2403b 100644
--- a/cmd-start-server.c
+++ b/cmd-start-server.c
@@ -24,7 +24,7 @@
* Start the server and do nothing else.
*/
-enum cmd_retval cmd_start_server_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_start_server_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_start_server_entry = {
"start-server", "start",
@@ -36,9 +36,8 @@ const struct cmd_entry cmd_start_server_entry = {
cmd_start_server_exec
};
-/* ARGSUSED */
enum cmd_retval
-cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
+cmd_start_server_exec(unused struct cmd *self, unused struct cmd_q *cmdq)
{
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-string.c b/cmd-string.c
index 5bb37397..7e84eda6 100644
--- a/cmd-string.c
+++ b/cmd-string.c
@@ -59,7 +59,8 @@ cmd_string_ungetc(size_t *p)
* string, or NULL for empty command.
*/
int
-cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
+cmd_string_parse(const char *s, struct cmd_list **cmdlist, const char *file,
+ u_int line, char **cause)
{
size_t p;
int ch, i, argc, rval;
@@ -131,7 +132,7 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
if (argc == 0)
goto out;
- *cmdlist = cmd_list_parse(argc, argv, cause);
+ *cmdlist = cmd_list_parse(argc, argv, file, line, cause);
if (*cmdlist == NULL)
goto out;
diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c
index 95278f98..101658b1 100644
--- a/cmd-suspend-client.c
+++ b/cmd-suspend-client.c
@@ -27,7 +27,7 @@
* Suspend client with SIGTSTP.
*/
-enum cmd_retval cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_suspend_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_suspend_client_entry = {
"suspend-client", "suspendc",
@@ -40,12 +40,12 @@ const struct cmd_entry cmd_suspend_client_entry = {
};
enum cmd_retval
-cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_suspend_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
- if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
+ if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
tty_stop_tty(&c->tty);
diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c
index 42fe2fcb..d484f4e2 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -27,7 +27,7 @@
*/
void cmd_swap_pane_key_binding(struct cmd *, int);
-enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_swap_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_swap_pane_entry = {
"swap-pane", "swapp",
@@ -50,7 +50,7 @@ cmd_swap_pane_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *src_wl, *dst_wl;
@@ -59,10 +59,11 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff;
- dst_wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &dst_wp);
+ dst_wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &dst_wp);
if (dst_wl == NULL)
return (CMD_RETURN_ERROR);
dst_w = dst_wl->window;
+ server_unzoom_window(dst_w);
if (!args_has(args, 's')) {
src_w = dst_w;
@@ -77,11 +78,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
} else
return (CMD_RETURN_NORMAL);
} else {
- src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
+ src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;
}
+ server_unzoom_window(src_w);
if (src_wp == dst_wp)
return (CMD_RETURN_NORMAL);
diff --git a/cmd-swap-window.c b/cmd-swap-window.c
index f0c9ffe2..f9a2cb1b 100644
--- a/cmd-swap-window.c
+++ b/cmd-swap-window.c
@@ -26,7 +26,7 @@
* Swap one window with another.
*/
-enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_swap_window_entry = {
"swap-window", "swapw",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_swap_window_entry = {
};
enum cmd_retval
-cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
const char *target_src, *target_dst;
@@ -49,17 +49,17 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct window *w;
target_src = args_get(args, 's');
- if ((wl_src = cmd_find_window(ctx, target_src, &src)) == NULL)
+ if ((wl_src = cmd_find_window(cmdq, target_src, &src)) == NULL)
return (CMD_RETURN_ERROR);
target_dst = args_get(args, 't');
- if ((wl_dst = cmd_find_window(ctx, target_dst, &dst)) == NULL)
+ if ((wl_dst = cmd_find_window(cmdq, target_dst, &dst)) == NULL)
return (CMD_RETURN_ERROR);
sg_src = session_group_find(src);
sg_dst = session_group_find(dst);
if (src != dst &&
sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) {
- ctx->error(ctx, "can't move window, sessions are grouped");
+ cmdq_error(cmdq, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-switch-client.c b/cmd-switch-client.c
index 1ca0c41d..9adb2146 100644
--- a/cmd-switch-client.c
+++ b/cmd-switch-client.c
@@ -28,7 +28,7 @@
*/
void cmd_switch_client_key_binding(struct cmd *, int);
-enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc",
@@ -58,45 +58,45 @@ cmd_switch_client_key_binding(struct cmd *self, int key)
}
enum cmd_retval
-cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
struct session *s;
- if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
+ if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'r')) {
if (c->flags & CLIENT_READONLY) {
c->flags &= ~CLIENT_READONLY;
- ctx->info(ctx, "made client writable");
+ cmdq_info(cmdq, "made client writable");
} else {
c->flags |= CLIENT_READONLY;
- ctx->info(ctx, "made client read-only");
+ cmdq_info(cmdq, "made client read-only");
}
}
s = NULL;
if (args_has(args, 'n')) {
if ((s = session_next_session(c->session)) == NULL) {
- ctx->error(ctx, "can't find next session");
+ cmdq_error(cmdq, "can't find next session");
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
if ((s = session_previous_session(c->session)) == NULL) {
- ctx->error(ctx, "can't find previous session");
+ cmdq_error(cmdq, "can't find previous session");
return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'l')) {
if (c->last_session != NULL && session_alive(c->last_session))
s = c->last_session;
if (s == NULL) {
- ctx->error(ctx, "can't find last session");
+ cmdq_error(cmdq, "can't find last session");
return (CMD_RETURN_ERROR);
}
} else
- s = cmd_find_session(ctx, args_get(args, 't'), 0);
+ s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c
index 261ded40..dc037dde 100644
--- a/cmd-unbind-key.c
+++ b/cmd-unbind-key.c
@@ -27,8 +27,8 @@
*/
enum cmd_retval cmd_unbind_key_check(struct args *);
-enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *);
-enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int);
+enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *);
+enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_q *, int);
const struct cmd_entry cmd_unbind_key_entry = {
"unbind-key", "unbind",
@@ -51,7 +51,7 @@ cmd_unbind_key_check(struct args *args)
}
enum cmd_retval
-cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
+cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct key_binding *bd;
@@ -60,14 +60,14 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
if (!args_has(args, 'a')) {
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);
}
} else
key = KEYC_NONE;
if (args_has(args, 't'))
- return (cmd_unbind_key_table(self, ctx, key));
+ return (cmd_unbind_key_table(self, cmdq, key));
if (key == KEYC_NONE) {
while (!RB_EMPTY(&key_bindings)) {
@@ -84,7 +84,7 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
}
enum cmd_retval
-cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
+cmd_unbind_key_table(struct cmd *self, struct cmd_q *cmdq, int key)
{
struct args *args = self->args;
const char *tablename;
@@ -93,7 +93,7 @@ cmd_unbind_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);
}
diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c
index 19731ba5..39cdd8ed 100644
--- a/cmd-unlink-window.c
+++ b/cmd-unlink-window.c
@@ -24,7 +24,7 @@
* Unlink a window, unless it would be destroyed by doing so (only one link).
*/
-enum cmd_retval cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval cmd_unlink_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_unlink_window_entry = {
"unlink-window", "unlinkw",
@@ -37,7 +37,7 @@ const struct cmd_entry cmd_unlink_window_entry = {
};
enum cmd_retval
-cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
+cmd_unlink_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
@@ -46,7 +46,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct session_group *sg;
u_int references;
- if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
+ if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;
@@ -59,7 +59,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
references = 1;
if (!args_has(self->args, 'k') && w->references == references) {
- ctx->error(ctx, "window is only linked to one session");
+ cmdq_error(cmdq, "window is only linked to one session");
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-wait-for.c b/cmd-wait-for.c
new file mode 100644
index 00000000..3a8d8ea4
--- /dev/null
+++ b/cmd-wait-for.c
@@ -0,0 +1,197 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
+ * Copyright (c) 2013 Thiago de Arruda <tpadilha84@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * Block or wake a client on a named wait channel.
+ */
+
+enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *);
+
+const struct cmd_entry cmd_wait_for_entry = {
+ "wait-for", "wait",
+ "LSU", 1, 1,
+ "[-LSU] channel",
+ 0,
+ NULL,
+ NULL,
+ cmd_wait_for_exec
+};
+
+struct wait_channel {
+ const char *name;
+ int locked;
+
+ TAILQ_HEAD(, cmd_q) waiters;
+ TAILQ_HEAD(, cmd_q) lockers;
+
+ RB_ENTRY(wait_channel) entry;
+};
+RB_HEAD(wait_channels, wait_channel);
+struct wait_channels wait_channels = RB_INITIALIZER(wait_channels);
+
+int wait_channel_cmp(struct wait_channel *, struct wait_channel *);
+RB_PROTOTYPE(wait_channels, wait_channel, entry, wait_channel_cmp);
+RB_GENERATE(wait_channels, wait_channel, entry, wait_channel_cmp);
+
+int
+wait_channel_cmp(struct wait_channel *wc1, struct wait_channel *wc2)
+{
+ return (strcmp(wc1->name, wc2->name));
+}
+
+enum cmd_retval cmd_wait_for_signal(struct cmd_q *, const char *,
+ struct wait_channel *);
+enum cmd_retval cmd_wait_for_wait(struct cmd_q *, const char *,
+ struct wait_channel *);
+enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const char *,
+ struct wait_channel *);
+enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *,
+ struct wait_channel *);
+
+enum cmd_retval
+cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ const char *name = args->argv[0];
+ struct wait_channel *wc, wc0;
+
+ wc0.name = name;
+ wc = RB_FIND(wait_channels, &wait_channels, &wc0);
+
+ if (args_has(args, 'S'))
+ return (cmd_wait_for_signal(cmdq, name, wc));
+ if (args_has(args, 'L'))
+ return (cmd_wait_for_lock(cmdq, name, wc));
+ if (args_has(args, 'U'))
+ return (cmd_wait_for_unlock(cmdq, name, wc));
+ return (cmd_wait_for_wait(cmdq, name, wc));
+}
+
+enum cmd_retval
+cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
+ struct wait_channel *wc)
+{
+ struct cmd_q *wq, *wq1;
+
+ if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) {
+ cmdq_error(cmdq, "no waiting clients on %s", name);
+ return (CMD_RETURN_ERROR);
+ }
+
+ TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
+ TAILQ_REMOVE(&wc->waiters, wq, waitentry);
+ if (!cmdq_free(wq))
+ cmdq_continue(wq);
+ }
+
+ if (!wc->locked) {
+ RB_REMOVE(wait_channels, &wait_channels, wc);
+ free((void*) wc->name);
+ free(wc);
+ }
+
+ return (CMD_RETURN_NORMAL);
+}
+
+enum cmd_retval
+cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
+ struct wait_channel *wc)
+{
+ if (cmdq->client == NULL || cmdq->client->session != NULL) {
+ cmdq_error(cmdq, "not able to wait");
+ return (CMD_RETURN_ERROR);
+ }
+
+ if (wc == NULL) {
+ wc = xmalloc(sizeof *wc);
+ wc->name = xstrdup(name);
+ wc->locked = 0;
+ TAILQ_INIT(&wc->waiters);
+ TAILQ_INIT(&wc->lockers);
+ RB_INSERT(wait_channels, &wait_channels, wc);
+ }
+
+ TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
+ cmdq->references++;
+
+ return (CMD_RETURN_WAIT);
+}
+
+enum cmd_retval
+cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
+ struct wait_channel *wc)
+{
+ if (cmdq->client == NULL || cmdq->client->session != NULL) {
+ cmdq_error(cmdq, "not able to lock");
+ return (CMD_RETURN_ERROR);
+ }
+
+ if (wc == NULL) {
+ wc = xmalloc(sizeof *wc);
+ wc->name = xstrdup(name);
+ wc->locked = 0;
+ TAILQ_INIT(&wc->waiters);
+ TAILQ_INIT(&wc->lockers);
+ RB_INSERT(wait_channels, &wait_channels, wc);
+ }
+
+ if (wc->locked) {
+ TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
+ cmdq->references++;
+ return (CMD_RETURN_WAIT);
+ }
+ wc->locked = 1;
+
+ return (CMD_RETURN_NORMAL);
+}
+
+enum cmd_retval
+cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
+ struct wait_channel *wc)
+{
+ struct cmd_q *wq;
+
+ 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);
+ } else {
+ wc->locked = 0;
+ if (TAILQ_EMPTY(&wc->waiters)) {
+ RB_REMOVE(wait_channels, &wait_channels, wc);
+ free((void*) wc->name);
+ free(wc);
+ }
+ }
+
+ return (CMD_RETURN_NORMAL);
+}
+
diff --git a/cmd.c b/cmd.c
index 6869c12c..16a9eb98 100644
--- a/cmd.c
+++ b/cmd.c
@@ -112,6 +112,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_switch_client_entry,
&cmd_unbind_key_entry,
&cmd_unlink_window_entry,
+ &cmd_wait_for_entry,
NULL
};
@@ -121,13 +122,14 @@ struct session *cmd_choose_session(int);
struct client *cmd_choose_client(struct clients *);
struct client *cmd_lookup_client(const char *);
struct session *cmd_lookup_session(const char *, int *);
+struct session *cmd_lookup_session_id(const char *);
struct winlink *cmd_lookup_window(struct session *, const char *, int *);
int cmd_lookup_index(struct session *, const char *, int *);
struct window_pane *cmd_lookup_paneid(const char *);
struct winlink *cmd_lookup_winlink_windowid(struct session *, const char *);
struct window *cmd_lookup_windowid(const char *);
-struct session *cmd_window_session(struct cmd_ctx *,
- struct window *, struct winlink **);
+struct session *cmd_window_session(struct cmd_q *, struct window *,
+ struct winlink **);
struct winlink *cmd_find_window_offset(const char *, struct session *, int *);
int cmd_find_index_offset(const char *, struct session *, int *);
struct window_pane *cmd_find_pane_offset(const char *, struct winlink *);
@@ -205,7 +207,7 @@ cmd_free_argv(int argc, char **argv)
}
struct cmd *
-cmd_parse(int argc, char **argv, char **cause)
+cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{
const struct cmd_entry **entryp, *entry;
struct cmd *cmd;
@@ -255,9 +257,14 @@ cmd_parse(int argc, char **argv, char **cause)
if (entry->check != NULL && entry->check(args) != 0)
goto usage;
- cmd = xmalloc(sizeof *cmd);
+ cmd = xcalloc(1, sizeof *cmd);
cmd->entry = entry;
cmd->args = args;
+
+ if (file != NULL)
+ cmd->file = xstrdup(file);
+ cmd->line = line;
+
return (cmd);
ambiguous:
@@ -281,19 +288,6 @@ usage:
return (NULL);
}
-enum cmd_retval
-cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
-{
- return (cmd->entry->exec(cmd, ctx));
-}
-
-void
-cmd_free(struct cmd *cmd)
-{
- args_free(cmd->args);
- free(cmd);
-}
-
size_t
cmd_print(struct cmd *cmd, char *buf, size_t len)
{
@@ -319,31 +313,33 @@ cmd_print(struct cmd *cmd, char *buf, size_t len)
* session from all sessions.
*/
struct session *
-cmd_current_session(struct cmd_ctx *ctx, int prefer_unattached)
+cmd_current_session(struct cmd_q *cmdq, int prefer_unattached)
{
- struct msg_command_data *data = ctx->msgdata;
- struct client *c = ctx->cmdclient;
+ struct msg_command_data *data = cmdq->msgdata;
+ struct client *c = cmdq->client;
struct session *s;
struct sessionslist ss;
struct winlink *wl;
struct window_pane *wp;
+ const char *path;
int found;
- if (ctx->curclient != NULL && ctx->curclient->session != NULL)
- return (ctx->curclient->session);
+ if (c != NULL && c->session != NULL)
+ return (c->session);
/*
- * If the name of the calling client's pty is know, build a list of the
- * sessions that contain it and if any choose either the first or the
- * newest.
+ * If the name of the calling client's pty is known, build a list of
+ * the sessions that contain it and if any choose either the first or
+ * the newest.
*/
- if (c != NULL && c->tty.path != NULL) {
+ path = c == NULL ? NULL : c->tty.path;
+ if (path != NULL) {
ARRAY_INIT(&ss);
RB_FOREACH(s, sessions, &sessions) {
found = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
- if (strcmp(wp->tty, c->tty.path) == 0) {
+ if (strcmp(wp->tty, path) == 0) {
found = 1;
break;
}
@@ -362,8 +358,8 @@ cmd_current_session(struct cmd_ctx *ctx, int prefer_unattached)
}
/* Use the session from the TMUX environment variable. */
- if (data != NULL && data->pid == getpid() && data->idx != -1) {
- s = session_find_by_index(data->idx);
+ if (data != NULL && data->pid == getpid() && data->session_id != -1) {
+ s = session_find_by_id(data->session_id);
if (s != NULL)
return (s);
}
@@ -434,21 +430,21 @@ cmd_choose_session_list(struct sessionslist *ss)
* then of all clients.
*/
struct client *
-cmd_current_client(struct cmd_ctx *ctx)
+cmd_current_client(struct cmd_q *cmdq)
{
struct session *s;
struct client *c;
struct clients cc;
u_int i;
- if (ctx->curclient != NULL)
- return (ctx->curclient);
+ if (cmdq->client != NULL && cmdq->client->session != NULL)
+ return (cmdq->client);
/*
* No current client set. Find the current session and return the
* newest of its clients.
*/
- s = cmd_current_session(ctx, 0);
+ s = cmd_current_session(cmdq, 0);
if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
ARRAY_INIT(&cc);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -493,15 +489,19 @@ cmd_choose_client(struct clients *cc)
/* Find the target client or report an error and return NULL. */
struct client *
-cmd_find_client(struct cmd_ctx *ctx, const char *arg)
+cmd_find_client(struct cmd_q *cmdq, const char *arg, int quiet)
{
struct client *c;
char *tmparg;
size_t arglen;
/* A NULL argument means the current client. */
- if (arg == NULL)
- return (cmd_current_client(ctx));
+ if (arg == NULL) {
+ c = cmd_current_client(cmdq);
+ if (c == NULL && !quiet)
+ cmdq_error(cmdq, "no clients");
+ return (c);
+ }
tmparg = xstrdup(arg);
/* Trim a single trailing colon if any. */
@@ -513,8 +513,8 @@ cmd_find_client(struct cmd_ctx *ctx, const char *arg)
c = cmd_lookup_client(tmparg);
/* If no client found, report an error. */
- if (c == NULL)
- ctx->error(ctx, "client not found: %s", tmparg);
+ if (c == NULL && !quiet)
+ cmdq_error(cmdq, "client not found: %s", tmparg);
free(tmparg);
return (c);
@@ -533,7 +533,7 @@ cmd_lookup_client(const char *name)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session == NULL)
+ if (c == NULL || c->session == NULL || c->tty.path == NULL)
continue;
path = c->tty.path;
@@ -551,6 +551,21 @@ cmd_lookup_client(const char *name)
return (NULL);
}
+/* Find the target session or report an error and return NULL. */
+struct session *
+cmd_lookup_session_id(const char *arg)
+{
+ char *endptr;
+ long id;
+
+ if (arg[0] != '$')
+ return (NULL);
+ id = strtol(arg + 1, &endptr, 10);
+ if (arg[1] != '\0' && *endptr == '\0')
+ return (session_find_by_id(id));
+ return (NULL);
+}
+
/* Lookup a session by name. If no session is found, NULL is returned. */
struct session *
cmd_lookup_session(const char *name, int *ambiguous)
@@ -559,6 +574,10 @@ cmd_lookup_session(const char *name, int *ambiguous)
*ambiguous = 0;
+ /* Look for $id first. */
+ if ((s = cmd_lookup_session_id(name)) != NULL)
+ return (s);
+
/*
* Look for matches. First look for exact matches - session names must
* be unique so an exact match can't be ambigious and can just be
@@ -716,14 +735,14 @@ cmd_lookup_windowid(const char *arg)
/* Find session and winlink for window. */
struct session *
-cmd_window_session(struct cmd_ctx *ctx, struct window *w, struct winlink **wlp)
+cmd_window_session(struct cmd_q *cmdq, struct window *w, struct winlink **wlp)
{
struct session *s;
struct sessionslist ss;
struct winlink *wl;
/* If this window is in the current session, return that winlink. */
- s = cmd_current_session(ctx, 0);
+ s = cmd_current_session(cmdq, 0);
if (s != NULL) {
wl = winlink_find_by_window(&s->windows, w);
if (wl != NULL) {
@@ -748,7 +767,7 @@ cmd_window_session(struct cmd_ctx *ctx, struct window *w, struct winlink **wlp)
/* Find the target session or report an error and return NULL. */
struct session *
-cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached)
+cmd_find_session(struct cmd_q *cmdq, const char *arg, int prefer_unattached)
{
struct session *s;
struct window_pane *wp;
@@ -760,13 +779,13 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached)
/* A NULL argument means the current session. */
if (arg == NULL)
- return (cmd_current_session(ctx, prefer_unattached));
+ return (cmd_current_session(cmdq, prefer_unattached));
/* Lookup as pane id or window id. */
if ((wp = cmd_lookup_paneid(arg)) != NULL)
- return (cmd_window_session(ctx, wp->window, NULL));
+ return (cmd_window_session(cmdq, wp->window, NULL));
if ((w = cmd_lookup_windowid(arg)) != NULL)
- return (cmd_window_session(ctx, w, NULL));
+ return (cmd_window_session(cmdq, w, NULL));
/* Trim a single trailing colon if any. */
tmparg = xstrdup(arg);
@@ -777,7 +796,7 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached)
/* An empty session name is the current session. */
if (*tmparg == '\0') {
free(tmparg);
- return (cmd_current_session(ctx, prefer_unattached));
+ return (cmd_current_session(cmdq, prefer_unattached));
}
/* Find the session, if any. */
@@ -790,9 +809,9 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached)
/* If no session found, report an error. */
if (s == NULL) {
if (ambiguous)
- ctx->error(ctx, "more than one session: %s", tmparg);
+ cmdq_error(cmdq, "more than one session: %s", tmparg);
else
- ctx->error(ctx, "session not found: %s", tmparg);
+ cmdq_error(cmdq, "session not found: %s", tmparg);
}
free(tmparg);
@@ -801,7 +820,7 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg, int prefer_unattached)
/* Find the target session and window or report an error and return NULL. */
struct winlink *
-cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
+cmd_find_window(struct cmd_q *cmdq, const char *arg, struct session **sp)
{
struct session *s;
struct winlink *wl;
@@ -814,8 +833,8 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
* Find the current session. There must always be a current session, if
* it can't be found, report an error.
*/
- if ((s = cmd_current_session(ctx, 0)) == NULL) {
- ctx->error(ctx, "can't establish current session");
+ if ((s = cmd_current_session(cmdq, 0)) == NULL) {
+ cmdq_error(cmdq, "can't establish current session");
return (NULL);
}
@@ -828,7 +847,7 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
/* Lookup as pane id. */
if ((wp = cmd_lookup_paneid(arg)) != NULL) {
- s = cmd_window_session(ctx, wp->window, &wl);
+ s = cmd_window_session(cmdq, wp->window, &wl);
if (sp != NULL)
*sp = s;
return (wl);
@@ -909,17 +928,17 @@ lookup_session:
no_session:
if (ambiguous)
- ctx->error(ctx, "multiple sessions: %s", arg);
+ cmdq_error(cmdq, "multiple sessions: %s", arg);
else
- ctx->error(ctx, "session not found: %s", arg);
+ cmdq_error(cmdq, "session not found: %s", arg);
free(sessptr);
return (NULL);
not_found:
if (ambiguous)
- ctx->error(ctx, "multiple windows: %s", arg);
+ cmdq_error(cmdq, "multiple windows: %s", arg);
else
- ctx->error(ctx, "window not found: %s", arg);
+ cmdq_error(cmdq, "window not found: %s", arg);
free(sessptr);
return (NULL);
}
@@ -951,7 +970,7 @@ cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous)
* example if it is going to be created).
*/
int
-cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
+cmd_find_index(struct cmd_q *cmdq, const char *arg, struct session **sp)
{
struct session *s;
struct winlink *wl;
@@ -963,8 +982,8 @@ cmd_find_index(struct cmd_ctx *ctx, const char *arg, struct session **sp)
* Find the current session. There must always be a current session, if
* it can't be found, report an error.
*/
- if ((s = cmd_current_session(ctx, 0)) == NULL) {
- ctx->error(ctx, "can't establish current session");
+ if ((s = cmd_current_session(cmdq, 0)) == NULL) {
+ cmdq_error(cmdq, "can't establish current session");
return (-2);
}
@@ -1047,25 +1066,25 @@ lookup_session:
no_session:
if (ambiguous)
- ctx->error(ctx, "multiple sessions: %s", arg);
+ cmdq_error(cmdq, "multiple sessions: %s", arg);
else
- ctx->error(ctx, "session not found: %s", arg);
+ cmdq_error(cmdq, "session not found: %s", arg);
free(sessptr);
return (-2);
invalid_index:
if (ambiguous)
goto not_found;
- ctx->error(ctx, "invalid index: %s", arg);
+ cmdq_error(cmdq, "invalid index: %s", arg);
free(sessptr);
return (-2);
not_found:
if (ambiguous)
- ctx->error(ctx, "multiple windows: %s", arg);
+ cmdq_error(cmdq, "multiple windows: %s", arg);
else
- ctx->error(ctx, "window not found: %s", arg);
+ cmdq_error(cmdq, "window not found: %s", arg);
free(sessptr);
return (-2);
}
@@ -1102,7 +1121,7 @@ cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous)
* such as mysession:mywindow.0.
*/
struct winlink *
-cmd_find_pane(struct cmd_ctx *ctx,
+cmd_find_pane(struct cmd_q *cmdq,
const char *arg, struct session **sp, struct window_pane **wpp)
{
struct session *s;
@@ -1112,8 +1131,8 @@ cmd_find_pane(struct cmd_ctx *ctx,
u_int idx;
/* Get the current session. */
- if ((s = cmd_current_session(ctx, 0)) == NULL) {
- ctx->error(ctx, "can't establish current session");
+ if ((s = cmd_current_session(cmdq, 0)) == NULL) {
+ cmdq_error(cmdq, "can't establish current session");
return (NULL);
}
if (sp != NULL)
@@ -1127,7 +1146,7 @@ cmd_find_pane(struct cmd_ctx *ctx,
/* Lookup as pane id. */
if ((*wpp = cmd_lookup_paneid(arg)) != NULL) {
- s = cmd_window_session(ctx, (*wpp)->window, &wl);
+ s = cmd_window_session(cmdq, (*wpp)->window, &wl);
if (sp != NULL)
*sp = s;
return (wl);
@@ -1142,7 +1161,7 @@ cmd_find_pane(struct cmd_ctx *ctx,
winptr[period - arg] = '\0';
if (*winptr == '\0')
wl = s->curw;
- else if ((wl = cmd_find_window(ctx, winptr, sp)) == NULL)
+ else if ((wl = cmd_find_window(cmdq, winptr, sp)) == NULL)
goto error;
/* Find the pane section and look it up. */
@@ -1166,7 +1185,7 @@ cmd_find_pane(struct cmd_ctx *ctx,
lookup_string:
/* Try pane string description. */
if ((*wpp = window_find_string(wl->window, paneptr)) == NULL) {
- ctx->error(ctx, "can't find pane: %s", paneptr);
+ cmdq_error(cmdq, "can't find pane: %s", paneptr);
goto error;
}
@@ -1191,7 +1210,7 @@ lookup_window:
return (s->curw);
/* Try as a window and use the active pane. */
- if ((wl = cmd_find_window(ctx, arg, sp)) != NULL)
+ if ((wl = cmd_find_window(cmdq, arg, sp)) != NULL)
*wpp = wl->window->active;
return (wl);
@@ -1221,14 +1240,14 @@ cmd_find_pane_offset(const char *paneptr, struct winlink *wl)
/* Replace the first %% or %idx in template by s. */
char *
-cmd_template_replace(char *template, const char *s, int idx)
+cmd_template_replace(const char *template, const char *s, int idx)
{
- char ch;
- char *buf, *ptr;
- int replaced;
- size_t len;
+ char ch, *buf;
+ const char *ptr;
+ int replaced;
+ size_t len;
- if (strstr(template, "%") == NULL)
+ if (strchr(template, '%') == NULL)
return (xstrdup(template));
buf = xmalloc(1);
@@ -1269,8 +1288,9 @@ cmd_template_replace(char *template, const char *s, int idx)
* directory.
*/
const char *
-cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd)
+cmd_get_default_path(struct cmd_q *cmdq, const char *cwd)
{
+ struct client *c = cmdq->client;
struct session *s;
struct environ_entry *envent;
const char *root;
@@ -1280,7 +1300,7 @@ cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd)
size_t skip;
static char path[MAXPATHLEN];
- if ((s = cmd_current_session(ctx, 0)) == NULL)
+ if ((s = cmd_current_session(cmdq, 0)) == NULL)
return (NULL);
if (cwd == NULL)
@@ -1310,10 +1330,10 @@ cmd_get_default_path(struct cmd_ctx *ctx, const char *cwd)
return (cwd);
} else {
/* Empty or relative path. */
- if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
- root = ctx->cmdclient->cwd;
- else if (ctx->curclient != NULL && s->curw != NULL)
- root = osdep_get_cwd(s->curw->window->active->fd);
+ if (c != NULL && c->session == NULL && c->cwd != NULL)
+ root = c->cwd;
+ else if (s->curw != NULL)
+ root = get_proc_cwd(s->curw->window->active->fd);
else
return (s->cwd);
skip = 0;
diff --git a/control-notify.c b/control-notify.c
index 87a25bb1..0931c23a 100644
--- a/control-notify.c
+++ b/control-notify.c
@@ -46,8 +46,12 @@ control_notify_input(struct client *c, struct window_pane *wp,
if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
message = evbuffer_new();
evbuffer_add_printf(message, "%%output %%%u ", wp->id);
- for (i = 0; i < len; i++)
- evbuffer_add_printf(message, "%02hhx", buf[i]);
+ for (i = 0; i < len; i++) {
+ if (buf[i] < ' ' || buf[i] == '\\')
+ evbuffer_add_printf(message, "\\%03o", buf[i]);
+ else
+ evbuffer_add_printf(message, "%c", buf[i]);
+ }
control_write_buffer(c, message);
evbuffer_free(message);
}
@@ -104,10 +108,7 @@ control_notify_window_unlinked(unused struct session *s, struct window *w)
continue;
cs = c->session;
- if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
- control_write(c, "%%window-close %u", w->id);
- else
- control_write(c, "%%unlinked-window-close %u", w->id);
+ control_write(c, "%%window-close @%u", w->id);
}
}
@@ -125,9 +126,9 @@ control_notify_window_linked(unused struct session *s, struct window *w)
cs = c->session;
if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
- control_write(c, "%%window-add %u", w->id);
+ control_write(c, "%%window-add @%u", w->id);
else
- control_write(c, "%%unlinked-window-add %u", w->id);
+ control_write(c, "%%unlinked-window-add @%u", w->id);
}
}
@@ -144,13 +145,7 @@ control_notify_window_renamed(struct window *w)
continue;
s = c->session;
- if (winlink_find_by_window_id(&s->windows, w->id) != NULL) {
- control_write(c, "%%window-renamed %u %s",
- w->id, w->name);
- } else {
- control_write(c, "%%unlinked-window-renamed %u %s",
- w->id, w->name);
- }
+ control_write(c, "%%window-renamed @%u %s", w->id, w->name);
}
}
@@ -163,7 +158,7 @@ control_notify_attached_session_changed(struct client *c)
return;
s = c->session;
- control_write(c, "%%session-changed %d %s", s->idx, s->name);
+ control_write(c, "%%session-changed $%u %s", s->id, s->name);
}
void
@@ -174,10 +169,10 @@ control_notify_session_renamed(struct session *s)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session != s)
+ if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
- control_write(c, "%%session-renamed %s", s->name);
+ control_write(c, "%%session-renamed $%u %s", s->id, s->name);
}
}
@@ -189,7 +184,7 @@ control_notify_session_created(unused struct session *s)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
+ if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%sessions-changed");
@@ -204,7 +199,7 @@ control_notify_session_close(unused struct session *s)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
+ if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%sessions-changed");
diff --git a/control.c b/control.c
index b5ec6bdb..c888877e 100644
--- a/control.c
+++ b/control.c
@@ -25,46 +25,6 @@
#include "tmux.h"
-void printflike2 control_msg_error(struct cmd_ctx *, const char *, ...);
-void printflike2 control_msg_print(struct cmd_ctx *, const char *, ...);
-void printflike2 control_msg_info(struct cmd_ctx *, const char *, ...);
-
-/* Command error callback. */
-void printflike2
-control_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
-{
- struct client *c = ctx->curclient;
- va_list ap;
-
- va_start(ap, fmt);
- evbuffer_add_vprintf(c->stdout_data, fmt, ap);
- va_end(ap);
-
- evbuffer_add(c->stdout_data, "\n", 1);
- server_push_stdout(c);
-}
-
-/* Command print callback. */
-void printflike2
-control_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
-{
- struct client *c = ctx->curclient;
- va_list ap;
-
- va_start(ap, fmt);
- evbuffer_add_vprintf(c->stdout_data, fmt, ap);
- va_end(ap);
-
- evbuffer_add(c->stdout_data, "\n", 1);
- server_push_stdout(c);
-}
-
-/* Command info callback. */
-void printflike2
-control_msg_info(unused struct cmd_ctx *ctx, unused const char *fmt, ...)
-{
-}
-
/* Write a line. */
void printflike2
control_write(struct client *c, const char *fmt, ...)
@@ -93,7 +53,6 @@ void
control_callback(struct client *c, int closed, unused void *data)
{
char *line, *cause;
- struct cmd_ctx ctx;
struct cmd_list *cmdlist;
if (closed)
@@ -108,20 +67,17 @@ control_callback(struct client *c, int closed, unused void *data)
break;
}
- ctx.msgdata = NULL;
- ctx.cmdclient = NULL;
- ctx.curclient = c;
+ if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) {
+ c->cmdq->time = time(NULL);
+ c->cmdq->number++;
- ctx.error = control_msg_error;
- ctx.print = control_msg_print;
- ctx.info = control_msg_info;
+ cmdq_guard(c->cmdq, "begin");
+ control_write(c, "parse error: %s", cause);
+ cmdq_guard(c->cmdq, "error");
- if (cmd_string_parse(line, &cmdlist, &cause) != 0) {
- control_write(c, "%%error in line \"%s\": %s", line,
- cause);
free(cause);
} else {
- cmd_list_exec(cmdlist, &ctx);
+ cmdq_run(c->cmdq, cmdlist);
cmd_list_free(cmdlist);
}
diff --git a/format.c b/format.c
index 5f57c72e..d70b7678 100644
--- a/format.c
+++ b/format.c
@@ -32,8 +32,9 @@
* string.
*/
-int format_replace(struct format_tree *,
- const char *, size_t, char **, size_t *, size_t *);
+int format_replace(struct format_tree *, const char *, size_t, char **,
+ size_t *, size_t *);
+void format_window_pane_tabs(struct format_tree *, struct window_pane *);
/* Format key-value replacement entry. */
RB_GENERATE(format_tree, format_entry, entry, format_cmp);
@@ -251,10 +252,11 @@ format_expand(struct format_tree *ft, const char *fmt)
continue;
}
}
- while (len - off < 2) {
+ while (len - off < 3) {
buf = xrealloc(buf, 2, len);
len *= 2;
}
+ buf[off++] = '#';
buf[off++] = ch;
continue;
}
@@ -278,6 +280,7 @@ format_session(struct format_tree *ft, struct session *s)
format_add(ft, "session_windows", "%u", winlink_count(&s->windows));
format_add(ft, "session_width", "%u", s->sx);
format_add(ft, "session_height", "%u", s->sy);
+ format_add(ft, "session_id", "$%u", s->id);
sg = session_group_find(s);
format_add(ft, "session_grouped", "%d", sg != NULL);
@@ -300,8 +303,9 @@ format_session(struct format_tree *ft, struct session *s)
void
format_client(struct format_tree *ft, struct client *c)
{
- char *tim;
- time_t t;
+ char *tim;
+ time_t t;
+ struct session *s;
format_add(ft, "client_cwd", "%s", c->cwd);
format_add(ft, "client_height", "%u", c->tty.sy);
@@ -321,6 +325,8 @@ format_client(struct format_tree *ft, struct client *c)
*strchr(tim, '\n') = '\0';
format_add(ft, "client_activity_string", "%s", tim);
+ format_add(ft, "client_prefix", "%d", !!(c->flags & CLIENT_PREFIX));
+
if (c->tty.flags & TTY_UTF8)
format_add(ft, "client_utf8", "%d", 1);
else
@@ -330,6 +336,13 @@ format_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_readonly", "%d", 1);
else
format_add(ft, "client_readonly", "%d", 0);
+
+ s = c->session;
+ if (s != NULL)
+ format_add(ft, "client_session", "%s", s->name);
+ s = c->last_session;
+ if (s != NULL && session_alive(s))
+ format_add(ft, "client_last_session", "%s", s->name);
}
/* Set default format keys for a winlink. */
@@ -356,6 +369,28 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl)
free(layout);
}
+/* Add window pane tabs. */
+void
+format_window_pane_tabs(struct format_tree *ft, struct window_pane *wp)
+{
+ struct evbuffer *buffer;
+ u_int i;
+
+ buffer = evbuffer_new();
+ for (i = 0; i < wp->base.grid->sx; i++) {
+ if (!bit_test(wp->base.tabs, i))
+ continue;
+
+ if (EVBUFFER_LENGTH(buffer) > 0)
+ evbuffer_add(buffer, ",", 1);
+ evbuffer_add_printf(buffer, "%d", i);
+ }
+
+ format_add(ft, "pane_tabs", "%.*s", (int) EVBUFFER_LENGTH(buffer),
+ EVBUFFER_DATA(buffer));
+ evbuffer_free(buffer);
+}
+
/* Set default format keys for a window pane. */
void
format_window_pane(struct format_tree *ft, struct window_pane *wp)
@@ -363,9 +398,9 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
struct grid *gd = wp->base.grid;
struct grid_line *gl;
unsigned long long size;
- u_int i;
- u_int idx;
+ u_int i, idx;
const char *cwd;
+ char *cmd;
size = 0;
for (i = 0; i < gd->hsize; i++) {
@@ -373,31 +408,72 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
size += gl->cellsize * sizeof *gl->celldata;
}
size += gd->hsize * sizeof *gd->linedata;
+ format_add(ft, "history_size", "%u", gd->hsize);
+ format_add(ft, "history_limit", "%u", gd->hlimit);
+ format_add(ft, "history_bytes", "%llu", size);
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
+ format_add(ft, "pane_index", "%u", idx);
format_add(ft, "pane_width", "%u", wp->sx);
format_add(ft, "pane_height", "%u", wp->sy);
format_add(ft, "pane_title", "%s", wp->base.title);
- format_add(ft, "pane_index", "%u", idx);
- format_add(ft, "history_size", "%u", gd->hsize);
- format_add(ft, "history_limit", "%u", gd->hlimit);
- format_add(ft, "history_bytes", "%llu", size);
format_add(ft, "pane_id", "%%%u", wp->id);
format_add(ft, "pane_active", "%d", wp == wp->window->active);
format_add(ft, "pane_dead", "%d", wp->fd == -1);
+
+ format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base);
+
+ if (wp->tty != NULL)
+ format_add(ft, "pane_tty", "%s", wp->tty);
+ format_add(ft, "pane_pid", "%ld", (long) wp->pid);
if (wp->cmd != NULL)
format_add(ft, "pane_start_command", "%s", wp->cmd);
if (wp->cwd != NULL)
format_add(ft, "pane_start_path", "%s", wp->cwd);
if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
format_add(ft, "pane_current_path", "%s", cwd);
- format_add(ft, "pane_pid", "%ld", (long) wp->pid);
- if (wp->tty != NULL)
- format_add(ft, "pane_tty", "%s", wp->tty);
+ if ((cmd = get_proc_name(wp->fd, wp->tty)) != NULL) {
+ format_add(ft, "pane_current_command", "%s", cmd);
+ free(cmd);
+ }
+
+ format_add(ft, "cursor_x", "%d", wp->base.cx);
+ format_add(ft, "cursor_y", "%d", wp->base.cy);
+ format_add(ft, "scroll_region_upper", "%d", wp->base.rupper);
+ format_add(ft, "scroll_region_lower", "%d", wp->base.rlower);
+ format_add(ft, "saved_cursor_x", "%d", wp->ictx.old_cx);
+ format_add(ft, "saved_cursor_y", "%d", wp->ictx.old_cy);
+
+ format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0);
+ format_add(ft, "alternate_saved_x", "%d", wp->saved_cx);
+ format_add(ft, "alternate_saved_y", "%d", wp->saved_cy);
+
+ format_add(ft, "cursor_flag", "%d",
+ !!(wp->base.mode & MODE_CURSOR));
+ format_add(ft, "insert_flag", "%d",
+ !!(wp->base.mode & MODE_INSERT));
+ format_add(ft, "keypad_cursor_flag", "%d",
+ !!(wp->base.mode & MODE_KCURSOR));
+ format_add(ft, "keypad_flag", "%d",
+ !!(wp->base.mode & MODE_KKEYPAD));
+ format_add(ft, "wrap_flag", "%d",
+ !!(wp->base.mode & MODE_WRAP));
+
+ format_add(ft, "mouse_standard_flag", "%d",
+ !!(wp->base.mode & MODE_MOUSE_STANDARD));
+ format_add(ft, "mouse_button_flag", "%d",
+ !!(wp->base.mode & MODE_MOUSE_BUTTON));
+ format_add(ft, "mouse_any_flag", "%d",
+ !!(wp->base.mode & MODE_MOUSE_ANY));
+ format_add(ft, "mouse_utf8_flag", "%d",
+ !!(wp->base.mode & MODE_MOUSE_UTF8));
+
+ format_window_pane_tabs(ft, wp);
}
+/* Set default format keys for paste buffer. */
void
format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
{
diff --git a/grid-view.c b/grid-view.c
index b4355413..7ef443a3 100644
--- a/grid-view.c
+++ b/grid-view.c
@@ -234,5 +234,5 @@ grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx)
px = grid_view_x(gd, px);
py = grid_view_y(gd, py);
- return (grid_string_cells(gd, px, py, nx));
+ return (grid_string_cells(gd, px, py, nx, NULL, 0, 0, 0));
}
diff --git a/grid.c b/grid.c
index aabf66cb..2955e8ba 100644
--- a/grid.c
+++ b/grid.c
@@ -70,6 +70,15 @@ grid_check_y(struct grid *gd, u_int py)
}
#endif
+void grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int);
+void grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int,
+ u_int);
+void grid_reflow_move(struct grid *, u_int *, struct grid_line *);
+size_t grid_string_cells_fg(const struct grid_cell *, int *);
+size_t grid_string_cells_bg(const struct grid_cell *, int *);
+void grid_string_cells_code(const struct grid_cell *,
+ const struct grid_cell *, char *, size_t, int);
+
/* Create a new grid. */
struct grid *
grid_create(u_int sx, u_int sy, u_int hlimit)
@@ -225,6 +234,15 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx)
gl->cellsize = sx;
}
+/* Peek at grid line. */
+const struct grid_line *
+grid_peek_line(struct grid *gd, u_int py)
+{
+ if (grid_check_y(gd, py) != 0)
+ return (NULL);
+ return (&gd->linedata[py]);
+}
+
/* Get cell for reading. */
const struct grid_cell *
grid_peek_cell(struct grid *gd, u_int px, u_int py)
@@ -387,18 +405,201 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
}
}
+/* Get ANSI foreground sequence. */
+size_t
+grid_string_cells_fg(const struct grid_cell *gc, int *values)
+{
+ size_t n;
+
+ n = 0;
+ if (gc->flags & GRID_FLAG_FG256) {
+ values[n++] = 38;
+ values[n++] = 5;
+ values[n++] = gc->fg;
+ } else {
+ switch (gc->fg) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ values[n++] = gc->fg + 30;
+ break;
+ case 8:
+ values[n++] = 39;
+ break;
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ values[n++] = gc->fg;
+ break;
+ }
+ }
+ return (n);
+}
+
+/* Get ANSI background sequence. */
+size_t
+grid_string_cells_bg(const struct grid_cell *gc, int *values)
+{
+ size_t n;
+
+ n = 0;
+ if (gc->flags & GRID_FLAG_BG256) {
+ values[n++] = 48;
+ values[n++] = 5;
+ values[n++] = gc->bg;
+ } else {
+ switch (gc->bg) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ values[n++] = gc->bg + 40;
+ break;
+ case 8:
+ values[n++] = 49;
+ break;
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ values[n++] = gc->bg - 10;
+ break;
+ }
+ }
+ return (n);
+}
+
+/*
+ * Returns ANSI code to set particular attributes (colour, bold and so on)
+ * given a current state. The output buffer must be able to hold at least 57
+ * bytes.
+ */
+void
+grid_string_cells_code(const struct grid_cell *lastgc,
+ const struct grid_cell *gc, char *buf, size_t len, int escape_c0)
+{
+ int oldc[16], newc[16], s[32];
+ size_t noldc, nnewc, n, i;
+ u_int attr = gc->attr;
+ u_int lastattr = lastgc->attr;
+ char tmp[64];
+
+ struct {
+ u_int mask;
+ u_int code;
+ } attrs[] = {
+ { GRID_ATTR_BRIGHT, 1 },
+ { GRID_ATTR_DIM, 2 },
+ { GRID_ATTR_ITALICS, 3 },
+ { GRID_ATTR_UNDERSCORE, 4 },
+ { GRID_ATTR_BLINK, 5 },
+ { GRID_ATTR_REVERSE, 7 },
+ { GRID_ATTR_HIDDEN, 8 }
+ };
+ n = 0;
+
+ /* If any attribute is removed, begin with 0. */
+ for (i = 0; i < nitems(attrs); i++) {
+ if (!(attr & attrs[i].mask) && (lastattr & attrs[i].mask)) {
+ s[n++] = 0;
+ lastattr &= GRID_ATTR_CHARSET;
+ break;
+ }
+ }
+ /* For each attribute that is newly set, add its code. */
+ for (i = 0; i < nitems(attrs); i++) {
+ if ((attr & attrs[i].mask) && !(lastattr & attrs[i].mask))
+ s[n++] = attrs[i].code;
+ }
+
+ /* If the foreground c changed, append its parameters. */
+ nnewc = grid_string_cells_fg(gc, newc);
+ noldc = grid_string_cells_fg(lastgc, oldc);
+ if (nnewc != noldc ||
+ memcmp(newc,oldc, nnewc * sizeof newc[0]) != 0) {
+ for (i = 0; i < nnewc; i++)
+ s[n++] = newc[i];
+ }
+
+ /* If the background c changed, append its parameters. */
+ nnewc = grid_string_cells_bg(gc, newc);
+ noldc = grid_string_cells_bg(lastgc, oldc);
+ if (nnewc != noldc ||
+ memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0) {
+ for (i = 0; i < nnewc; i++)
+ s[n++] = newc[i];
+ }
+
+ /* If there are any parameters, append an SGR code. */
+ *buf = '\0';
+ if (n > 0) {
+ if (escape_c0)
+ strlcat(buf, "\\033[", len);
+ else
+ strlcat(buf, "\033[", len);
+ for (i = 0; i < n; i++) {
+ if (i + 1 < n)
+ xsnprintf(tmp, sizeof tmp, "%d;", s[i]);
+ else
+ xsnprintf(tmp, sizeof tmp, "%d", s[i]);
+ strlcat(buf, tmp, len);
+ }
+ strlcat(buf, "m", len);
+ }
+
+ /* Append shift in/shift out if needed. */
+ if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) {
+ if (escape_c0)
+ strlcat(buf, "\\016", len); /* SO */
+ else
+ strlcat(buf, "\016", len); /* SO */
+ }
+ if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) {
+ if (escape_c0)
+ strlcat(buf, "\\017", len); /* SI */
+ else
+ strlcat(buf, "\017", len); /* SI */
+ }
+}
+
/* Convert cells into a string. */
char *
-grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx)
+grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
+ struct grid_cell **lastgc, int with_codes, int escape_c0, int trim)
{
const struct grid_cell *gc;
+ static struct grid_cell lastgc1;
struct utf8_data ud;
- char *buf;
- size_t len, off;
+ const char* data;
+ char *buf, code[128];
+ size_t len, off, size, codelen;
u_int xx;
GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx);
+ if (lastgc != NULL && *lastgc == NULL) {
+ memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1);
+ *lastgc = &lastgc1;
+ }
+
len = 128;
buf = xmalloc(len);
off = 0;
@@ -409,18 +610,40 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx)
continue;
grid_cell_get(gc, &ud);
- while (len < off + ud.size + 1) {
+ if (with_codes) {
+ grid_string_cells_code(*lastgc, gc, code, sizeof code,
+ escape_c0);
+ codelen = strlen(code);
+ memcpy(*lastgc, gc, sizeof *gc);
+ } else
+ codelen = 0;
+
+ data = ud.data;
+ size = ud.size;
+ if (escape_c0 && size == 1 && *data == '\\') {
+ data = "\\\\";
+ size = 2;
+ }
+
+ while (len < off + size + codelen + 1) {
buf = xrealloc(buf, 2, len);
len *= 2;
}
- memcpy(buf + off, ud.data, ud.size);
- off += ud.size;
+ if (codelen != 0) {
+ memcpy(buf + off, code, codelen);
+ off += codelen;
+ }
+ memcpy(buf + off, data, size);
+ off += size;
}
- while (off > 0 && buf[off - 1] == ' ')
- off--;
+ if (trim) {
+ while (off > 0 && buf[off - 1] == ' ')
+ off--;
+ }
buf[off] = '\0';
+
return (buf);
}
@@ -461,43 +684,135 @@ grid_duplicate_lines(
}
}
+/* Join line data. */
+void
+grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl,
+ u_int new_x)
+{
+ struct grid_line *dst_gl = &dst->linedata[(*py) - 1];
+ u_int left, to_copy, ox, nx;
+
+ /* How much is left on the old line? */
+ left = new_x - dst_gl->cellsize;
+
+ /* Work out how much to append. */
+ to_copy = src_gl->cellsize;
+ if (to_copy > left)
+ to_copy = left;
+ ox = dst_gl->cellsize;
+ nx = ox + to_copy;
+
+ /* Resize the destination line. */
+ dst_gl->celldata = xrealloc(dst_gl->celldata, nx,
+ sizeof *dst_gl->celldata);
+ dst_gl->cellsize = nx;
+
+ /* Append as much as possible. */
+ memcpy(&dst_gl->celldata[ox], &src_gl->celldata[0],
+ to_copy * sizeof src_gl->celldata[0]);
+
+ /* If there is any left in the source, split it. */
+ if (src_gl->cellsize > to_copy) {
+ dst_gl->flags |= GRID_LINE_WRAPPED;
+
+ src_gl->cellsize -= to_copy;
+ grid_reflow_split(dst, py, src_gl, new_x, to_copy);
+ }
+}
+
+/* Split line data. */
+void
+grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl,
+ u_int new_x, u_int offset)
+{
+ struct grid_line *dst_gl = NULL;
+ u_int to_copy;
+
+ /* Loop and copy sections of the source line. */
+ while (src_gl->cellsize > 0) {
+ /* Create new line. */
+ if (*py >= dst->hsize + dst->sy)
+ grid_scroll_history(dst);
+ dst_gl = &dst->linedata[*py];
+ (*py)++;
+
+ /* How much should we copy? */
+ to_copy = new_x;
+ if (to_copy > src_gl->cellsize)
+ to_copy = src_gl->cellsize;
+
+ /* Expand destination line. */
+ dst_gl->celldata = xmalloc(to_copy * sizeof *dst_gl->celldata);
+ dst_gl->cellsize = to_copy;
+ dst_gl->flags |= GRID_LINE_WRAPPED;
+
+ /* Copy the data. */
+ memcpy (&dst_gl->celldata[0], &src_gl->celldata[offset],
+ to_copy * sizeof dst_gl->celldata[0]);
+
+ /* Move offset and reduce old line size. */
+ offset += to_copy;
+ src_gl->cellsize -= to_copy;
+ }
+
+ /* Last line is not wrapped. */
+ if (dst_gl != NULL)
+ dst_gl->flags &= ~GRID_LINE_WRAPPED;
+}
+
+/* Move line data. */
+void
+grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl)
+{
+ struct grid_line *dst_gl;
+
+ /* Create new line. */
+ if (*py >= dst->hsize + dst->sy)
+ grid_scroll_history(dst);
+ dst_gl = &dst->linedata[*py];
+ (*py)++;
+
+ /* Copy the old line. */
+ memcpy(dst_gl, src_gl, sizeof *dst_gl);
+ dst_gl->flags &= ~GRID_LINE_WRAPPED;
+
+ /* Clear old line. */
+ src_gl->celldata = NULL;
+}
+
/*
- * Reflow lines from src grid into dst grid based on width sx. Returns number
- * of lines fewer in the visible area, or zero.
+ * Reflow lines from src grid into dst grid of width new_x. Returns number of
+ * lines fewer in the visible area. The source grid is destroyed.
*/
u_int
-grid_reflow(struct grid *dst, const struct grid *src, u_int sx)
+grid_reflow(struct grid *dst, struct grid *src, u_int new_x)
{
- u_int px, py, line, cell;
+ u_int py, sy, line;
int previous_wrapped;
- struct grid_line *gl;
+ struct grid_line *src_gl;
+
+ py = 0;
+ sy = src->sy;
- px = py = 0;
- previous_wrapped = 1;
- for (line = 0; line < src->sy + src->hsize; line++) {
- gl = src->linedata + line;
+ previous_wrapped = 0;
+ for (line = 0; line < sy + src->hsize; line++) {
+ src_gl = src->linedata + line;
if (!previous_wrapped) {
- px = 0;
- py++;
- if (py >= dst->hsize + dst->sy)
- grid_scroll_history(dst);
+ /* Wasn't wrapped. If smaller, move to destination. */
+ if (src_gl->cellsize <= new_x)
+ grid_reflow_move(dst, &py, src_gl);
+ else
+ grid_reflow_split(dst, &py, src_gl, new_x, 0);
+ } else {
+ /* Previous was wrapped. Try to join. */
+ grid_reflow_join(dst, &py, src_gl, new_x);
}
- for (cell = 0; cell < gl->cellsize; cell++) {
- if (px == sx) {
- dst->linedata[py].flags |= GRID_LINE_WRAPPED;
- px = 0;
- py++;
- if (py >= dst->hsize + dst->sy)
- grid_scroll_history(dst);
- }
- grid_set_cell(dst, px, py, gl->celldata + cell);
- px++;
- }
- previous_wrapped = gl->flags & GRID_LINE_WRAPPED;
+ previous_wrapped = src_gl->flags & GRID_LINE_WRAPPED;
}
- py++; /* account for final line, which never wraps */
- if (py > src->sy)
+ grid_destroy(src);
+
+ if (py > sy)
return (0);
- return (src->sy - py);
+ return (sy - py);
}
diff --git a/input-keys.c b/input-keys.c
index 0953ce7e..faa7bd17 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -201,12 +201,26 @@ input_key(struct window_pane *wp, int key)
void
input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
{
- char buf[10];
+ char buf[40];
size_t len;
struct paste_buffer *pb;
if (wp->screen->mode & ALL_MOUSE_MODES) {
- if (wp->screen->mode & MODE_MOUSE_UTF8) {
+ /*
+ * Use the SGR (1006) extension only if the application
+ * requested it and the underlying terminal also sent the event
+ * in this format (this is because an old style mouse release
+ * event cannot be converted into the new SGR format, since the
+ * released button is unknown). Otherwise pretend that tmux
+ * doesn't speak this extension, and fall back to the UTF-8
+ * (1005) extension if the application requested, or to the
+ * legacy format.
+ */
+ if (m->sgr && (wp->screen->mode & MODE_MOUSE_SGR)) {
+ len = xsnprintf(buf, sizeof buf, "\033[<%d;%d;%d%c",
+ m->sgr_xb, m->x + 1, m->y + 1,
+ m->sgr_rel ? 'm' : 'M');
+ } else if (wp->screen->mode & MODE_MOUSE_UTF8) {
len = xsnprintf(buf, sizeof buf, "\033[M");
len += utf8_split2(m->xb + 32, &buf[len]);
len += utf8_split2(m->x + 33, &buf[len]);
diff --git a/input.c b/input.c
index 3b8d76b0..4aa02e90 100644
--- a/input.c
+++ b/input.c
@@ -1033,10 +1033,10 @@ input_esc_dispatch(struct input_ctx *ictx)
screen_write_reverseindex(sctx);
break;
case INPUT_ESC_DECKPAM:
- screen_write_kkeypadmode(sctx, 1);
+ screen_write_mode_set(sctx, MODE_KKEYPAD);
break;
case INPUT_ESC_DECKPNM:
- screen_write_kkeypadmode(sctx, 0);
+ screen_write_mode_clear(sctx, MODE_KKEYPAD);
break;
case INPUT_ESC_DECSC:
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
@@ -1232,7 +1232,7 @@ input_csi_dispatch(struct input_ctx *ictx)
case INPUT_CSI_RM:
switch (input_get(ictx, 0, 0, -1)) {
case 4: /* IRM */
- screen_write_insertmode(&ictx->ctx, 0);
+ screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -1242,23 +1242,32 @@ input_csi_dispatch(struct input_ctx *ictx)
case INPUT_CSI_RM_PRIVATE:
switch (input_get(ictx, 0, 0, -1)) {
case 1: /* GATM */
- screen_write_kcursormode(&ictx->ctx, 0);
+ screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
break;
case 3: /* DECCOLM */
screen_write_cursormove(&ictx->ctx, 0, 0);
screen_write_clearscreen(&ictx->ctx);
break;
+ case 7: /* DECAWM */
+ screen_write_mode_clear(&ictx->ctx, MODE_WRAP);
+ break;
case 25: /* TCEM */
- screen_write_cursormode(&ictx->ctx, 0);
+ screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
break;
case 1000:
case 1001:
case 1002:
case 1003:
- screen_write_mousemode_off(&ictx->ctx);
+ screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
+ break;
+ case 1004:
+ screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON);
break;
case 1005:
- screen_write_utf8mousemode(&ictx->ctx, 0);
+ screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
+ break;
+ case 1006:
+ screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
break;
case 47:
case 1047:
@@ -1268,7 +1277,7 @@ input_csi_dispatch(struct input_ctx *ictx)
window_pane_alternate_off(wp, &ictx->cell, 1);
break;
case 2004:
- screen_write_bracketpaste(&ictx->ctx, 0);
+ screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -1286,7 +1295,7 @@ input_csi_dispatch(struct input_ctx *ictx)
case INPUT_CSI_SM:
switch (input_get(ictx, 0, 0, -1)) {
case 4: /* IRM */
- screen_write_insertmode(&ictx->ctx, 1);
+ screen_write_mode_set(&ictx->ctx, MODE_INSERT);
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
@@ -1296,28 +1305,41 @@ input_csi_dispatch(struct input_ctx *ictx)
case INPUT_CSI_SM_PRIVATE:
switch (input_get(ictx, 0, 0, -1)) {
case 1: /* GATM */
- screen_write_kcursormode(&ictx->ctx, 1);
+ screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
break;
case 3: /* DECCOLM */
screen_write_cursormove(&ictx->ctx, 0, 0);
screen_write_clearscreen(&ictx->ctx);
break;
+ case 7: /* DECAWM */
+ screen_write_mode_set(&ictx->ctx, MODE_WRAP);
+ break;
case 25: /* TCEM */
- screen_write_cursormode(&ictx->ctx, 1);
+ screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
break;
case 1000:
- screen_write_mousemode_on(
- &ictx->ctx, MODE_MOUSE_STANDARD);
+ screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
+ screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD);
break;
case 1002:
- screen_write_mousemode_on(
- &ictx->ctx, MODE_MOUSE_BUTTON);
+ screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
+ screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON);
break;
case 1003:
- screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
+ screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
+ screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY);
+ break;
+ case 1004:
+ if (s->mode & MODE_FOCUSON)
+ break;
+ screen_write_mode_set(&ictx->ctx, MODE_FOCUSON);
+ wp->flags &= ~PANE_FOCUSED; /* force update if needed */
break;
case 1005:
- screen_write_utf8mousemode(&ictx->ctx, 1);
+ screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
+ break;
+ case 1006:
+ screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
break;
case 47:
case 1047:
@@ -1327,7 +1349,7 @@ input_csi_dispatch(struct input_ctx *ictx)
window_pane_alternate_on(wp, &ictx->cell, 1);
break;
case 2004:
- screen_write_bracketpaste(&ictx->ctx, 1);
+ screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
diff --git a/job.c b/job.c
index c648eae0..6a7286ae 100644
--- a/job.c
+++ b/job.c
@@ -32,13 +32,14 @@
*/
void job_callback(struct bufferevent *, short, void *);
+void job_write_callback(struct bufferevent *, void *);
/* All jobs list. */
struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
/* Start a job running, if it isn't already. */
struct job *
-job_run(const char *cmd,
+job_run(const char *cmd, struct session *s,
void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
{
struct job *job;
@@ -51,7 +52,9 @@ job_run(const char *cmd,
environ_init(&env);
environ_copy(&global_environ, &env);
- server_fill_environ(NULL, &env);
+ if (s != NULL)
+ environ_copy(&s->environ, &env);
+ server_fill_environ(s, &env);
switch (pid = fork()) {
case -1:
@@ -63,20 +66,20 @@ job_run(const char *cmd,
environ_push(&env);
environ_free(&env);
+ if (dup2(out[1], STDIN_FILENO) == -1)
+ fatal("dup2 failed");
if (dup2(out[1], STDOUT_FILENO) == -1)
fatal("dup2 failed");
- if (out[1] != STDOUT_FILENO)
+ if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
close(out[1]);
close(out[0]);
nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
if (nullfd < 0)
fatal("open failed");
- if (dup2(nullfd, STDIN_FILENO) == -1)
- fatal("dup2 failed");
if (dup2(nullfd, STDERR_FILENO) == -1)
fatal("dup2 failed");
- if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
+ if (nullfd != STDERR_FILENO)
close(nullfd);
closefrom(STDERR_FILENO + 1);
@@ -103,7 +106,8 @@ job_run(const char *cmd,
job->fd = out[0];
setblocking(job->fd, 0);
- job->event = bufferevent_new(job->fd, NULL, NULL, job_callback, job);
+ job->event = bufferevent_new(job->fd, NULL, job_write_callback,
+ job_callback, job);
bufferevent_enable(job->event, EV_READ);
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
@@ -132,8 +136,23 @@ job_free(struct job *job)
free(job);
}
+/* Called when output buffer falls below low watermark (default is 0). */
+void
+job_write_callback(unused struct bufferevent *bufev, void *data)
+{
+ struct job *job = data;
+ size_t len = EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job->event));
+
+ log_debug("job write %p: %s, pid %ld, output left %lu", job, job->cmd,
+ (long) job->pid, (unsigned long) len);
+
+ if (len == 0) {
+ shutdown(job->fd, SHUT_WR);
+ bufferevent_disable(job->event, EV_WRITE);
+ }
+}
+
/* Job buffer error callback. */
-/* ARGSUSED */
void
job_callback(unused struct bufferevent *bufev, unused short events, void *data)
{
diff --git a/key-bindings.c b/key-bindings.c
index cf5237d4..86048ea6 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -150,6 +150,7 @@ key_bindings_init(void)
{ 't', 0, &cmd_clock_mode_entry },
{ 'w', 0, &cmd_choose_window_entry },
{ 'x', 0, &cmd_confirm_before_entry },
+ { 'z', 0, &cmd_resize_pane_entry },
{ '{', 0, &cmd_swap_pane_entry },
{ '}', 0, &cmd_swap_pane_entry },
{ '~', 0, &cmd_show_messages_entry },
@@ -182,11 +183,11 @@ key_bindings_init(void)
RB_INIT(&key_bindings);
for (i = 0; i < nitems(table); i++) {
- cmdlist = xmalloc(sizeof *cmdlist);
- TAILQ_INIT(&cmdlist->list);
+ cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1;
+ TAILQ_INIT(&cmdlist->list);
- cmd = xmalloc(sizeof *cmd);
+ cmd = xcalloc(1, sizeof *cmd);
cmd->entry = table[i].entry;
if (cmd->entry->key_binding != NULL)
cmd->entry->key_binding(cmd, table[i].key);
@@ -199,91 +200,21 @@ key_bindings_init(void)
}
}
-void printflike2
-key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...)
-{
- va_list ap;
- char *msg;
-
- if (ctx->curclient->session == NULL)
- return;
-
- va_start(ap, fmt);
- xvasprintf(&msg, fmt, ap);
- va_end(ap);
-
- *msg = toupper((u_char) *msg);
- status_message_set(ctx->curclient, "%s", msg);
- free(msg);
-}
-
-void printflike2
-key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...)
-{
- struct winlink *wl;
- va_list ap;
-
- if (ctx->curclient->session == NULL)
- return;
-
- wl = ctx->curclient->session->curw;
- if (wl->window->active->mode != &window_copy_mode) {
- window_pane_reset_mode(wl->window->active);
- window_pane_set_mode(wl->window->active, &window_copy_mode);
- window_copy_init_for_output(wl->window->active);
- }
-
- va_start(ap, fmt);
- window_copy_vadd(wl->window->active, fmt, ap);
- va_end(ap);
-}
-
-void printflike2
-key_bindings_info(struct cmd_ctx *ctx, const char *fmt, ...)
-{
- va_list ap;
- char *msg;
-
- if (ctx->curclient->session == NULL)
- return;
-
- if (options_get_number(&global_options, "quiet"))
- return;
-
- va_start(ap, fmt);
- xvasprintf(&msg, fmt, ap);
- va_end(ap);
-
- *msg = toupper((u_char) *msg);
- status_message_set(ctx->curclient, "%s", msg);
- free(msg);
-}
-
void
key_bindings_dispatch(struct key_binding *bd, struct client *c)
{
- struct cmd_ctx ctx;
struct cmd *cmd;
int readonly;
- ctx.msgdata = NULL;
- ctx.curclient = c;
-
- ctx.error = key_bindings_error;
- ctx.print = key_bindings_print;
- ctx.info = key_bindings_info;
-
- ctx.cmdclient = NULL;
-
readonly = 1;
TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) {
if (!(cmd->entry->flags & CMD_READONLY))
readonly = 0;
}
- if (!readonly && c->flags & CLIENT_READONLY) {
- key_bindings_info(&ctx, "Client is read-only");
+ if (!readonly && (c->flags & CLIENT_READONLY)) {
+ cmdq_info(c->cmdq, "client is read-only");
return;
}
- cmd_list_exec(bd->cmdlist, &ctx);
+ cmdq_run(c->cmdq, bd->cmdlist);
}
diff --git a/key-string.c b/key-string.c
index df177399..797eedd5 100644
--- a/key-string.c
+++ b/key-string.c
@@ -136,9 +136,10 @@ key_string_get_modifiers(const char **string)
int
key_string_lookup_string(const char *string)
{
- int key, modifiers;
- u_short u;
- int size;
+ static const char *other = "!#()+,-.0123456789:;<=>?'\r\t";
+ int key, modifiers;
+ u_short u;
+ int size;
/* Is this a hexadecimal value? */
if (string[0] == '0' && string[1] == 'x') {
@@ -170,7 +171,7 @@ key_string_lookup_string(const char *string)
}
/* Convert the standard control keys. */
- if (key < KEYC_BASE && (modifiers & KEYC_CTRL)) {
+ if (key < KEYC_BASE && (modifiers & KEYC_CTRL) && !strchr(other, key)) {
if (key >= 97 && key <= 122)
key -= 96;
else if (key >= 64 && key <= 95)
@@ -193,7 +194,7 @@ key_string_lookup_key(int key)
{
static char out[24];
char tmp[8];
- u_int i;
+ u_int i;
*out = '\0';
diff --git a/layout-custom.c b/layout-custom.c
index c076232f..e32d9d9d 100644
--- a/layout-custom.c
+++ b/layout-custom.c
@@ -63,7 +63,7 @@ layout_dump(struct window *w)
if (layout_append(w->layout_root, layout, sizeof layout) != 0)
return (NULL);
- xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
+ xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);
return (out);
}
@@ -206,11 +206,11 @@ layout_construct(struct layout_cell *lcparent, const char **layout)
{
struct layout_cell *lc, *lcchild;
u_int sx, sy, xoff, yoff;
+ const char *saved;
if (!isdigit((u_char) **layout))
return (NULL);
- if (sscanf(*layout, "%ux%u,%u,%u,%*u", &sx, &sy, &xoff, &yoff) != 4 &&
- sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
+ if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
return (NULL);
while (isdigit((u_char) **layout))
@@ -231,9 +231,12 @@ layout_construct(struct layout_cell *lcparent, const char **layout)
while (isdigit((u_char) **layout))
(*layout)++;
if (**layout == ',') {
+ saved = *layout;
(*layout)++;
while (isdigit((u_char) **layout))
(*layout)++;
+ if (**layout == 'x')
+ *layout = saved;
}
lc = layout_create_cell(lcparent);
diff --git a/layout.c b/layout.c
index 397d90e5..b74bd789 100644
--- a/layout.c
+++ b/layout.c
@@ -374,13 +374,13 @@ layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot)
}
void
-layout_init(struct window *w)
+layout_init(struct window *w, struct window_pane *wp)
{
struct layout_cell *lc;
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, w->sx, w->sy, 0, 0);
- layout_make_leaf(lc, TAILQ_FIRST(&w->panes));
+ layout_make_leaf(lc, wp);
layout_fix_panes(w, w->sx, w->sy);
}
@@ -443,6 +443,39 @@ layout_resize(struct window *w, u_int sx, u_int sy)
layout_fix_panes(w, sx, sy);
}
+/* Resize a pane to an absolute size. */
+void
+layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
+ u_int new_size)
+{
+ struct layout_cell *lc, *lcparent;
+ int change, size;
+
+ lc = wp->layout_cell;
+
+ /* Find next parent of the same type. */
+ lcparent = lc->parent;
+ while (lcparent != NULL && lcparent->type != type) {
+ lc = lcparent;
+ lcparent = lc->parent;
+ }
+ if (lcparent == NULL)
+ return;
+
+ /* Work out the size adjustment. */
+ if (type == LAYOUT_LEFTRIGHT)
+ size = lc->sx;
+ else
+ size = lc->sy;
+ if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
+ change = size - new_size;
+ else
+ change = new_size - size;
+
+ /* Resize the pane. */
+ layout_resize_pane(wp, type, change);
+}
+
/* Resize a single pane within the layout. */
void
layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
@@ -486,6 +519,7 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
notify_window_layout_changed(wp->window);
}
+/* Resize pane based on mouse events. */
void
layout_resize_pane_mouse(struct client *c)
{
@@ -534,6 +568,7 @@ layout_resize_pane_mouse(struct client *c)
m->flags &= ~MOUSE_RESIZE_PANE;
}
+/* Helper function to grow pane. */
int
layout_resize_pane_grow(
struct layout_cell *lc, enum layout_type type, int needed)
@@ -574,6 +609,7 @@ layout_resize_pane_grow(
return (size);
}
+/* Helper function to shrink pane. */
int
layout_resize_pane_shrink(
struct layout_cell *lc, enum layout_type type, int needed)
diff --git a/mode-key.c b/mode-key.c
index 7dea26d8..94115ebb 100644
--- a/mode-key.c
+++ b/mode-key.c
@@ -99,6 +99,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_BOTTOMLINE, "bottom-line" },
{ MODEKEYCOPY_CANCEL, "cancel" },
{ MODEKEYCOPY_CLEARSELECTION, "clear-selection" },
+ { MODEKEYCOPY_COPYPIPE, "copy-pipe" },
{ MODEKEYCOPY_COPYLINE, "copy-line" },
{ MODEKEYCOPY_COPYENDOFLINE, "copy-end-of-line" },
{ MODEKEYCOPY_COPYSELECTION, "copy-selection" },
@@ -413,7 +414,6 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE },
{ '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION },
{ '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL },
- { 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
{ 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'f', 0, MODEKEYCOPY_JUMP },
{ 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND },
@@ -514,6 +514,7 @@ mode_key_init_trees(void)
mbind->key = ment->key;
mbind->mode = ment->mode;
mbind->cmd = ment->cmd;
+ mbind->arg = NULL;
RB_INSERT(mode_key_tree, mtab->tree, mbind);
}
}
@@ -527,7 +528,7 @@ mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
}
enum mode_key_cmd
-mode_key_lookup(struct mode_key_data *mdata, int key)
+mode_key_lookup(struct mode_key_data *mdata, int key, const char **arg)
{
struct mode_key_binding *mbind, mtmp;
@@ -547,6 +548,8 @@ mode_key_lookup(struct mode_key_data *mdata, int key)
mdata->mode = 1 - mdata->mode;
/* FALLTHROUGH */
default:
+ if (arg != NULL)
+ *arg = mbind->arg;
return (mbind->cmd);
}
}
diff --git a/names.c b/names.c
index 72f1ad17..bcb6aafe 100644
--- a/names.c
+++ b/names.c
@@ -26,8 +26,8 @@
#include "tmux.h"
-void window_name_callback(unused int, unused short, void *);
-char *parse_window_name(const char *);
+void window_name_callback(int, short, void *);
+char *parse_window_name(struct window *, const char *);
void
queue_window_name(struct window *w)
@@ -43,7 +43,6 @@ queue_window_name(struct window *w)
evtimer_add(&w->name_timer, &tv);
}
-/* ARGSUSED */
void
window_name_callback(unused int fd, unused short events, void *data)
{
@@ -74,9 +73,9 @@ window_name_callback(unused int fd, unused short events, void *data)
*/
if (w->active->cmd != NULL && *w->active->cmd == '\0' &&
name != NULL && name[0] == '-' && name[1] != '\0')
- wname = parse_window_name(name + 1);
+ wname = parse_window_name(w, name + 1);
else
- wname = parse_window_name(name);
+ wname = parse_window_name(w, name);
free(name);
}
@@ -99,18 +98,22 @@ default_window_name(struct window *w)
if (w->active->screen != &w->active->base)
return (xstrdup("[tmux]"));
if (w->active->cmd != NULL && *w->active->cmd != '\0')
- return (parse_window_name(w->active->cmd));
- return (parse_window_name(w->active->shell));
+ return (parse_window_name(w, w->active->cmd));
+ return (parse_window_name(w, w->active->shell));
}
char *
-parse_window_name(const char *in)
+parse_window_name(struct window *w, const char *in)
{
- char *copy, *name, *ptr;
+ char *copy, *name, *ptr, *prefix;
+ size_t prefixlen;
+
+ prefix = options_get_string(&w->options, "command-prefix");
+ prefixlen = strlen(prefix);
name = copy = xstrdup(in);
- if (strncmp(name, "exec ", (sizeof "exec ") - 1) == 0)
- name = name + (sizeof "exec ") - 1;
+ if (strncmp(name, prefix, prefixlen) == 0)
+ name = name + prefixlen;
while (*name == ' ')
name++;
diff --git a/options-table.c b/options-table.c
index 83ec97f2..e5f6c777 100644
--- a/options-table.c
+++ b/options-table.c
@@ -476,7 +476,6 @@ const struct options_table_entry window_options_table[] = {
.default_num = 1
},
-
{ .name = "c0-change-trigger",
.type = OPTIONS_TABLE_NUMBER,
.default_num = 250,
@@ -502,6 +501,11 @@ const struct options_table_entry window_options_table[] = {
.default_num = 1
},
+ { .name = "command-prefix",
+ .type = OPTIONS_TABLE_STRING,
+ .default_str = "exec "
+ },
+
{ .name = "force-height",
.type = OPTIONS_TABLE_NUMBER,
.minimum = 0,
@@ -745,8 +749,8 @@ options_table_populate_tree(
/* Print an option using its type from the table. */
const char *
-options_table_print_entry(
- const struct options_table_entry *oe, struct options_entry *o)
+options_table_print_entry(const struct options_table_entry *oe,
+ struct options_entry *o, int no_quotes)
{
static char out[BUFSIZ];
const char *s;
@@ -754,13 +758,17 @@ options_table_print_entry(
*out = '\0';
switch (oe->type) {
case OPTIONS_TABLE_STRING:
- xsnprintf(out, sizeof out, "\"%s\"", o->str);
+ if (no_quotes)
+ xsnprintf(out, sizeof out, "%s", o->str);
+ else
+ xsnprintf(out, sizeof out, "\"%s\"", o->str);
break;
case OPTIONS_TABLE_NUMBER:
xsnprintf(out, sizeof out, "%lld", o->num);
break;
case OPTIONS_TABLE_KEY:
- xsnprintf(out, sizeof out, "%s", key_string_lookup_key(o->num));
+ xsnprintf(out, sizeof out, "%s",
+ key_string_lookup_key(o->num));
break;
case OPTIONS_TABLE_COLOUR:
s = colour_tostring(o->num);
diff --git a/resize.c b/resize.c
index 317110e3..5c365dfe 100644
--- a/resize.c
+++ b/resize.c
@@ -49,10 +49,12 @@ recalculate_sizes(void)
struct client *c;
struct window *w;
struct window_pane *wp;
- u_int i, j, ssx, ssy, has, limit;
- int flag;
+ u_int i, j, ssx, ssy, has, limit;
+ int flag, has_status, is_zoomed;
RB_FOREACH(s, sessions, &sessions) {
+ has_status = options_get_number(&s->options, "status");
+
ssx = ssy = UINT_MAX;
for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
c = ARRAY_ITEM(&clients, j);
@@ -61,7 +63,11 @@ recalculate_sizes(void)
if (c->session == s) {
if (c->tty.sx < ssx)
ssx = c->tty.sx;
- if (c->tty.sy < ssy)
+ if (has_status &&
+ !(c->flags & CLIENT_CONTROL) &&
+ c->tty.sy > 1 && c->tty.sy - 1 < ssy)
+ ssy = c->tty.sy - 1;
+ else if (c->tty.sy < ssy)
ssy = c->tty.sy;
}
}
@@ -71,17 +77,14 @@ recalculate_sizes(void)
}
s->flags &= ~SESSION_UNATTACHED;
- if (options_get_number(&s->options, "status")) {
- if (ssy == 0)
- ssy = 1;
- else
- ssy--;
- }
+ if (has_status && ssy == 0)
+ ssy = 1;
+
if (s->sx == ssx && s->sy == ssy)
continue;
- log_debug(
- "session size %u,%u (was %u,%u)", ssx, ssy, s->sx, s->sy);
+ log_debug("session size %u,%u (was %u,%u)", ssx, ssy, s->sx,
+ s->sy);
s->sx = ssx;
s->sy = ssy;
@@ -120,12 +123,16 @@ recalculate_sizes(void)
if (w->sx == ssx && w->sy == ssy)
continue;
+ log_debug("window size %u,%u (was %u,%u)", ssx, ssy, w->sx,
+ w->sy);
- log_debug(
- "window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy);
-
+ is_zoomed = w->flags & WINDOW_ZOOMED;
+ if (is_zoomed)
+ window_unzoom(w);
layout_resize(w, ssx, ssy);
window_resize(w, ssx, ssy);
+ if (is_zoomed && window_pane_visible(w->active))
+ window_zoom(w->active);
/*
* If the current pane is now not visible, move to the next
diff --git a/screen-redraw.c b/screen-redraw.c
index 899f741b..a7bf81ff 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -24,7 +24,11 @@
int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
int screen_redraw_cell_border(struct client *, u_int, u_int);
-int screen_redraw_check_cell(struct client *, u_int, u_int);
+int screen_redraw_check_cell(struct client *, u_int, u_int,
+ struct window_pane **);
+int screen_redraw_check_active(u_int, u_int, int, struct window *,
+ struct window_pane *);
+
void screen_redraw_draw_number(struct client *, struct window_pane *);
#define CELL_INSIDE 0
@@ -93,7 +97,8 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
/* Check if cell inside a pane. */
int
-screen_redraw_check_cell(struct client *c, u_int px, u_int py)
+screen_redraw_check_cell(struct client *c, u_int px, u_int py,
+ struct window_pane **wpp)
{
struct window *w = c->session->curw->window;
struct window_pane *wp;
@@ -105,6 +110,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py)
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
+ *wpp = wp;
/* If outside the pane and its border, skip it. */
if ((wp->xoff != 0 && px < wp->xoff - 1) ||
@@ -162,9 +168,52 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py)
}
}
+ *wpp = NULL;
return (CELL_OUTSIDE);
}
+/* Check active pane indicator. */
+int
+screen_redraw_check_active(u_int px, u_int py, int type, struct window *w,
+ struct window_pane *wp)
+{
+ /* Is this off the active pane border? */
+ if (screen_redraw_cell_border1(w->active, px, py) != 1)
+ return (0);
+
+ /* If there are more than two panes, that's enough. */
+ if (window_count_panes(w) != 2)
+ return (1);
+
+ /* Else if the cell is not a border cell, forget it. */
+ if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE))
+ return (1);
+
+ /* Check if the pane covers the whole width. */
+ if (wp->xoff == 0 && wp->sx == w->sx) {
+ /* This can either be the top pane or the bottom pane. */
+ if (wp->yoff == 0) { /* top pane */
+ if (wp == w->active)
+ return (px <= wp->sx / 2);
+ return (px > wp->sx / 2);
+ }
+ return (0);
+ }
+
+ /* Check if the pane covers the whole height. */
+ if (wp->yoff == 0 && wp->sy == w->sy) {
+ /* This can either be the left pane or the right pane. */
+ if (wp->xoff == 0) { /* left pane */
+ if (wp == w->active)
+ return (py <= wp->sy / 2);
+ return (py > wp->sy / 2);
+ }
+ return (0);
+ }
+
+ return (type);
+}
+
/* Redraw entire screen. */
void
screen_redraw_screen(struct client *c, int status_only, int borders_only)
@@ -223,10 +272,10 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
break;
}
for (i = 0; i < tty->sx; i++) {
- type = screen_redraw_check_cell(c, i, j);
+ type = screen_redraw_check_cell(c, i, j, &wp);
if (type == CELL_INSIDE)
continue;
- if (screen_redraw_cell_border1(w->active, i, j) == 1)
+ if (screen_redraw_check_active(i, j, type, w, wp))
tty_attributes(tty, &active_gc);
else
tty_attributes(tty, &other_gc);
@@ -273,6 +322,9 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
{
u_int i, yoff;
+ if (!window_pane_visible(wp))
+ return;
+
yoff = wp->yoff;
if (status_at_line(c) == 0)
yoff++;
diff --git a/screen-write.c b/screen-write.c
index 04d2b385..3e836938 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -41,7 +41,6 @@ screen_write_start(
}
/* Finish writing. */
-/* ARGSUSED */
void
screen_write_stop(unused struct screen_write_ctx *ctx)
{
@@ -52,14 +51,13 @@ screen_write_stop(unused struct screen_write_ctx *ctx)
void
screen_write_reset(struct screen_write_ctx *ctx)
{
- screen_reset_tabs(ctx->s);
+ struct screen *s = ctx->s;
- screen_write_scrollregion(ctx, 0, screen_size_y(ctx->s) - 1);
+ screen_reset_tabs(s);
+ screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
- screen_write_insertmode(ctx, 0);
- screen_write_kcursormode(ctx, 0);
- screen_write_kkeypadmode(ctx, 0);
- screen_write_mousemode_off(ctx);
+ s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD);
+ s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
screen_write_clearscreen(ctx);
screen_write_cursormove(ctx, 0, 0);
@@ -454,6 +452,24 @@ screen_write_initctx(
memcpy(&ttyctx->last_cell, gc, sizeof ttyctx->last_cell);
}
+/* Set a mode. */
+void
+screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
+{
+ struct screen *s = ctx->s;
+
+ s->mode |= mode;
+}
+
+/* Clear a mode. */
+void
+screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
+{
+ struct screen *s = ctx->s;
+
+ s->mode &= ~mode;
+}
+
/* Cursor up by ny. */
void
screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
@@ -805,18 +821,6 @@ screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
s->cy = py;
}
-/* Set cursor mode. */
-void
-screen_write_cursormode(struct screen_write_ctx *ctx, int state)
-{
- struct screen *s = ctx->s;
-
- if (state)
- s->mode |= MODE_CURSOR;
- else
- s->mode &= ~MODE_CURSOR;
-}
-
/* Reverse index (up with scroll). */
void
screen_write_reverseindex(struct screen_write_ctx *ctx)
@@ -856,61 +860,6 @@ screen_write_scrollregion(
s->rlower = rlower;
}
-/* Set insert mode. */
-void
-screen_write_insertmode(struct screen_write_ctx *ctx, int state)
-{
- struct screen *s = ctx->s;
-
- if (state)
- s->mode |= MODE_INSERT;
- else
- s->mode &= ~MODE_INSERT;
-}
-
-/* Set UTF-8 mouse mode. */
-void
-screen_write_utf8mousemode(struct screen_write_ctx *ctx, int state)
-{
- struct screen *s = ctx->s;
-
- if (state)
- s->mode |= MODE_MOUSE_UTF8;
- else
- s->mode &= ~MODE_MOUSE_UTF8;
-}
-
-/* Set mouse mode off. */
-void
-screen_write_mousemode_off(struct screen_write_ctx *ctx)
-{
- struct screen *s = ctx->s;
-
- s->mode &= ~ALL_MOUSE_MODES;
-}
-
-/* Set mouse mode on. */
-void
-screen_write_mousemode_on(struct screen_write_ctx *ctx, int mode)
-{
- struct screen *s = ctx->s;
-
- s->mode &= ~ALL_MOUSE_MODES;
- s->mode |= mode;
-}
-
-/* Set bracketed paste mode. */
-void
-screen_write_bracketpaste(struct screen_write_ctx *ctx, int state)
-{
- struct screen *s = ctx->s;
-
- if (state)
- s->mode |= MODE_BRACKETPASTE;
- else
- s->mode &= ~MODE_BRACKETPASTE;
-}
-
/* Line feed. */
void
screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
@@ -945,30 +894,6 @@ screen_write_carriagereturn(struct screen_write_ctx *ctx)
s->cx = 0;
}
-/* Set keypad cursor keys mode. */
-void
-screen_write_kcursormode(struct screen_write_ctx *ctx, int state)
-{
- struct screen *s = ctx->s;
-
- if (state)
- s->mode |= MODE_KCURSOR;
- else
- s->mode &= ~MODE_KCURSOR;
-}
-
-/* Set keypad number keys mode. */
-void
-screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state)
-{
- struct screen *s = ctx->s;
-
- if (state)
- s->mode |= MODE_KKEYPAD;
- else
- s->mode &= ~MODE_KKEYPAD;
-}
-
/* Clear to end of screen from cursor. */
void
screen_write_clearendofscreen(struct screen_write_ctx *ctx)
@@ -1054,10 +979,10 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
struct screen *s = ctx->s;
struct grid *gd = s->grid;
struct tty_ctx ttyctx;
- u_int width, xx;
+ u_int width, xx, last;
struct grid_cell tmp_gc, *tmp_gcp;
struct utf8_data ud;
- int insert = 0;
+ int insert;
/* Ignore padding. */
if (gc->flags & GRID_FLAG_PADDING)
@@ -1095,7 +1020,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
xx = screen_size_x(s) - s->cx - width;
grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
insert = 1;
- }
+ } else
+ insert = 0;
/* Check this will fit on the current line and wrap if not. */
if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) {
@@ -1103,9 +1029,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
s->cx = 0; /* carriage return */
}
- /* Sanity checks. */
- if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width)
- || s->cy > screen_size_y(s) - 1)
+ /* Sanity check cursor position. */
+ if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1)
return;
/* Handle overwriting of UTF-8 characters. */
@@ -1124,8 +1049,15 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
/* Set the cell. */
grid_view_set_cell(gd, s->cx, s->cy, gc);
- /* Move the cursor. */
- s->cx += width;
+ /*
+ * Move the cursor. If not wrapping, stick at the last character and
+ * replace it.
+ */
+ last = !(s->mode & MODE_WRAP);
+ if (s->cx <= screen_size_x(s) - last - width)
+ s->cx += width;
+ else
+ s->cx = screen_size_x(s) - last;
/* Draw to the screen if necessary. */
if (insert) {
diff --git a/screen.c b/screen.c
index fe0b7389..e92c6aa7 100644
--- a/screen.c
+++ b/screen.c
@@ -363,15 +363,10 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
/* Reflow wrapped lines. */
void
-screen_reflow(struct screen *s, u_int sx)
+screen_reflow(struct screen *s, u_int new_x)
{
- struct grid *old, *new;
+ struct grid *old = s->grid;
- old = s->grid;
- new = grid_create(old->sx, old->sy, old->hlimit);
-
- s->cy -= grid_reflow(new, old, sx);
- s->grid = new;
-
- grid_destroy(old);
+ s->grid = grid_create(old->sx, old->sy, old->hlimit);
+ s->cy -= grid_reflow(s->grid, old, new_x);
}
diff --git a/server-client.c b/server-client.c
index 796390f7..377f9ae9 100644
--- a/server-client.c
+++ b/server-client.c
@@ -17,9 +17,11 @@
*/
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <event.h>
#include <fcntl.h>
+#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -27,6 +29,8 @@
#include "tmux.h"
+void server_client_check_focus(struct window_pane *);
+void server_client_check_resize(struct window_pane *);
void server_client_check_mouse(struct client *, struct window_pane *);
void server_client_repeat_timer(int, short, void *);
void server_client_check_exit(struct client *);
@@ -41,10 +45,6 @@ void server_client_msg_identify(
struct client *, struct msg_identify_data *, int);
void server_client_msg_shell(struct client *);
-void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...);
-void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...);
-void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...);
-
/* Create a new client. */
void
server_client_create(int fd)
@@ -63,6 +63,9 @@ server_client_create(int fd)
fatal("gettimeofday failed");
memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
+ c->cmdq = cmdq_new(c);
+ c->cmdq->client_exit = 1;
+
c->stdin_data = evbuffer_new ();
c->stdout_data = evbuffer_new ();
c->stderr_data = evbuffer_new ();
@@ -93,6 +96,8 @@ server_client_create(int fd)
c->tty.mouse.event = MOUSE_EVENT_UP;
c->tty.mouse.flags = 0;
+ c->flags |= CLIENT_FOCUSED;
+
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -149,7 +154,8 @@ server_client_lost(struct client *c)
evbuffer_free (c->stdin_data);
evbuffer_free (c->stdout_data);
- evbuffer_free (c->stderr_data);
+ if (c->stderr_data != c->stdout_data)
+ evbuffer_free (c->stderr_data);
status_free_jobs(&c->status_new);
status_free_jobs(&c->status_old);
@@ -175,6 +181,10 @@ server_client_lost(struct client *c)
free(c->prompt_buffer);
free(c->cwd);
+ c->cmdq->dead = 1;
+ cmdq_free(c->cmdq);
+ c->cmdq = NULL;
+
environ_free(&c->environ);
close(c->ibuf.fd);
@@ -355,6 +365,7 @@ server_client_handle_key(struct client *c, int key)
/* Check the client is good to accept input. */
if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
return;
+
if (c->session == NULL)
return;
s = c->session;
@@ -374,6 +385,7 @@ server_client_handle_key(struct client *c, int key)
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
if (c->flags & CLIENT_READONLY)
return;
+ window_unzoom(w);
wp = window_pane_at_index(w, key - '0');
if (wp != NULL && window_pane_visible(wp))
window_set_active_pane(w, wp);
@@ -417,6 +429,7 @@ server_client_handle_key(struct client *c, int key)
if (!(c->flags & CLIENT_PREFIX)) {
if (isprefix) {
c->flags |= CLIENT_PREFIX;
+ server_status_client(c);
return;
}
@@ -431,6 +444,7 @@ server_client_handle_key(struct client *c, int key)
/* Prefix key already pressed. Reset prefix and lookup key. */
c->flags &= ~CLIENT_PREFIX;
+ server_status_client(c);
if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
/* If repeating, treat this as a key, else ignore. */
if (c->flags & CLIENT_REPEAT) {
@@ -491,7 +505,7 @@ server_client_loop(void)
/*
* Any windows will have been redrawn as part of clients, so clear
- * their flags now.
+ * their flags now. Also check pane focus and resize.
*/
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
w = ARRAY_ITEM(&windows, i);
@@ -499,9 +513,90 @@ server_client_loop(void)
continue;
w->flags &= ~WINDOW_REDRAW;
- TAILQ_FOREACH(wp, &w->panes, entry)
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ server_client_check_focus(wp);
+ server_client_check_resize(wp);
wp->flags &= ~PANE_REDRAW;
+ }
+ }
+}
+
+/* Check if pane should be resized. */
+void
+server_client_check_resize(struct window_pane *wp)
+{
+ struct winsize ws;
+
+ if (wp->fd == -1 || !(wp->flags & PANE_RESIZE))
+ return;
+
+ memset(&ws, 0, sizeof ws);
+ ws.ws_col = wp->sx;
+ ws.ws_row = wp->sy;
+
+ if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) {
+#ifdef __sun
+ /*
+ * Some versions of Solaris apparently can return an error when
+ * resizing; don't know why this happens, can't reproduce on
+ * other platforms and ignoring it doesn't seem to cause any
+ * issues.
+ */
+ if (errno != EINVAL)
+#endif
+ fatal("ioctl failed");
+ }
+
+ wp->flags &= ~PANE_RESIZE;
+}
+
+/* Check whether pane should be focused. */
+void
+server_client_check_focus(struct window_pane *wp)
+{
+ u_int i;
+ struct client *c;
+
+ /* If we don't care about focus, forget it. */
+ if (!(wp->base.mode & MODE_FOCUSON))
+ return;
+
+ /* If we're not the active pane in our window, we're not focused. */
+ if (wp->window->active != wp)
+ goto not_focused;
+
+ /* If we're in a mode, we're not focused. */
+ if (wp->screen != &wp->base)
+ goto not_focused;
+
+ /*
+ * If our window is the current window in any focused clients with an
+ * attached session, we're focused.
+ */
+ for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
+ c = ARRAY_ITEM(&clients, i);
+ if (c == NULL || c->session == NULL)
+ continue;
+
+ if (!(c->flags & CLIENT_FOCUSED))
+ continue;
+ if (c->session->flags & SESSION_UNATTACHED)
+ continue;
+
+ if (c->session->curw->window == wp->window)
+ goto focused;
}
+
+not_focused:
+ if (wp->flags & PANE_FOCUSED)
+ bufferevent_write(wp->event, "\033[O", 3);
+ wp->flags &= ~PANE_FOCUSED;
+ return;
+
+focused:
+ if (!(wp->flags & PANE_FOCUSED))
+ bufferevent_write(wp->event, "\033[I", 3);
+ wp->flags |= PANE_FOCUSED;
}
/*
@@ -526,6 +621,9 @@ server_client_reset_state(struct client *c)
if (c->flags & CLIENT_SUSPENDED)
return;
+ if (c->flags & CLIENT_CONTROL)
+ return;
+
tty_region(&c->tty, 0, c->tty.sy - 1);
status = options_get_number(oo, "status");
@@ -580,14 +678,16 @@ server_client_reset_state(struct client *c)
}
/* Repeat time callback. */
-/* ARGSUSED */
void
server_client_repeat_timer(unused int fd, unused short events, void *data)
{
struct client *c = data;
- if (c->flags & CLIENT_REPEAT)
+ if (c->flags & CLIENT_REPEAT) {
+ if (c->flags & CLIENT_PREFIX)
+ server_status_client(c);
c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
+ }
}
/* Check if client should be exited. */
@@ -620,7 +720,7 @@ server_client_check_redraw(struct client *c)
struct window_pane *wp;
int flags, redraw;
- if (c->flags & CLIENT_SUSPENDED)
+ if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
flags = c->tty.flags & TTY_FREEZE;
@@ -750,6 +850,8 @@ server_client_msg_dispatch(struct client *c)
if (datalen != 0)
fatalx("bad MSG_RESIZE size");
+ if (c->flags & CLIENT_CONTROL)
+ break;
if (tty_resize(&c->tty)) {
recalculate_sizes();
server_redraw_client(c);
@@ -804,74 +906,18 @@ server_client_msg_dispatch(struct client *c)
}
}
-/* Callback to send error message to client. */
-void printflike2
-server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- evbuffer_add_vprintf(ctx->cmdclient->stderr_data, fmt, ap);
- va_end(ap);
-
- evbuffer_add(ctx->cmdclient->stderr_data, "\n", 1);
- server_push_stderr(ctx->cmdclient);
- ctx->cmdclient->retcode = 1;
-}
-
-/* Callback to send print message to client. */
-void printflike2
-server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap);
- va_end(ap);
-
- evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1);
- server_push_stdout(ctx->cmdclient);
-}
-
-/* Callback to send print message to client, if not quiet. */
-void printflike2
-server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
-{
- va_list ap;
-
- if (options_get_number(&global_options, "quiet"))
- return;
-
- va_start(ap, fmt);
- evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap);
- va_end(ap);
-
- evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1);
- server_push_stdout(ctx->cmdclient);
-}
-
/* Handle command message. */
void
server_client_msg_command(struct client *c, struct msg_command_data *data)
{
- struct cmd_ctx ctx;
struct cmd_list *cmdlist = NULL;
int argc;
char **argv, *cause;
- ctx.error = server_client_msg_error;
- ctx.print = server_client_msg_print;
- ctx.info = server_client_msg_info;
-
- ctx.msgdata = data;
- ctx.curclient = NULL;
-
- ctx.cmdclient = c;
-
argc = data->argc;
data->argv[(sizeof data->argv) - 1] = '\0';
if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) {
- server_client_msg_error(&ctx, "command too long");
+ cmdq_error(c->cmdq, "command too long");
goto error;
}
@@ -881,29 +927,21 @@ server_client_msg_command(struct client *c, struct msg_command_data *data)
*argv = xstrdup("new-session");
}
- if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
- server_client_msg_error(&ctx, "%s", cause);
+ 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);
- switch (cmd_list_exec(cmdlist, &ctx))
- {
- case CMD_RETURN_ERROR:
- case CMD_RETURN_NORMAL:
- c->flags |= CLIENT_EXIT;
- break;
- case CMD_RETURN_ATTACH:
- case CMD_RETURN_YIELD:
- break;
- }
+ cmdq_run(c->cmdq, cmdlist);
cmd_list_free(cmdlist);
return;
error:
if (cmdlist != NULL)
cmd_list_free(cmdlist);
+
c->flags |= CLIENT_EXIT;
}
@@ -919,7 +957,11 @@ server_client_msg_identify(
if (data->flags & IDENTIFY_CONTROL) {
c->stdin_callback = control_callback;
- c->flags |= (CLIENT_CONTROL|CLIENT_SUSPENDED);
+ evbuffer_free(c->stderr_data);
+ c->stderr_data = c->stdout_data;
+ c->flags |= CLIENT_CONTROL;
+ if (data->flags & IDENTIFY_TERMIOS)
+ evbuffer_add_printf(c->stdout_data, "\033P1000p");
server_write_client(c, MSG_STDIN, NULL, 0);
c->tty.fd = -1;
@@ -944,7 +986,8 @@ server_client_msg_identify(
tty_resize(&c->tty);
- c->flags |= CLIENT_TERMINAL;
+ if (!(data->flags & IDENTIFY_CONTROL))
+ c->flags |= CLIENT_TERMINAL;
}
/* Handle shell message. */
diff --git a/server-fn.c b/server-fn.c
index b21d94a1..566925f0 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -39,7 +39,7 @@ server_fill_environ(struct session *s, struct environ *env)
term = options_get_string(&s->options, "default-terminal");
environ_set(env, "TERM", term);
- idx = s->idx;
+ idx = s->id;
} else
idx = -1;
pid = getpid();
@@ -194,7 +194,7 @@ server_status_window(struct window *w)
/*
* This is slightly different. We want to redraw the status line of any
- * clients containing this window rather than any where it is the
+ * clients containing this window rather than anywhere it is the
* current window.
*/
@@ -239,6 +239,9 @@ server_lock_client(struct client *c)
size_t cmdlen;
struct msg_lock_data lockdata;
+ if (c->flags & CLIENT_CONTROL)
+ return;
+
if (c->flags & CLIENT_SUSPENDED)
return;
@@ -374,6 +377,7 @@ server_destroy_pane(struct window_pane *wp)
return;
}
+ server_unzoom_window(w);
layout_close_pane(wp);
window_remove_pane(w, wp);
@@ -491,7 +495,6 @@ server_clear_identify(struct client *c)
}
}
-/* ARGSUSED */
void
server_callback_identify(unused int fd, unused short events, void *data)
{
@@ -543,6 +546,10 @@ server_push_stderr(struct client *c)
struct msg_stderr_data data;
size_t size;
+ if (c->stderr_data == c->stdout_data) {
+ server_push_stdout(c);
+ return;
+ }
size = EVBUFFER_LENGTH(c->stderr_data);
if (size == 0)
return;
@@ -561,7 +568,7 @@ int
server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int,
void *), void *cb_data, char **cause)
{
- if (c == NULL) {
+ if (c == NULL || c->session != NULL) {
*cause = xstrdup("no client with stdin");
return (-1);
}
@@ -586,3 +593,11 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int,
return (0);
}
+
+void
+server_unzoom_window(struct window *w)
+{
+ window_unzoom(w);
+ server_redraw_window(w);
+ server_status_window(w);
+}
diff --git a/server-window.c b/server-window.c
index fce6439b..4f5a5504 100644
--- a/server-window.c
+++ b/server-window.c
@@ -85,7 +85,7 @@ server_window_check_bell(struct session *s, struct winlink *wl)
return (0);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (c == NULL || c->session != s)
+ if (c == NULL || c->session != s || (c->flags & CLIENT_CONTROL))
continue;
if (!visual) {
tty_bell(&c->tty);
@@ -242,7 +242,7 @@ ring_bell(struct session *s)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
- if (c != NULL && c->session == s)
+ if (c != NULL && c->session == s && !(c->flags & CLIENT_CONTROL))
tty_bell(&c->tty);
}
}
diff --git a/server.c b/server.c
index b5139b4f..4bfa9185 100644
--- a/server.c
+++ b/server.c
@@ -105,8 +105,9 @@ server_create_socket(void)
int
server_start(int lockfd, char *lockfile)
{
- int pair[2];
- struct timeval tv;
+ int pair[2];
+ struct timeval tv;
+ char *cause;
/* The first client is special and gets a socketpair; create it. */
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
@@ -163,23 +164,28 @@ server_start(int lockfd, char *lockfile)
free(lockfile);
close(lockfd);
- if (access(SYSTEM_CFG, R_OK) == 0)
- load_cfg(SYSTEM_CFG, NULL, &cfg_causes);
- else if (errno != ENOENT) {
- cfg_add_cause(
- &cfg_causes, "%s: %s", SYSTEM_CFG, strerror(errno));
- }
- if (cfg_file != NULL)
- load_cfg(cfg_file, NULL, &cfg_causes);
-
- /*
- * If there is a session already, put the current window and pane into
- * more mode.
- */
- if (!RB_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes))
- show_cfg_causes(RB_MIN(sessions, &sessions));
+ cfg_cmd_q = cmdq_new(NULL);
+ cfg_cmd_q->emptyfn = cfg_default_done;
+ cfg_finished = 0;
+ cfg_references = 1;
+ ARRAY_INIT(&cfg_causes);
- cfg_finished = 1;
+ if (access(SYSTEM_CFG, R_OK) == 0) {
+ if (load_cfg(SYSTEM_CFG, cfg_cmd_q, &cause) == -1) {
+ xasprintf(&cause, "%s: %s", SYSTEM_CFG, cause);
+ ARRAY_ADD(&cfg_causes, cause);
+ }
+ } else if (errno != ENOENT) {
+ xasprintf(&cause, "%s: %s", SYSTEM_CFG, strerror(errno));
+ ARRAY_ADD(&cfg_causes, cause);
+ }
+ if (cfg_file != NULL) {
+ if (load_cfg(cfg_file, cfg_cmd_q, &cause) == -1) {
+ xasprintf(&cause, "%s: %s", cfg_file, cause);
+ ARRAY_ADD(&cfg_causes, cause);
+ }
+ }
+ cmdq_continue(cfg_cmd_q);
server_add_accept(0);
@@ -317,7 +323,6 @@ server_update_socket(void)
}
/* Callback for server socket. */
-/* ARGSUSED */
void
server_accept_callback(int fd, short events, unused void *data)
{
@@ -371,7 +376,6 @@ server_add_accept(int timeout)
}
/* Signal handler. */
-/* ARGSUSED */
void
server_signal_callback(int sig, unused short events, unused void *data)
{
@@ -467,7 +471,6 @@ server_child_stopped(pid_t pid, int status)
}
/* Handle once-per-second timer events. */
-/* ARGSUSED */
void
server_second_callback(unused int fd, unused short events, unused void *arg)
{
diff --git a/session.c b/session.c
index 1f4fb30c..74eb06a5 100644
--- a/session.c
+++ b/session.c
@@ -29,7 +29,7 @@
/* Global session list. */
struct sessions sessions;
struct sessions dead_sessions;
-u_int next_session;
+u_int next_session_id;
struct session_groups session_groups;
struct winlink *session_next_alert(struct winlink *);
@@ -69,14 +69,14 @@ session_find(const char *name)
return (RB_FIND(sessions, &sessions, &s));
}
-/* Find session by index. */
+/* Find session by id. */
struct session *
-session_find_by_index(u_int idx)
+session_find_by_id(u_int id)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions) {
- if (s->idx == idx)
+ if (s->id == id)
return (s);
}
return (NULL);
@@ -120,13 +120,13 @@ session_create(const char *name, const char *cmd, const char *cwd,
if (name != NULL) {
s->name = xstrdup(name);
- s->idx = next_session++;
+ s->id = next_session_id++;
} else {
s->name = NULL;
do {
- s->idx = next_session++;
+ s->id = next_session_id++;
free (s->name);
- xasprintf(&s->name, "%u", s->idx);
+ xasprintf(&s->name, "%u", s->id);
} while (RB_FIND(sessions, &sessions, s) != NULL);
}
RB_INSERT(sessions, &sessions, s);
@@ -345,13 +345,7 @@ session_next(struct session *s, int alert)
if (alert && ((wl = session_next_alert(wl)) == NULL))
return (-1);
}
- if (wl == s->curw)
- return (1);
- winlink_stack_remove(&s->lastw, wl);
- winlink_stack_push(&s->lastw, s->curw);
- s->curw = wl;
- winlink_clear_flags(wl);
- return (0);
+ return (session_set_current(s, wl));
}
struct winlink *
@@ -382,13 +376,7 @@ session_previous(struct session *s, int alert)
if (alert && (wl = session_previous_alert(wl)) == NULL)
return (-1);
}
- if (wl == s->curw)
- return (1);
- winlink_stack_remove(&s->lastw, wl);
- winlink_stack_push(&s->lastw, s->curw);
- s->curw = wl;
- winlink_clear_flags(wl);
- return (0);
+ return (session_set_current(s, wl));
}
/* Move session to specific window. */
@@ -398,15 +386,7 @@ session_select(struct session *s, int idx)
struct winlink *wl;
wl = winlink_find_by_index(&s->windows, idx);
- if (wl == NULL)
- return (-1);
- if (wl == s->curw)
- return (1);
- winlink_stack_remove(&s->lastw, wl);
- winlink_stack_push(&s->lastw, s->curw);
- s->curw = wl;
- winlink_clear_flags(wl);
- return (0);
+ return (session_set_current(s, wl));
}
/* Move session to last used window. */
@@ -421,6 +401,18 @@ session_last(struct session *s)
if (wl == s->curw)
return (1);
+ return (session_set_current(s, wl));
+}
+
+/* Set current winlink to wl .*/
+int
+session_set_current(struct session *s, struct winlink *wl)
+{
+ if (wl == NULL)
+ return (-1);
+ if (wl == s->curw)
+ return (1);
+
winlink_stack_remove(&s->lastw, wl);
winlink_stack_push(&s->lastw, s->curw);
s->curw = wl;
diff --git a/status.c b/status.c
index 88ab68d1..f120c38a 100644
--- a/status.c
+++ b/status.c
@@ -393,13 +393,6 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl,
long limit;
u_int idx;
- if (s == NULL)
- s = c->session;
- if (wl == NULL)
- wl = s->curw;
- if (wp == NULL)
- wp = wl->window->active;
-
errno = 0;
limit = strtol(*iptr, &endptr, 10);
if ((limit == 0 && errno != EINVAL) ||
@@ -444,8 +437,7 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl,
case 'P':
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
- xsnprintf(
- tmp, sizeof tmp, "%u", idx);
+ xsnprintf(tmp, sizeof tmp, "%u", idx);
ptr = tmp;
goto do_replace;
case 'S':
@@ -468,6 +460,9 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl,
*/
ch = ']';
goto skip_to;
+ case '{':
+ ptr = (char *) "#{";
+ goto do_replace;
case '#':
*(*optr)++ = '#';
break;
@@ -507,13 +502,21 @@ char *
status_replace(struct client *c, struct session *s, struct winlink *wl,
struct window_pane *wp, const char *fmt, time_t t, int jobsflag)
{
- static char out[BUFSIZ];
- char in[BUFSIZ], ch, *iptr, *optr;
- size_t len;
+ static char out[BUFSIZ];
+ char in[BUFSIZ], ch, *iptr, *optr, *expanded;
+ size_t len;
+ struct format_tree *ft;
if (fmt == NULL)
return (xstrdup(""));
+ if (s == NULL)
+ s = c->session;
+ if (wl == NULL)
+ wl = s->curw;
+ if (wp == NULL)
+ wp = wl->window->active;
+
len = strftime(in, sizeof in, fmt, localtime(&t));
in[len] = '\0';
@@ -534,7 +537,14 @@ status_replace(struct client *c, struct session *s, struct winlink *wl,
}
*optr = '\0';
- return (xstrdup(out));
+ ft = format_create();
+ format_client(ft, c);
+ format_session(ft, s);
+ format_winlink(ft, s, wl);
+ format_window_pane(ft, wp);
+ expanded = format_expand(ft, out);
+ format_free(ft);
+ return (expanded);
}
/* Figure out job name and get its result, starting it off if necessary. */
@@ -584,7 +594,7 @@ status_find_job(struct client *c, char **iptr)
/* If not found at all, start the job and add to the tree. */
if (so == NULL) {
- job_run(cmd, status_job_callback, status_job_free, c);
+ job_run(cmd, NULL, status_job_callback, status_job_free, c);
c->references++;
so = xmalloc(sizeof *so);
@@ -666,7 +676,7 @@ status_job_callback(struct job *job)
memcpy(buf, EVBUFFER_DATA(job->event->input), len);
buf[len] = '\0';
} else
- buf = xstrdup(line);
+ buf = line;
so->out = buf;
server_status_client(c);
@@ -819,7 +829,6 @@ status_message_clear(struct client *c)
}
/* Clear status line message after timer expires. */
-/* ARGSUSED */
void
status_message_callback(unused int fd, unused short event, void *data)
{
@@ -1033,7 +1042,7 @@ status_prompt_key(struct client *c, int key)
size_t size, n, off, idx;
size = strlen(c->prompt_buffer);
- switch (mode_key_lookup(&c->prompt_mdata, key)) {
+ switch (mode_key_lookup(&c->prompt_mdata, key, NULL)) {
case MODEKEYEDIT_CURSORLEFT:
if (c->prompt_index > 0) {
c->prompt_index--;
diff --git a/tmux.1 b/tmux.1
index 3e85be76..a639476f 100644
--- a/tmux.1
+++ b/tmux.1
@@ -23,7 +23,7 @@
.Sh SYNOPSIS
.Nm tmux
.Bk -words
-.Op Fl 28lquvV
+.Op Fl 28lCquv
.Op Fl c Ar shell-command
.Op Fl f Ar file
.Op Fl L Ar socket-name
@@ -102,6 +102,11 @@ to assume the terminal supports 256 colours.
Like
.Fl 2 ,
but indicates that the terminal supports 88 colours.
+.It Fl C
+Start in control mode.
+Given twice
+.Xo ( Fl CC ) Xc
+disables echo.
.It Fl c Ar shell-command
Execute
.Ar shell-command
@@ -369,9 +374,9 @@ Clients may be listed with the
command.
.Pp
.Ar target-session
-is either the name of a session (as listed by the
+is the session id prefixed with a $, the name of a session (as listed by the
.Ic list-sessions
-command) or the name of a client with the same syntax as
+command), or the name of a client with the same syntax as
.Ar target-client ,
in which case the session attached to the client is used.
When looking for the session name,
@@ -670,7 +675,8 @@ command.
Lock all clients attached to
.Ar target-session .
.It Xo Ic new-session
-.Op Fl d
+.Op Fl AdDP
+.Op Fl F Ar format
.Op Fl n Ar window-name
.Op Fl s Ar session-name
.Op Fl t Ar target-session
@@ -701,6 +707,21 @@ If run from a terminal, any
.Xr termios 4
special characters are saved and used for new windows in the new session.
.Pp
+The
+.Fl A
+flag makes
+.Ic new-session
+behave like
+.Ic attach-session
+if
+.Ar session-name
+already exists; in the case,
+.Fl D
+behaves like
+.Fl d
+to
+.Ic attach-session .
+.Pp
If
.Fl t
is given, the new session is
@@ -720,6 +741,14 @@ or
are invalid if
.Fl t
is used.
+.Pp
+The
+.Fl P
+option prints information about the new session after it has been created.
+By default, it uses the format
+.Ql #{session_name}:
+but a different format may be specified with
+.Fl F .
.It Xo Ic refresh-client
.Op Fl S
.Op Fl t Ar target-client
@@ -854,7 +883,7 @@ The following keys are supported as appropriate for the mode:
.It Li "Start of line" Ta "0" Ta "C-a"
.It Li "Start selection" Ta "Space" Ta "C-Space"
.It Li "Top of history" Ta "g" Ta "M->"
-.It Li "Transpose chars" Ta "" Ta "C-t"
+.It Li "Transpose characters" Ta "" Ta "C-t"
.El
.Pp
The next and previous word keys use space and the
@@ -916,6 +945,17 @@ command and keys modified or removed with
.Ic bind-key
and
.Ic unbind-key .
+One command accepts an argument,
+.Ic copy-pipe ,
+which copies the selection and pipes it to a command.
+For example the following will bind
+.Ql C-q
+to copy the selection into
+.Pa /tmp
+as well as the paste buffer:
+.Bd -literal -offset indent
+bind-key -temacs-copy C-q copy-pipe "cat >/tmp/out"
+.Ed
.Pp
The paste buffer key pastes the first line from the top paste buffer on the
stack.
@@ -1040,14 +1080,36 @@ By default, it uses the format
but a different format may be specified with
.Fl F .
.It Xo Ic capture-pane
+.Op Fl aepPq
.Op Fl b Ar buffer-index
.Op Fl E Ar end-line
.Op Fl S Ar start-line
.Op Fl t Ar target-pane
.Xc
.D1 (alias: Ic capturep )
-Capture the contents of a pane to the specified buffer, or a new buffer if none
-is specified.
+Capture the contents of a pane.
+If
+.Fl p
+is given, the output goes to stdout, otherwise to the buffer specified with
+.Fl b
+or a new buffer if omitted.
+If
+.Fl a
+is given, the alternate screen is used, and the history is not accessible.
+If no alternate screen exists, an error will be returned unless
+.Fl q
+is given.
+If
+.Fl e
+is given, the output includes escape sequences for text and background
+attributes.
+.Fl C
+also escapes non-printable characters as octal \exxx.
+.Fl J
+joins wrapped lines and preserves trailing spaces at each line's end.
+.Fl P
+captures only any output that the pane has received that is the beginning of an
+as-yet incomplete escape sequence.
.Pp
.Fl S
and
@@ -1078,8 +1140,7 @@ For the meaning of the
flag, see the
.Sx FORMATS
section.
-This command works only from inside
-.Nm .
+This command works only if at least one client is attached.
.It Xo
.Ic choose-list
.Op Fl l Ar items
@@ -1105,8 +1166,7 @@ also accepts format specifiers.
For the meaning of this see the
.Sx FORMATS
section.
-This command works only from inside
-.Nm .
+This command works only if at least one client is attached.
.It Xo
.Ic choose-session
.Op Fl F Ar format
@@ -1128,13 +1188,10 @@ For the meaning of the
flag, see the
.Sx FORMATS
section.
-This command works only from inside
-.Nm .
+This command works only if at least one client is attached.
.It Xo
.Ic choose-tree
-.Op Fl s
-.Op Fl w
-.Op Fl u
+.Op Fl suw
.Op Fl b Ar session-template
.Op Fl c Ar window-template
.Op Fl S Ar format
@@ -1159,25 +1216,30 @@ is given, will show sessions.
If
.Fl w
is given, will show windows.
-If
+.Pp
+By default, the tree is collapsed and sessions must be expanded to windows
+with the right arrow key.
+The
.Fl u
-is given, the tree is uncollapsed by default.
+option will start with all sessions expanded instead.
+.Pp
If
.Fl b
is given, will override the default session command.
Note that
.Ql %%
-can be used, and will be replaced with the session name.
+can be used and will be replaced with the session name.
The default option if not specified is "switch-client -t '%%'".
If
.Fl c
is given, will override the default window command.
-Note that
+Like
+.Fl b ,
.Ql %%
-can be used, and will be replaced with the session name and window index.
-This command will run
-.Ar session-template
-before it.
+can be used and will be replaced with the session name and window index.
+When a window is chosen from the list, the session command is run before the
+window command.
+.Pp
If
.Fl S
is given will display the specified format instead of the default session
@@ -1193,8 +1255,8 @@ and
options, see the
.Sx FORMATS
section.
-This command only works from inside
-.Nm .
+.Pp
+This command works only if at least one client is attached.
.It Xo
.Ic choose-window
.Op Fl F Ar format
@@ -1216,8 +1278,7 @@ For the meaning of the
flag, see the
.Sx FORMATS
section.
-This command works only from inside
-.Nm .
+This command works only if at least one client is attached.
.It Ic display-panes Op Fl t Ar target-client
.D1 (alias: Ic displayp)
Display a visible indicator of each pane shown by
@@ -1261,8 +1322,7 @@ For the meaning of the
flag, see the
.Sx FORMATS
section.
-This command only works from inside
-.Nm .
+This command works only if at least one client is attached.
.It Xo Ic join-pane
.Op Fl bdhv
.Oo Fl l
@@ -1419,9 +1479,9 @@ option.
.It Xo Ic new-window
.Op Fl adkP
.Op Fl c Ar start-directory
+.Op Fl F Ar format
.Op Fl n Ar window-name
.Op Fl t Ar target-window
-.Op Fl F Ar format
.Op Ar shell-command
.Xc
.D1 (alias: Ic neww )
@@ -1549,22 +1609,35 @@ Rename the current window, or the window at
if specified, to
.Ar new-name .
.It Xo Ic resize-pane
-.Op Fl DLRU
+.Op Fl DLRUZ
.Op Fl t Ar target-pane
+.Op Fl x Ar width
+.Op Fl y Ar height
.Op Ar adjustment
.Xc
.D1 (alias: Ic resizep )
-Resize a pane, upward with
-.Fl U
-(the default), downward with
+Resize a pane, up, down, left or right by
+.Ar adjustment
+with
+.Fl U ,
.Fl D ,
-to the left with
.Fl L
-and to the right with
-.Fl R .
+or
+.Fl R ,
+or
+to an absolute size
+with
+.Fl x
+or
+.Fl y .
The
.Ar adjustment
is given in lines or cells (the default is 1).
+.Pp
+With
+.Fl Z ,
+the active pane is toggled between zoomed (occupying the whole of the window)
+and unzoomed (its normal position in the layout).
.It Xo Ic respawn-pane
.Op Fl k
.Op Fl t Ar target-pane
@@ -1949,10 +2022,23 @@ All window options are documented with the
.Ic set-window-option
command.
.Pp
+.Nm
+also supports user options which are prefixed with a
+.Ql \&@ .
+User options may have any name, so long as they are prefixed with
+.Ql \&@ ,
+and be set to any string.
+For example
+.Bd -literal -offset indent
+$ tmux setw -q @foo "abc123"
+$ tmux showw -v @foo
+abc123
+.Ed
+.Pp
Commands which set options are as follows:
.Bl -tag -width Ds
.It Xo Ic set-option
-.Op Fl agqsuw
+.Op Fl agoqsuw
.Op Fl t Ar target-session | Ar target-window
.Ar option Ar value
.Xc
@@ -1981,6 +2067,10 @@ options.
It is not possible to unset a global option.
.Pp
The
+.Fl o
+flag prevents setting an option that is already set.
+.Pp
+The
.Fl q
flag suppresses the informational message (as if the
.Ic quiet
@@ -2664,6 +2754,13 @@ Set clock colour.
.Xc
Set clock hour format.
.Pp
+.It Ic command-prefix Ar string
+String prefixed to commands (apart from a plain shell as set by the
+.Ic default-shell
+option).
+The default is
+.Ql "exec\ " .
+.Pp
.It Ic force-height Ar height
.It Ic force-width Ar width
Prevent
@@ -2875,7 +2972,7 @@ If this option is set, searches will wrap around the end of the pane contents.
The default is on.
.El
.It Xo Ic show-options
-.Op Fl gsw
+.Op Fl gqsvw
.Op Fl t Ar target-session | Ar target-window
.Op Ar option
.Xc
@@ -2891,8 +2988,15 @@ otherwise the session options for
Global session or window options are listed if
.Fl g
is used.
+.Fl v
+shows only the option value, not the name.
+If
+.Fl q
+is set, no error will be returned if
+.Ar option
+is unset.
.It Xo Ic show-window-options
-.Op Fl g
+.Op Fl gv
.Op Fl t Ar target-window
.Op Ar option
.Xc
@@ -2902,6 +3006,8 @@ List the window options or a single option for
or the global window options if
.Fl g
is used.
+.Fl v
+shows only the option value, not the name.
.El
.Sh FORMATS
Certain commands accept the
@@ -2937,6 +3043,9 @@ if it is unattached.
The following variables are available, where appropriate:
.Bl -column "session_created_string" "Replaced with" -offset indent
.It Sy "Variable name" Ta Sy "Replaced with"
+.It Li "alternate_on" Ta "If pane is in alternate screen"
+.It Li "alternate_saved_x" Ta "Saved cursor X in alternate screen"
+.It Li "alternate_saved_y" Ta "Saved cursor Y in alternate screen"
.It Li "buffer_sample" Ta "First 50 characters from the specified buffer"
.It Li "buffer_size" Ta "Size of the specified buffer in bytes"
.It Li "client_activity" Ta "Integer time client last had activity"
@@ -2945,34 +3054,55 @@ The following variables are available, where appropriate:
.It Li "client_created_string" Ta "String time client created"
.It Li "client_cwd" Ta "Working directory of client"
.It Li "client_height" Ta "Height of client"
+.It Li "client_last_session" Ta "Name of the client's last session"
+.It Li "client_prefix" Ta "1 if prefix key has been pressed"
.It Li "client_readonly" Ta "1 if client is readonly"
+.It Li "client_session" Ta "Name of the client's session"
.It Li "client_termname" Ta "Terminal name of client"
.It Li "client_tty" Ta "Pseudo terminal of client"
.It Li "client_utf8" Ta "1 if client supports utf8"
.It Li "client_width" Ta "Width of client"
-.It Li "host" Ta "Hostname of local host"
+.It Li "cursor_flag" Ta "Pane cursor flag"
+.It Li "cursor_x" Ta "Cursor X position in pane"
+.It Li "cursor_y" Ta "Cursor Y position in pane"
.It Li "history_bytes" Ta "Number of bytes in window history"
.It Li "history_limit" Ta "Maximum window history lines"
.It Li "history_size" Ta "Size of history in bytes"
+.It Li "host" Ta "Hostname of local host"
+.It Li "insert_flag" Ta "Pane insert flag"
+.It Li "keypad_cursor_flag" Ta "Pane keypad cursor flag"
+.It Li "keypad_flag" Ta "Pane keypad flag"
.It Li "line" Ta "Line number in the list"
+.It Li "mouse_any_flag" Ta "Pane mouse any flag"
+.It Li "mouse_button_flag" Ta "Pane mouse button flag"
+.It Li "mouse_standard_flag" Ta "Pane mouse standard flag"
+.It Li "mouse_utf8_flag" Ta "Pane mouse UTF-8 flag"
.It Li "pane_active" Ta "1 if active pane"
+.It Li "pane_current_command" Ta "Current command if available"
.It Li "pane_current_path" Ta "Current path if available"
.It Li "pane_dead" Ta "1 if pane is dead"
.It Li "pane_height" Ta "Height of pane"
.It Li "pane_id" Ta "Unique pane ID"
+.It Li "pane_in_mode" Ta "If pane is in a mode"
.It Li "pane_index" Ta "Index of pane"
.It Li "pane_pid" Ta "PID of first process in pane"
.It Li "pane_start_command" Ta "Command pane started with"
.It Li "pane_start_path" Ta "Path pane started with"
+.It Li "pane_tabs" Ta "Pane tab positions"
.It Li "pane_title" Ta "Title of pane"
.It Li "pane_tty" Ta "Pseudo terminal of pane"
.It Li "pane_width" Ta "Width of pane"
+.It Li "saved_cursor_x" Ta "Saved cursor X in pane"
+.It Li "saved_cursor_y" Ta "Saved cursor Y in pane"
+.It Li "scroll_region_lower" Ta "Bottom of scroll region in pane"
+.It Li "scroll_region_upper" Ta "Top of scroll region in pane"
.It Li "session_attached" Ta "1 if session attached"
.It Li "session_created" Ta "Integer time session created"
.It Li "session_created_string" Ta "String time session created"
.It Li "session_group" Ta "Number of session group"
.It Li "session_grouped" Ta "1 if session in a group"
.It Li "session_height" Ta "Height of session"
+.It Li "session_id" Ta "Unique session ID"
.It Li "session_name" Ta "Name of session"
.It Li "session_width" Ta "Width of session"
.It Li "session_windows" Ta "Number of windows in session"
@@ -2986,6 +3116,7 @@ The following variables are available, where appropriate:
.It Li "window_name" Ta "Name of window"
.It Li "window_panes" Ta "Number of panes in window"
.It Li "window_width" Ta "Width of window"
+.It Li "wrap_flag" Ta "Pane wrap flag"
.El
.Sh NAMES AND TITLES
.Nm
@@ -3138,6 +3269,7 @@ The flag is one of the following symbols appended to the window name:
.It Li "!" Ta "A bell has occurred in the window."
.It Li "+" Ta "Window is monitored for content and it has appeared."
.It Li "~" Ta "The window has been silent for the monitor-silence interval."
+.It Li "Z" Ta "The window's active pane is zoomed."
.El
.Pp
The # symbol relates to the
@@ -3310,8 +3442,7 @@ For the meaning of the
flag, see the
.Sx FORMATS
section.
-This command works only from inside
-.Nm .
+This command works only if at least one client is attached.
.It Ic clear-history Op Fl t Ar target-pane
.D1 (alias: Ic clearhist )
Remove and free the history for the specified pane.
@@ -3390,7 +3521,12 @@ Miscellaneous commands are as follows:
.Bl -tag -width Ds
.It Ic clock-mode Op Fl t Ar target-pane
Display a large clock.
-.It Ic if-shell Ar shell-command command Op Ar command
+.It Xo Ic if-shell
+.Op Fl b
+.Op Fl t Ar target-pane
+.Ar shell-command command
+.Op Ar command
+.Xc
.D1 (alias: Ic if )
Execute the first
.Ar command
@@ -3399,12 +3535,21 @@ if
returns success or the second
.Ar command
otherwise.
+Before being executed, shell-command is expanded using the rules specified in the
+.Sx FORMATS
+section, including those relevant to
+.Ar target-pane .
+With
+.Fl b ,
+.Ar shell-command
+is run in the background.
.It Ic lock-server
.D1 (alias: Ic lock )
Lock each client individually by running the command specified by the
.Ic lock-command
option.
.It Xo Ic run-shell
+.Fl b
.Op Fl t Ar target-pane
.Ar shell-command
.Xc
@@ -3412,6 +3557,13 @@ option.
Execute
.Ar shell-command
in the background without creating a window.
+Before being executed, shell-command is expanded using the rules specified in
+the
+.Sx FORMATS
+section.
+With
+.Fl b ,
+the command is run in the background.
After it finishes, any output to stdout is displayed in copy mode (in the pane
specified by
.Fl t
@@ -3420,6 +3572,23 @@ If the command doesn't return success, the exit status is also displayed.
.It Ic server-info
.D1 (alias: Ic info )
Show server information and terminal details.
+.It Xo Ic wait-for
+.Fl LSU
+.Ar channel
+.Xc
+.D1 (alias: Ic wait )
+When used without options, prevents the client from exiting until woken using
+.Ic wait-for
+.Fl S
+with the same channel.
+When
+.Fl L
+is used, the channel is locked and any clients that try to lock the same
+channel are made to wait until the channel is unlocked with
+.Ic wait-for
+.Fl U .
+This command only works from outside
+.Nm .
.El
.Sh TERMINFO EXTENSIONS
.Nm
@@ -3459,6 +3628,91 @@ option above and the
.Xr xterm 1
man page.
.El
+.Sh CONTROL MODE
+.Nm
+offers a textual interface called
+.Em control mode .
+This allows applications to communicate with
+.Nm
+using a simple text-only protocol.
+.Pp
+In control mode, a client sends
+.Nm
+commands or command sequences terminated by newlines on standard input.
+Each command will produce one block of output on standard output.
+An output block consists of a
+.Em %begin
+line followed by the output (which may be empty).
+The output block ends with a
+.Em %end
+or
+.Em %error .
+.Em %begin
+and matching
+.Em %end
+or
+.Em %error
+have two arguments: an integer time (as seconds from epoch) and command number.
+For example:
+.Bd -literal -offset indent
+%begin 1363006971 2
+0: ksh* (1 panes) [80x24] [layout b25f,80x24,0,0,2] @2 (active)
+%end 1363006971 2
+.Ed
+.Pp
+In control mode,
+.Nm
+outputs notifications.
+A notification will never occur inside an output block.
+.Pp
+The following notifications are defined:
+.Bl -tag -width Ds
+.It Ic %exit Op Ar reason
+The
+.Nm
+client is exiting immediately, either because it is not attached to any session
+or an error occurred.
+If present,
+.Ar reason
+describes why the client exited.
+.It Ic %layout-change Ar window-id Ar window-layout
+The layout of a window with ID
+.Ar window-id
+changed.
+The new layout is
+.Ar window-layout .
+.It Ic %output Ar pane-id Ar value
+A window pane produced output.
+.Ar value
+escapes non-printable characters and backslash as octal \\xxx.
+.It Ic %session-changed Ar session-id Ar name
+The client is now attached to the session with ID
+.Ar session-id ,
+which is named
+.Ar name .
+.It Ic %session-renamed Ar name
+The current session was renamed to
+.Ar name .
+.It Ic %sessions-changed
+A session was created or destroyed.
+.It Ic %unlinked-window-add Ar window-id
+The window with ID
+.Ar window-id
+was created but is not linked to the current session.
+.It Ic %window-add Ar window-id
+The window with ID
+.Ar window-id
+was linked to the current session.
+.It Ic %window-close Ar window-id
+The window with ID
+.Ar window-id
+closed.
+.It Ic %window-renamed Ar window-id Ar name
+The window with ID
+.Ar window-id
+was renamed to
+.Ar name .
+.El
.Sh FILES
.Bl -tag -width "/etc/tmux.confXXX" -compact
.It Pa ~/.tmux.conf
diff --git a/tmux.c b/tmux.c
index 4b58abad..8ea91ebe 100644
--- a/tmux.c
+++ b/tmux.c
@@ -48,7 +48,7 @@ char socket_path[MAXPATHLEN];
int login_shell;
char *environ_path;
pid_t environ_pid = -1;
-int environ_idx = -1;
+int environ_session_id = -1;
__dead void usage(void);
void parseenvironment(void);
@@ -147,16 +147,16 @@ parseenvironment(void)
{
char *env, path[256];
long pid;
- int idx;
+ int id;
if ((env = getenv("TMUX")) == NULL)
return;
- if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &idx) != 3)
+ if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &id) != 3)
return;
environ_path = xstrdup(path);
environ_pid = pid;
- environ_idx = idx;
+ environ_session_id = id;
}
char *
@@ -336,8 +336,6 @@ main(int argc, char **argv)
options_init(&global_w_options, NULL);
options_table_populate_tree(window_options_table, &global_w_options);
- ARRAY_INIT(&cfg_causes);
-
/* Enable UTF-8 if the first client is on UTF-8 terminal. */
if (flags & IDENTIFY_UTF8) {
options_set_number(&global_s_options, "status-utf8", 1);
diff --git a/tmux.h b/tmux.h
index 1dd11ade..9c91d6a4 100644
--- a/tmux.h
+++ b/tmux.h
@@ -101,7 +101,7 @@ extern char **environ;
/* Default templates for choose-tree. */
#define CHOOSE_TREE_SESSION_TEMPLATE \
- "#{session_name}: #{session_windows} windows " \
+ "#{session_name}: #{session_windows} windows" \
"#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \
"#{?session_attached, (attached),}"
@@ -155,6 +155,7 @@ extern char **environ;
/* Default templates for break-pane, new-window and split-window. */
#define BREAK_PANE_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
+#define NEW_SESSION_TEMPLATE "#{session_name}:"
#define NEW_WINDOW_TEMPLATE BREAK_PANE_TEMPLATE
#define SPLIT_WINDOW_TEMPLATE BREAK_PANE_TEMPLATE
@@ -237,6 +238,9 @@ enum key_code {
KEYC_KP_ENTER,
KEYC_KP_ZERO,
KEYC_KP_PERIOD,
+
+ KEYC_FOCUS_IN,
+ KEYC_FOCUS_OUT,
};
/* Termcap codes. */
@@ -425,6 +429,9 @@ struct tty_term_code_entry {
const char *name;
};
+/* List of error causes. */
+ARRAY_DECL(causelist, char *);
+
/* Message codes. */
enum msgtype {
MSG_COMMAND,
@@ -456,8 +463,8 @@ enum msgtype {
* Don't forget to bump PROTOCOL_VERSION if any of these change!
*/
struct msg_command_data {
- pid_t pid; /* PID from $TMUX or -1 */
- int idx; /* index from $TMUX or -1 */
+ pid_t pid; /* from $TMUX or -1 */
+ int session_id; /* from $TMUX or -1 */
int argc;
char argv[COMMAND_LENGTH];
@@ -562,6 +569,7 @@ enum mode_key_cmd {
MODEKEYCOPY_BOTTOMLINE,
MODEKEYCOPY_CANCEL,
MODEKEYCOPY_CLEARSELECTION,
+ MODEKEYCOPY_COPYPIPE,
MODEKEYCOPY_COPYLINE,
MODEKEYCOPY_COPYENDOFLINE,
MODEKEYCOPY_COPYSELECTION,
@@ -628,12 +636,13 @@ struct mode_key_data {
/* Binding between a key and a command. */
struct mode_key_binding {
- int key;
+ int key;
- int mode;
- enum mode_key_cmd cmd;
+ int mode;
+ enum mode_key_cmd cmd;
+ const char *arg;
- RB_ENTRY(mode_key_binding) entry;
+ RB_ENTRY(mode_key_binding) entry;
};
RB_HEAD(mode_key_tree, mode_key_binding);
@@ -661,7 +670,9 @@ struct mode_key_table {
#define MODE_MOUSE_BUTTON 0x40
#define MODE_MOUSE_ANY 0x80
#define MODE_MOUSE_UTF8 0x100
-#define MODE_BRACKETPASTE 0x200
+#define MODE_MOUSE_SGR 0x200
+#define MODE_BRACKETPASTE 0x400
+#define MODE_FOCUSON 0x800
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ANY)
@@ -879,18 +890,24 @@ struct window_mode {
/* Structures for choose mode. */
struct window_choose_data {
- struct client *client;
- struct session *session; /* Session of current client. */
- struct session *tree_session; /* Session of items in tree. */
- struct format_tree *ft;
- struct winlink *wl;
- char *ft_template;
- char *command;
+ struct client *start_client;
+ struct session *start_session;
+
u_int idx;
int type;
+#define TREE_OTHER 0x0
#define TREE_WINDOW 0x1
#define TREE_SESSION 0x2
+
+ struct session *tree_session; /* session of items in tree */
+
+ struct winlink *wl;
int pane_id;
+
+ char *ft_template;
+ struct format_tree *ft;
+
+ char *command;
};
struct window_choose_mode_item {
@@ -906,7 +923,9 @@ struct window_pane {
u_int id;
struct window *window;
+
struct layout_cell *layout_cell;
+ struct layout_cell *saved_layout_cell;
u_int sx;
u_int sy;
@@ -917,6 +936,8 @@ struct window_pane {
int flags;
#define PANE_REDRAW 0x1
#define PANE_DROP 0x2
+#define PANE_FOCUSED 0x4
+#define PANE_RESIZE 0x8
char *cmd;
char *shell;
@@ -969,6 +990,7 @@ struct window {
int lastlayout;
struct layout_cell *layout_root;
+ struct layout_cell *saved_layout_root;
u_int sx;
u_int sy;
@@ -978,6 +1000,7 @@ struct window {
#define WINDOW_ACTIVITY 0x2
#define WINDOW_REDRAW 0x4
#define WINDOW_SILENCE 0x8
+#define WINDOW_ZOOMED 0x10
struct options options;
@@ -1061,7 +1084,7 @@ struct session_group {
TAILQ_HEAD(session_groups, session_group);
struct session {
- u_int idx;
+ u_int id;
char *name;
char *cwd;
@@ -1143,6 +1166,9 @@ LIST_HEAD(tty_terms, tty_term);
* - bits 3, 4 and 5 are for keys
* - bit 6 is set for dragging
* - bit 7 for buttons 4 and 5
+ *
+ * With the SGR 1006 extension the released button becomes known. Store these
+ * in separate fields and store the value converted to the old format in xb.
*/
struct mouse_event {
u_int xb;
@@ -1155,6 +1181,10 @@ struct mouse_event {
u_int ly;
u_int sy;
+ u_int sgr; /* whether the input arrived in SGR format */
+ u_int sgr_xb; /* only for SGR: the unmangled button */
+ u_int sgr_rel; /* only for SGR: if it is a release event */
+
u_int button;
u_int clicks;
@@ -1196,7 +1226,7 @@ struct tty {
#define TTY_NOCURSOR 0x1
#define TTY_FREEZE 0x2
-#define TTY_ESCAPE 0x4
+#define TTY_TIMER 0x4
#define TTY_UTF8 0x8
#define TTY_STARTED 0x10
#define TTY_OPENED 0x20
@@ -1297,6 +1327,7 @@ struct client {
#define CLIENT_READONLY 0x800
#define CLIENT_REDRAWWINDOW 0x1000
#define CLIENT_CONTROL 0x2000
+#define CLIENT_FOCUSED 0x4000
int flags;
struct event identify_timer;
@@ -1323,6 +1354,7 @@ struct client {
int wlmouse;
+ struct cmd_q *cmdq;
int references;
};
ARRAY_DECL(clients, struct client *);
@@ -1336,39 +1368,14 @@ struct args {
char **argv;
};
-/* Key/command line command. */
-struct cmd_ctx {
- /*
- * curclient is the client where this command was executed if inside
- * tmux. This is NULL if the command came from the command-line.
- *
- * cmdclient is the client which sent the MSG_COMMAND to the server, if
- * any. This is NULL unless the command came from the command-line.
- *
- * cmdclient and curclient may both be NULL if the command is in the
- * configuration file.
- */
- struct client *curclient;
- struct client *cmdclient;
-
- struct msg_command_data *msgdata;
-
- /* gcc2 doesn't understand attributes on function pointers... */
-#if defined(__GNUC__) && __GNUC__ >= 3
- void printflike2 (*print)(struct cmd_ctx *, const char *, ...);
- void printflike2 (*info)(struct cmd_ctx *, const char *, ...);
- void printflike2 (*error)(struct cmd_ctx *, const char *, ...);
-#else
- void (*print)(struct cmd_ctx *, const char *, ...);
- void (*info)(struct cmd_ctx *, const char *, ...);
- void (*error)(struct cmd_ctx *, const char *, ...);
-#endif
-};
-
+/* Command and list of commands. */
struct cmd {
const struct cmd_entry *entry;
struct args *args;
+ char *file;
+ u_int line;
+
TAILQ_ENTRY(cmd) qentry;
};
struct cmd_list {
@@ -1376,13 +1383,45 @@ struct cmd_list {
TAILQ_HEAD(, cmd) list;
};
+/* Command return values. */
enum cmd_retval {
CMD_RETURN_ERROR = -1,
CMD_RETURN_NORMAL = 0,
- CMD_RETURN_YIELD,
- CMD_RETURN_ATTACH
+ CMD_RETURN_WAIT,
+ CMD_RETURN_STOP
+};
+
+/* Command queue entry. */
+struct cmd_q_item {
+ struct cmd_list *cmdlist;
+ TAILQ_ENTRY(cmd_q_item) qentry;
+};
+TAILQ_HEAD(cmd_q_items, cmd_q_item);
+
+/* Command queue. */
+struct cmd_q {
+ int references;
+ int dead;
+
+ struct client *client;
+ int client_exit;
+
+ struct cmd_q_items queue;
+ struct cmd_q_item *item;
+ struct cmd *cmd;
+
+ time_t time;
+ u_int number;
+
+ void (*emptyfn)(struct cmd_q *);
+ void *data;
+
+ struct msg_command_data *msgdata;
+
+ TAILQ_ENTRY(cmd_q) waitentry;
};
+/* Command definition. */
struct cmd_entry {
const char *name;
const char *alias;
@@ -1401,7 +1440,7 @@ struct cmd_entry {
void (*key_binding)(struct cmd *, int);
int (*check)(struct args *);
- enum cmd_retval (*exec)(struct cmd *, struct cmd_ctx *);
+ enum cmd_retval (*exec)(struct cmd *, struct cmd_q *);
};
/* Key binding. */
@@ -1450,9 +1489,6 @@ struct format_entry {
};
RB_HEAD(format_tree, format_entry);
-/* List of configuration causes. */
-ARRAY_DECL(causelist, char *);
-
/* Common command usages. */
#define CMD_TARGET_PANE_USAGE "[-t target-pane]"
#define CMD_TARGET_WINDOW_USAGE "[-t target-window]"
@@ -1478,7 +1514,7 @@ extern char socket_path[MAXPATHLEN];
extern int login_shell;
extern char *environ_path;
extern pid_t environ_pid;
-extern int environ_idx;
+extern int environ_session_id;
void logfile(const char *);
const char *getshell(void);
int checkshell(const char *);
@@ -1488,12 +1524,13 @@ void setblocking(int, int);
__dead void shell_exec(const char *, const char *);
/* cfg.c */
-extern int cfg_finished;
-extern int cfg_references;
+extern struct cmd_q *cfg_cmd_q;
+extern int cfg_finished;
+extern int cfg_references;
extern struct causelist cfg_causes;
-void printflike2 cfg_add_cause(struct causelist *, const char *, ...);
-enum cmd_retval load_cfg(const char *, struct cmd_ctx *, struct causelist *);
-void show_cfg_causes(struct session *);
+int load_cfg(const char *, struct cmd_q *, char **);
+void cfg_default_done(struct cmd_q *);
+void cfg_show_causes(struct session *);
/* format.c */
int format_cmp(struct format_entry *, struct format_entry *);
@@ -1528,7 +1565,7 @@ enum mode_key_cmd mode_key_fromstring(const struct mode_key_cmdstr *,
const struct mode_key_table *mode_key_findtable(const char *);
void mode_key_init_trees(void);
void mode_key_init(struct mode_key_data *, struct mode_key_tree *);
-enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int);
+enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int, const char **);
/* notify.c */
void notify_enable(void);
@@ -1562,18 +1599,17 @@ long long options_get_number(struct options *, const char *);
extern const struct options_table_entry server_options_table[];
extern const struct options_table_entry session_options_table[];
extern const struct options_table_entry window_options_table[];
-void options_table_populate_tree(
- const struct options_table_entry *, struct options *);
-const char *options_table_print_entry(
- const struct options_table_entry *, struct options_entry *);
-int options_table_find(
- const char *, const struct options_table_entry **,
+void options_table_populate_tree(const struct options_table_entry *,
+ struct options *);
+const char *options_table_print_entry(const struct options_table_entry *,
+ struct options_entry *, int);
+int options_table_find(const char *, const struct options_table_entry **,
const struct options_table_entry **);
/* job.c */
extern struct joblist all_jobs;
-struct job *job_run(
- const char *, void (*)(struct job *), void (*)(void *), void *);
+struct job *job_run(const char *, struct session *,
+ void (*)(struct job *), void (*)(void *), void *);
void job_free(struct job *);
void job_died(struct job *, int);
@@ -1665,7 +1701,7 @@ int tty_term_flag(struct tty_term *, enum tty_code_code);
const char *tty_acs_get(struct tty *, u_char);
/* tty-keys.c */
-void tty_keys_init(struct tty *);
+void tty_keys_build(struct tty *);
void tty_keys_free(struct tty *);
int tty_keys_next(struct tty *);
@@ -1701,22 +1737,20 @@ int cmd_pack_argv(int, char **, char *, size_t);
int cmd_unpack_argv(char *, size_t, int, char ***);
char **cmd_copy_argv(int, char *const *);
void cmd_free_argv(int, char **);
-struct cmd *cmd_parse(int, char **, char **);
-enum cmd_retval cmd_exec(struct cmd *, struct cmd_ctx *);
-void cmd_free(struct cmd *);
+struct cmd *cmd_parse(int, char **, const char *, u_int, char **);
size_t cmd_print(struct cmd *, char *, size_t);
-struct session *cmd_current_session(struct cmd_ctx *, int);
-struct client *cmd_current_client(struct cmd_ctx *);
-struct client *cmd_find_client(struct cmd_ctx *, const char *);
-struct session *cmd_find_session(struct cmd_ctx *, const char *, int);
-struct winlink *cmd_find_window(
- struct cmd_ctx *, const char *, struct session **);
-int cmd_find_index(
- struct cmd_ctx *, const char *, struct session **);
-struct winlink *cmd_find_pane(struct cmd_ctx *,
- const char *, struct session **, struct window_pane **);
-char *cmd_template_replace(char *, const char *, int);
-const char *cmd_get_default_path(struct cmd_ctx *, const char *);
+struct session *cmd_current_session(struct cmd_q *, int);
+struct client *cmd_current_client(struct cmd_q *);
+struct client *cmd_find_client(struct cmd_q *, const char *, int);
+struct session *cmd_find_session(struct cmd_q *, const char *, int);
+struct winlink *cmd_find_window(struct cmd_q *, const char *,
+ struct session **);
+int cmd_find_index(struct cmd_q *, const char *,
+ struct session **);
+struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **,
+ struct window_pane **);
+char *cmd_template_replace(const char *, const char *, int);
+const char *cmd_get_default_path(struct cmd_q *, const char *);
extern const struct cmd_entry *cmd_table[];
extern const struct cmd_entry cmd_attach_session_entry;
extern const struct cmd_entry cmd_bind_key_entry;
@@ -1804,15 +1838,31 @@ extern const struct cmd_entry cmd_switch_client_entry;
extern const struct cmd_entry cmd_unbind_key_entry;
extern const struct cmd_entry cmd_unlink_window_entry;
extern const struct cmd_entry cmd_up_pane_entry;
+extern const struct cmd_entry cmd_wait_for_entry;
+
+/* cmd-attach-session.c */
+enum cmd_retval cmd_attach_session(struct cmd_q *, const char*, int, int);
/* cmd-list.c */
-struct cmd_list *cmd_list_parse(int, char **, char **);
-enum cmd_retval cmd_list_exec(struct cmd_list *, struct cmd_ctx *);
+struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **);
void cmd_list_free(struct cmd_list *);
size_t cmd_list_print(struct cmd_list *, char *, size_t);
+/* cmd-queue.c */
+struct cmd_q *cmdq_new(struct client *);
+int cmdq_free(struct cmd_q *);
+void printflike2 cmdq_print(struct cmd_q *, const char *, ...);
+void printflike2 cmdq_info(struct cmd_q *, const char *, ...);
+void printflike2 cmdq_error(struct cmd_q *, const char *, ...);
+int cmdq_guard(struct cmd_q *, const char *);
+void cmdq_run(struct cmd_q *, struct cmd_list *);
+void cmdq_append(struct cmd_q *, struct cmd_list *);
+int cmdq_continue(struct cmd_q *);
+void cmdq_flush(struct cmd_q *);
+
/* cmd-string.c */
-int cmd_string_parse(const char *, struct cmd_list **, char **);
+int cmd_string_parse(const char *, struct cmd_list **, const char *,
+ u_int, char **);
/* client.c */
int client_main(int, char **, int);
@@ -1827,9 +1877,6 @@ void key_bindings_remove(int);
void key_bindings_clean(void);
void key_bindings_init(void);
void key_bindings_dispatch(struct key_binding *, struct client *);
-void printflike2 key_bindings_error(struct cmd_ctx *, const char *, ...);
-void printflike2 key_bindings_print(struct cmd_ctx *, const char *, ...);
-void printflike2 key_bindings_info(struct cmd_ctx *, const char *, ...);
/* key-string.c */
int key_string_lookup_string(const char *);
@@ -1890,6 +1937,7 @@ void server_push_stdout(struct client *);
void server_push_stderr(struct client *);
int server_set_stdin_callback(struct client *, void (*)(struct client *,
int, void *), void *, char **);
+void server_unzoom_window(struct window *);
/* status.c */
int status_out_cmp(struct status_out *, struct status_out *);
@@ -1951,16 +1999,18 @@ void grid_scroll_history(struct grid *);
void grid_scroll_history_region(struct grid *, u_int, u_int);
void grid_expand_line(struct grid *, u_int, u_int);
const struct grid_cell *grid_peek_cell(struct grid *, u_int, u_int);
+const struct grid_line *grid_peek_line(struct grid *, u_int);
struct grid_cell *grid_get_cell(struct grid *, u_int, u_int);
void grid_set_cell(struct grid *, u_int, u_int, const struct grid_cell *);
void grid_clear(struct grid *, u_int, u_int, u_int, u_int);
void grid_clear_lines(struct grid *, u_int, u_int);
void grid_move_lines(struct grid *, u_int, u_int, u_int);
void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int);
-char *grid_string_cells(struct grid *, u_int, u_int, u_int);
+char *grid_string_cells(struct grid *, u_int, u_int, u_int,
+ struct grid_cell **, int, int, int);
void grid_duplicate_lines(
struct grid *, u_int, struct grid *, u_int, u_int);
-u_int grid_reflow(struct grid *, const struct grid *, u_int);
+u_int grid_reflow(struct grid *, struct grid *, u_int);
/* grid-cell.c */
u_int grid_cell_width(const struct grid_cell *);
@@ -2007,6 +2057,8 @@ void screen_write_putc(
void screen_write_copy(struct screen_write_ctx *,
struct screen *, u_int, u_int, u_int, u_int);
void screen_write_backspace(struct screen_write_ctx *);
+void screen_write_mode_set(struct screen_write_ctx *, int);
+void screen_write_mode_clear(struct screen_write_ctx *, int);
void screen_write_cursorup(struct screen_write_ctx *, u_int);
void screen_write_cursordown(struct screen_write_ctx *, u_int);
void screen_write_cursorright(struct screen_write_ctx *, u_int);
@@ -2021,18 +2073,11 @@ void screen_write_clearline(struct screen_write_ctx *);
void screen_write_clearendofline(struct screen_write_ctx *);
void screen_write_clearstartofline(struct screen_write_ctx *);
void screen_write_cursormove(struct screen_write_ctx *, u_int, u_int);
-void screen_write_cursormode(struct screen_write_ctx *, int);
void screen_write_reverseindex(struct screen_write_ctx *);
void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int);
-void screen_write_insertmode(struct screen_write_ctx *, int);
-void screen_write_utf8mousemode(struct screen_write_ctx *, int);
-void screen_write_mousemode_on(struct screen_write_ctx *, int);
-void screen_write_mousemode_off(struct screen_write_ctx *);
void screen_write_linefeed(struct screen_write_ctx *, int);
void screen_write_linefeedscreen(struct screen_write_ctx *, int);
void screen_write_carriagereturn(struct screen_write_ctx *);
-void screen_write_kcursormode(struct screen_write_ctx *, int);
-void screen_write_kkeypadmode(struct screen_write_ctx *, int);
void screen_write_clearendofscreen(struct screen_write_ctx *);
void screen_write_clearstartofscreen(struct screen_write_ctx *);
void screen_write_clearscreen(struct screen_write_ctx *);
@@ -2040,7 +2085,6 @@ void screen_write_clearhistory(struct screen_write_ctx *);
void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *);
void screen_write_setselection(struct screen_write_ctx *, u_char *, u_int);
void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int);
-void screen_write_bracketpaste(struct screen_write_ctx *, int);
/* screen-redraw.c */
void screen_redraw_screen(struct client *, int, int);
@@ -2097,6 +2141,8 @@ struct window_pane *window_find_string(struct window *, const char *);
void window_set_active_pane(struct window *, struct window_pane *);
struct window_pane *window_add_pane(struct window *, u_int);
void window_resize(struct window *, u_int, u_int);
+int window_zoom(struct window_pane *);
+int window_unzoom(struct window *);
void window_remove_pane(struct window *, struct window_pane *);
struct window_pane *window_pane_at_index(struct window *, u_int);
struct window_pane *window_pane_next_by_number(struct window *,
@@ -2153,12 +2199,14 @@ void layout_fix_panes(struct window *, u_int, u_int);
u_int layout_resize_check(struct layout_cell *, enum layout_type);
void layout_resize_adjust(
struct layout_cell *, enum layout_type, int);
-void layout_init(struct window *);
+void layout_init(struct window *, struct window_pane *);
void layout_free(struct window *);
void layout_resize(struct window *, u_int, u_int);
-void layout_resize_pane(
- struct window_pane *, enum layout_type, int);
-void layout_resize_pane_mouse(struct client *c);
+void layout_resize_pane(struct window_pane *, enum layout_type,
+ int);
+void layout_resize_pane_to(struct window_pane *, enum layout_type,
+ u_int);
+void layout_resize_pane_mouse(struct client *);
void layout_assign_pane(struct layout_cell *, struct window_pane *);
struct layout_cell *layout_split_pane(
struct window_pane *, enum layout_type, int, int);
@@ -2192,19 +2240,20 @@ extern const struct window_mode window_choose_mode;
void window_choose_add(struct window_pane *,
struct window_choose_data *);
void window_choose_ready(struct window_pane *,
- u_int, void (*)(struct window_choose_data *),
- void (*)(struct window_choose_data *));
-struct window_choose_data *window_choose_data_create(struct cmd_ctx *);
-void window_choose_ctx(struct window_choose_data *);
+ u_int, void (*)(struct window_choose_data *));
+struct window_choose_data *window_choose_data_create (int,
+ struct client *, struct session *);
+void window_choose_data_free(struct window_choose_data *);
+void window_choose_data_run(struct window_choose_data *);
struct window_choose_data *window_choose_add_window(struct window_pane *,
- struct cmd_ctx *, struct session *, struct winlink *,
- const char *, char *, u_int);
+ struct client *, struct session *, struct winlink *,
+ const char *, const char *, u_int);
struct window_choose_data *window_choose_add_session(struct window_pane *,
- struct cmd_ctx *, struct session *, const char *,
- char *, u_int);
+ struct client *, struct session *, const char *,
+ const char *, u_int);
struct window_choose_data *window_choose_add_item(struct window_pane *,
- struct cmd_ctx *, struct winlink *, const char *,
- char *, u_int);
+ struct client *, struct winlink *, const char *,
+ const char *, u_int);
void window_choose_expand_all(struct window_pane *);
/* names.c */
@@ -2240,7 +2289,7 @@ int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_alive(struct session *);
struct session *session_find(const char *);
-struct session *session_find_by_index(u_int);
+struct session *session_find_by_id(u_int);
struct session *session_create(const char *, const char *, const char *,
struct environ *, struct termios *, int, u_int, u_int,
char **);
@@ -2259,6 +2308,7 @@ int session_next(struct session *, int);
int session_previous(struct session *, int);
int session_select(struct session *, int);
int session_last(struct session *);
+int session_set_current(struct session *, struct winlink *);
struct session_group *session_group_find(struct session *);
u_int session_group_index(struct session_group *);
void session_group_add(struct session *, struct session *);
diff --git a/tty-keys.c b/tty-keys.c
index 681f31b6..d86d22cd 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -28,9 +28,9 @@
#include "tmux.h"
/*
- * Handle keys input from the outside terminal. tty_keys[] is a base table of
- * supported keys which are looked up in terminfo(5) and translated into a
- * ternary tree (a binary tree of binary trees).
+ * Handle keys input from the outside terminal. tty_default_*_keys[] are a base
+ * table of supported keys which are looked up in terminfo(5) and translated
+ * into a ternary tree.
*/
void tty_keys_add1(struct tty_key **, const char *, int);
@@ -43,249 +43,255 @@ void tty_keys_callback(int, short, void *);
int tty_keys_mouse(struct tty *, const char *, size_t, size_t *);
int tty_keys_device(struct tty *, const char *, size_t, size_t *);
-struct tty_key_ent {
- enum tty_code_code code;
+/* Default raw keys. */
+struct tty_default_key_raw {
const char *string;
-
int key;
- int flags;
-#define TTYKEY_RAW 0x1
};
-
-/*
- * Default key tables. Those flagged with TTYKEY_RAW are inserted directly,
- * otherwise they are looked up in terminfo(5).
- */
-const struct tty_key_ent tty_keys[] = {
+const struct tty_default_key_raw tty_default_raw_keys[] = {
/*
* Numeric keypad. Just use the vt100 escape sequences here and always
* put the terminal into keypad_xmit mode. Translation of numbers
* mode/applications mode is done in input-keys.c.
*/
- { 0, "\033Oo", KEYC_KP_SLASH, TTYKEY_RAW },
- { 0, "\033Oj", KEYC_KP_STAR, TTYKEY_RAW },
- { 0, "\033Om", KEYC_KP_MINUS, TTYKEY_RAW },
- { 0, "\033Ow", KEYC_KP_SEVEN, TTYKEY_RAW },
- { 0, "\033Ox", KEYC_KP_EIGHT, TTYKEY_RAW },
- { 0, "\033Oy", KEYC_KP_NINE, TTYKEY_RAW },
- { 0, "\033Ok", KEYC_KP_PLUS, TTYKEY_RAW },
- { 0, "\033Ot", KEYC_KP_FOUR, TTYKEY_RAW },
- { 0, "\033Ou", KEYC_KP_FIVE, TTYKEY_RAW },
- { 0, "\033Ov", KEYC_KP_SIX, TTYKEY_RAW },
- { 0, "\033Oq", KEYC_KP_ONE, TTYKEY_RAW },
- { 0, "\033Or", KEYC_KP_TWO, TTYKEY_RAW },
- { 0, "\033Os", KEYC_KP_THREE, TTYKEY_RAW },
- { 0, "\033OM", KEYC_KP_ENTER, TTYKEY_RAW },
- { 0, "\033Op", KEYC_KP_ZERO, TTYKEY_RAW },
- { 0, "\033On", KEYC_KP_PERIOD, TTYKEY_RAW },
+ { "\033Oo", KEYC_KP_SLASH },
+ { "\033Oj", KEYC_KP_STAR },
+ { "\033Om", KEYC_KP_MINUS },
+ { "\033Ow", KEYC_KP_SEVEN },
+ { "\033Ox", KEYC_KP_EIGHT },
+ { "\033Oy", KEYC_KP_NINE },
+ { "\033Ok", KEYC_KP_PLUS },
+ { "\033Ot", KEYC_KP_FOUR },
+ { "\033Ou", KEYC_KP_FIVE },
+ { "\033Ov", KEYC_KP_SIX },
+ { "\033Oq", KEYC_KP_ONE },
+ { "\033Or", KEYC_KP_TWO },
+ { "\033Os", KEYC_KP_THREE },
+ { "\033OM", KEYC_KP_ENTER },
+ { "\033Op", KEYC_KP_ZERO },
+ { "\033On", KEYC_KP_PERIOD },
/* Arrow keys. */
- { 0, "\033OA", KEYC_UP, TTYKEY_RAW },
- { 0, "\033OB", KEYC_DOWN, TTYKEY_RAW },
- { 0, "\033OC", KEYC_RIGHT, TTYKEY_RAW },
- { 0, "\033OD", KEYC_LEFT, TTYKEY_RAW },
+ { "\033OA", KEYC_UP },
+ { "\033OB", KEYC_DOWN },
+ { "\033OC", KEYC_RIGHT },
+ { "\033OD", KEYC_LEFT },
- { 0, "\033[A", KEYC_UP, TTYKEY_RAW },
- { 0, "\033[B", KEYC_DOWN, TTYKEY_RAW },
- { 0, "\033[C", KEYC_RIGHT, TTYKEY_RAW },
- { 0, "\033[D", KEYC_LEFT, TTYKEY_RAW },
+ { "\033[A", KEYC_UP },
+ { "\033[B", KEYC_DOWN },
+ { "\033[C", KEYC_RIGHT },
+ { "\033[D", KEYC_LEFT },
- /* rxvt-style arrow + modifier keys. */
- { 0, "\033Oa", KEYC_UP|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033Ob", KEYC_DOWN|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033Oc", KEYC_RIGHT|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033Od", KEYC_LEFT|KEYC_CTRL, TTYKEY_RAW },
+ /* Other (xterm) "cursor" keys. */
+ { "\033OH", KEYC_HOME },
+ { "\033OF", KEYC_END },
- { 0, "\033[a", KEYC_UP|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[b", KEYC_DOWN|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[c", KEYC_RIGHT|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[d", KEYC_LEFT|KEYC_SHIFT, TTYKEY_RAW },
+ { "\033[H", KEYC_HOME },
+ { "\033[F", KEYC_END },
- /*
- * rxvt-style function + modifier keys:
- * Ctrl = ^, Shift = $, Ctrl+Shift = @
- */
- { 0, "\033[11^", KEYC_F1|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[12^", KEYC_F2|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[13^", KEYC_F3|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[14^", KEYC_F4|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[15^", KEYC_F5|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[17^", KEYC_F6|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[18^", KEYC_F7|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[19^", KEYC_F8|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[20^", KEYC_F9|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[21^", KEYC_F10|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[23^", KEYC_F11|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[24^", KEYC_F12|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[25^", KEYC_F13|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[26^", KEYC_F14|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[28^", KEYC_F15|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[29^", KEYC_F16|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[31^", KEYC_F17|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[32^", KEYC_F18|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[33^", KEYC_F19|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[34^", KEYC_F20|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[2^", KEYC_IC|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[3^", KEYC_DC|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[7^", KEYC_HOME|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[8^", KEYC_END|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[6^", KEYC_NPAGE|KEYC_CTRL, TTYKEY_RAW },
- { 0, "\033[5^", KEYC_PPAGE|KEYC_CTRL, TTYKEY_RAW },
-
- { 0, "\033[11$", KEYC_F1|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[12$", KEYC_F2|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[13$", KEYC_F3|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[14$", KEYC_F4|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[15$", KEYC_F5|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[17$", KEYC_F6|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[18$", KEYC_F7|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[19$", KEYC_F8|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[20$", KEYC_F9|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[21$", KEYC_F10|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[23$", KEYC_F11|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[24$", KEYC_F12|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[25$", KEYC_F13|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[26$", KEYC_F14|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[28$", KEYC_F15|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[29$", KEYC_F16|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[31$", KEYC_F17|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[32$", KEYC_F18|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[33$", KEYC_F19|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[34$", KEYC_F20|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[2$", KEYC_IC|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[3$", KEYC_DC|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[7$", KEYC_HOME|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[8$", KEYC_END|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[6$", KEYC_NPAGE|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[5$", KEYC_PPAGE|KEYC_SHIFT, TTYKEY_RAW },
-
- { 0, "\033[11@", KEYC_F1|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[12@", KEYC_F2|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[13@", KEYC_F3|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[14@", KEYC_F4|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[15@", KEYC_F5|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[17@", KEYC_F6|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[18@", KEYC_F7|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[19@", KEYC_F8|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[20@", KEYC_F9|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[21@", KEYC_F10|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[23@", KEYC_F11|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[24@", KEYC_F12|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[25@", KEYC_F13|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[26@", KEYC_F14|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[28@", KEYC_F15|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[29@", KEYC_F16|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[31@", KEYC_F17|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[32@", KEYC_F18|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[33@", KEYC_F19|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[34@", KEYC_F20|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[2@", KEYC_IC|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[3@", KEYC_DC|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[7@", KEYC_HOME|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[8@", KEYC_END|KEYC_CTRL|KEYC_SHIFT, TTYKEY_RAW },
- { 0, "\033[6@", KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW },
- { 0, "\033[5@", KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT,TTYKEY_RAW },
-
- /* terminfo lookups below this line so they can override raw keys. */
+ /* rxvt-style arrow + modifier keys. */
+ { "\033Oa", KEYC_UP|KEYC_CTRL },
+ { "\033Ob", KEYC_DOWN|KEYC_CTRL },
+ { "\033Oc", KEYC_RIGHT|KEYC_CTRL },
+ { "\033Od", KEYC_LEFT|KEYC_CTRL },
+
+ { "\033[a", KEYC_UP|KEYC_SHIFT },
+ { "\033[b", KEYC_DOWN|KEYC_SHIFT },
+ { "\033[c", KEYC_RIGHT|KEYC_SHIFT },
+ { "\033[d", KEYC_LEFT|KEYC_SHIFT },
+
+ /* rxvt-style function + modifier keys (C = ^, S = $, C-S = @). */
+ { "\033[11^", KEYC_F1|KEYC_CTRL },
+ { "\033[12^", KEYC_F2|KEYC_CTRL },
+ { "\033[13^", KEYC_F3|KEYC_CTRL },
+ { "\033[14^", KEYC_F4|KEYC_CTRL },
+ { "\033[15^", KEYC_F5|KEYC_CTRL },
+ { "\033[17^", KEYC_F6|KEYC_CTRL },
+ { "\033[18^", KEYC_F7|KEYC_CTRL },
+ { "\033[19^", KEYC_F8|KEYC_CTRL },
+ { "\033[20^", KEYC_F9|KEYC_CTRL },
+ { "\033[21^", KEYC_F10|KEYC_CTRL },
+ { "\033[23^", KEYC_F11|KEYC_CTRL },
+ { "\033[24^", KEYC_F12|KEYC_CTRL },
+ { "\033[25^", KEYC_F13|KEYC_CTRL },
+ { "\033[26^", KEYC_F14|KEYC_CTRL },
+ { "\033[28^", KEYC_F15|KEYC_CTRL },
+ { "\033[29^", KEYC_F16|KEYC_CTRL },
+ { "\033[31^", KEYC_F17|KEYC_CTRL },
+ { "\033[32^", KEYC_F18|KEYC_CTRL },
+ { "\033[33^", KEYC_F19|KEYC_CTRL },
+ { "\033[34^", KEYC_F20|KEYC_CTRL },
+ { "\033[2^", KEYC_IC|KEYC_CTRL },
+ { "\033[3^", KEYC_DC|KEYC_CTRL },
+ { "\033[7^", KEYC_HOME|KEYC_CTRL },
+ { "\033[8^", KEYC_END|KEYC_CTRL },
+ { "\033[6^", KEYC_NPAGE|KEYC_CTRL },
+ { "\033[5^", KEYC_PPAGE|KEYC_CTRL },
+
+ { "\033[11$", KEYC_F1|KEYC_SHIFT },
+ { "\033[12$", KEYC_F2|KEYC_SHIFT },
+ { "\033[13$", KEYC_F3|KEYC_SHIFT },
+ { "\033[14$", KEYC_F4|KEYC_SHIFT },
+ { "\033[15$", KEYC_F5|KEYC_SHIFT },
+ { "\033[17$", KEYC_F6|KEYC_SHIFT },
+ { "\033[18$", KEYC_F7|KEYC_SHIFT },
+ { "\033[19$", KEYC_F8|KEYC_SHIFT },
+ { "\033[20$", KEYC_F9|KEYC_SHIFT },
+ { "\033[21$", KEYC_F10|KEYC_SHIFT },
+ { "\033[23$", KEYC_F11|KEYC_SHIFT },
+ { "\033[24$", KEYC_F12|KEYC_SHIFT },
+ { "\033[25$", KEYC_F13|KEYC_SHIFT },
+ { "\033[26$", KEYC_F14|KEYC_SHIFT },
+ { "\033[28$", KEYC_F15|KEYC_SHIFT },
+ { "\033[29$", KEYC_F16|KEYC_SHIFT },
+ { "\033[31$", KEYC_F17|KEYC_SHIFT },
+ { "\033[32$", KEYC_F18|KEYC_SHIFT },
+ { "\033[33$", KEYC_F19|KEYC_SHIFT },
+ { "\033[34$", KEYC_F20|KEYC_SHIFT },
+ { "\033[2$", KEYC_IC|KEYC_SHIFT },
+ { "\033[3$", KEYC_DC|KEYC_SHIFT },
+ { "\033[7$", KEYC_HOME|KEYC_SHIFT },
+ { "\033[8$", KEYC_END|KEYC_SHIFT },
+ { "\033[6$", KEYC_NPAGE|KEYC_SHIFT },
+ { "\033[5$", KEYC_PPAGE|KEYC_SHIFT },
+
+ { "\033[11@", KEYC_F1|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[12@", KEYC_F2|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[13@", KEYC_F3|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[14@", KEYC_F4|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[15@", KEYC_F5|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[17@", KEYC_F6|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[18@", KEYC_F7|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[19@", KEYC_F8|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[20@", KEYC_F9|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[21@", KEYC_F10|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[23@", KEYC_F11|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[24@", KEYC_F12|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[25@", KEYC_F13|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[26@", KEYC_F14|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[28@", KEYC_F15|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[29@", KEYC_F16|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[31@", KEYC_F17|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[32@", KEYC_F18|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[33@", KEYC_F19|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[34@", KEYC_F20|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[2@", KEYC_IC|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[3@", KEYC_DC|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[7@", KEYC_HOME|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[8@", KEYC_END|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[6@", KEYC_NPAGE|KEYC_CTRL|KEYC_SHIFT },
+ { "\033[5@", KEYC_PPAGE|KEYC_CTRL|KEYC_SHIFT },
+
+ /* Focus tracking. */
+ { "\033[I", KEYC_FOCUS_IN },
+ { "\033[O", KEYC_FOCUS_OUT },
+};
+/* Default terminfo(5) keys. */
+struct tty_default_key_code {
+ enum tty_code_code code;
+ int key;
+};
+const struct tty_default_key_code tty_default_code_keys[] = {
/* Function keys. */
- { TTYC_KF1, NULL, KEYC_F1, 0 },
- { TTYC_KF2, NULL, KEYC_F2, 0 },
- { TTYC_KF3, NULL, KEYC_F3, 0 },
- { TTYC_KF4, NULL, KEYC_F4, 0 },
- { TTYC_KF5, NULL, KEYC_F5, 0 },
- { TTYC_KF6, NULL, KEYC_F6, 0 },
- { TTYC_KF7, NULL, KEYC_F7, 0 },
- { TTYC_KF8, NULL, KEYC_F8, 0 },
- { TTYC_KF9, NULL, KEYC_F9, 0 },
- { TTYC_KF10, NULL, KEYC_F10, 0 },
- { TTYC_KF11, NULL, KEYC_F11, 0 },
- { TTYC_KF12, NULL, KEYC_F12, 0 },
- { TTYC_KF13, NULL, KEYC_F13, 0 },
- { TTYC_KF14, NULL, KEYC_F14, 0 },
- { TTYC_KF15, NULL, KEYC_F15, 0 },
- { TTYC_KF16, NULL, KEYC_F16, 0 },
- { TTYC_KF17, NULL, KEYC_F17, 0 },
- { TTYC_KF18, NULL, KEYC_F18, 0 },
- { TTYC_KF19, NULL, KEYC_F19, 0 },
- { TTYC_KF20, NULL, KEYC_F20, 0 },
- { TTYC_KICH1, NULL, KEYC_IC, 0 },
- { TTYC_KDCH1, NULL, KEYC_DC, 0 },
- { TTYC_KHOME, NULL, KEYC_HOME, 0 },
- { TTYC_KEND, NULL, KEYC_END, 0 },
- { TTYC_KNP, NULL, KEYC_NPAGE, 0 },
- { TTYC_KPP, NULL, KEYC_PPAGE, 0 },
- { TTYC_KCBT, NULL, KEYC_BTAB, 0 },
+ { TTYC_KF1, KEYC_F1 },
+ { TTYC_KF2, KEYC_F2 },
+ { TTYC_KF3, KEYC_F3 },
+ { TTYC_KF4, KEYC_F4 },
+ { TTYC_KF5, KEYC_F5 },
+ { TTYC_KF6, KEYC_F6 },
+ { TTYC_KF7, KEYC_F7 },
+ { TTYC_KF8, KEYC_F8 },
+ { TTYC_KF9, KEYC_F9 },
+ { TTYC_KF10, KEYC_F10 },
+ { TTYC_KF11, KEYC_F11 },
+ { TTYC_KF12, KEYC_F12 },
+ { TTYC_KF13, KEYC_F13 },
+ { TTYC_KF14, KEYC_F14 },
+ { TTYC_KF15, KEYC_F15 },
+ { TTYC_KF16, KEYC_F16 },
+ { TTYC_KF17, KEYC_F17 },
+ { TTYC_KF18, KEYC_F18 },
+ { TTYC_KF19, KEYC_F19 },
+ { TTYC_KF20, KEYC_F20 },
+ { TTYC_KICH1, KEYC_IC },
+ { TTYC_KDCH1, KEYC_DC },
+ { TTYC_KHOME, KEYC_HOME },
+ { TTYC_KEND, KEYC_END },
+ { TTYC_KNP, KEYC_NPAGE },
+ { TTYC_KPP, KEYC_PPAGE },
+ { TTYC_KCBT, KEYC_BTAB },
/* Arrow keys from terminfo. */
- { TTYC_KCUU1, NULL, KEYC_UP, 0 },
- { TTYC_KCUD1, NULL, KEYC_DOWN, 0 },
- { TTYC_KCUB1, NULL, KEYC_LEFT, 0 },
- { TTYC_KCUF1, NULL, KEYC_RIGHT, 0 },
+ { TTYC_KCUU1, KEYC_UP },
+ { TTYC_KCUD1, KEYC_DOWN },
+ { TTYC_KCUB1, KEYC_LEFT },
+ { TTYC_KCUF1, KEYC_RIGHT },
/* Key and modifier capabilities. */
- { TTYC_KDC2, NULL, KEYC_DC|KEYC_SHIFT, 0 },
- { TTYC_KDC3, NULL, KEYC_DC|KEYC_ESCAPE, 0 },
- { TTYC_KDC4, NULL, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KDC5, NULL, KEYC_DC|KEYC_CTRL, 0 },
- { TTYC_KDC6, NULL, KEYC_DC|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KDC7, NULL, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KDN2, NULL, KEYC_DOWN|KEYC_SHIFT, 0 },
- { TTYC_KDN3, NULL, KEYC_DOWN|KEYC_ESCAPE, 0 },
- { TTYC_KDN4, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KDN5, NULL, KEYC_DOWN|KEYC_CTRL, 0 },
- { TTYC_KDN6, NULL, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KDN7, NULL, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KEND2, NULL, KEYC_END|KEYC_SHIFT, 0 },
- { TTYC_KEND3, NULL, KEYC_END|KEYC_ESCAPE, 0 },
- { TTYC_KEND4, NULL, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KEND5, NULL, KEYC_END|KEYC_CTRL, 0 },
- { TTYC_KEND6, NULL, KEYC_END|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KEND7, NULL, KEYC_END|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KHOM2, NULL, KEYC_HOME|KEYC_SHIFT, 0 },
- { TTYC_KHOM3, NULL, KEYC_HOME|KEYC_ESCAPE, 0 },
- { TTYC_KHOM4, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KHOM5, NULL, KEYC_HOME|KEYC_CTRL, 0 },
- { TTYC_KHOM6, NULL, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KHOM7, NULL, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KIC2, NULL, KEYC_IC|KEYC_SHIFT, 0 },
- { TTYC_KIC3, NULL, KEYC_IC|KEYC_ESCAPE, 0 },
- { TTYC_KIC4, NULL, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KIC5, NULL, KEYC_IC|KEYC_CTRL, 0 },
- { TTYC_KIC6, NULL, KEYC_IC|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KIC7, NULL, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KLFT2, NULL, KEYC_LEFT|KEYC_SHIFT, 0 },
- { TTYC_KLFT3, NULL, KEYC_LEFT|KEYC_ESCAPE, 0 },
- { TTYC_KLFT4, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KLFT5, NULL, KEYC_LEFT|KEYC_CTRL, 0 },
- { TTYC_KLFT6, NULL, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KLFT7, NULL, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KNXT2, NULL, KEYC_NPAGE|KEYC_SHIFT, 0 },
- { TTYC_KNXT3, NULL, KEYC_NPAGE|KEYC_ESCAPE, 0 },
- { TTYC_KNXT4, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KNXT5, NULL, KEYC_NPAGE|KEYC_CTRL, 0 },
- { TTYC_KNXT6, NULL, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KNXT7, NULL, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KPRV2, NULL, KEYC_PPAGE|KEYC_SHIFT, 0 },
- { TTYC_KPRV3, NULL, KEYC_PPAGE|KEYC_ESCAPE, 0 },
- { TTYC_KPRV4, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KPRV5, NULL, KEYC_PPAGE|KEYC_CTRL, 0 },
- { TTYC_KPRV6, NULL, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KPRV7, NULL, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KRIT2, NULL, KEYC_RIGHT|KEYC_SHIFT, 0 },
- { TTYC_KRIT3, NULL, KEYC_RIGHT|KEYC_ESCAPE, 0 },
- { TTYC_KRIT4, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KRIT5, NULL, KEYC_RIGHT|KEYC_CTRL, 0 },
- { TTYC_KRIT6, NULL, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KRIT7, NULL, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL, 0 },
- { TTYC_KUP2, NULL, KEYC_UP|KEYC_SHIFT, 0 },
- { TTYC_KUP3, NULL, KEYC_UP|KEYC_ESCAPE, 0 },
- { TTYC_KUP4, NULL, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE, 0 },
- { TTYC_KUP5, NULL, KEYC_UP|KEYC_CTRL, 0 },
- { TTYC_KUP6, NULL, KEYC_UP|KEYC_SHIFT|KEYC_CTRL, 0 },
- { TTYC_KUP7, NULL, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL, 0 },
+ { TTYC_KDC2, KEYC_DC|KEYC_SHIFT },
+ { TTYC_KDC3, KEYC_DC|KEYC_ESCAPE },
+ { TTYC_KDC4, KEYC_DC|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KDC5, KEYC_DC|KEYC_CTRL },
+ { TTYC_KDC6, KEYC_DC|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KDC7, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KDN2, KEYC_DOWN|KEYC_SHIFT },
+ { TTYC_KDN3, KEYC_DOWN|KEYC_ESCAPE },
+ { TTYC_KDN4, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KDN5, KEYC_DOWN|KEYC_CTRL },
+ { TTYC_KDN6, KEYC_DOWN|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KDN7, KEYC_DOWN|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KEND2, KEYC_END|KEYC_SHIFT },
+ { TTYC_KEND3, KEYC_END|KEYC_ESCAPE },
+ { TTYC_KEND4, KEYC_END|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KEND5, KEYC_END|KEYC_CTRL },
+ { TTYC_KEND6, KEYC_END|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KEND7, KEYC_END|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KHOM2, KEYC_HOME|KEYC_SHIFT },
+ { TTYC_KHOM3, KEYC_HOME|KEYC_ESCAPE },
+ { TTYC_KHOM4, KEYC_HOME|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KHOM5, KEYC_HOME|KEYC_CTRL },
+ { TTYC_KHOM6, KEYC_HOME|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KHOM7, KEYC_HOME|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KIC2, KEYC_IC|KEYC_SHIFT },
+ { TTYC_KIC3, KEYC_IC|KEYC_ESCAPE },
+ { TTYC_KIC4, KEYC_IC|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KIC5, KEYC_IC|KEYC_CTRL },
+ { TTYC_KIC6, KEYC_IC|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KIC7, KEYC_IC|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KLFT2, KEYC_LEFT|KEYC_SHIFT },
+ { TTYC_KLFT3, KEYC_LEFT|KEYC_ESCAPE },
+ { TTYC_KLFT4, KEYC_LEFT|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KLFT5, KEYC_LEFT|KEYC_CTRL },
+ { TTYC_KLFT6, KEYC_LEFT|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KLFT7, KEYC_LEFT|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KNXT2, KEYC_NPAGE|KEYC_SHIFT },
+ { TTYC_KNXT3, KEYC_NPAGE|KEYC_ESCAPE },
+ { TTYC_KNXT4, KEYC_NPAGE|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KNXT5, KEYC_NPAGE|KEYC_CTRL },
+ { TTYC_KNXT6, KEYC_NPAGE|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KNXT7, KEYC_NPAGE|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KPRV2, KEYC_PPAGE|KEYC_SHIFT },
+ { TTYC_KPRV3, KEYC_PPAGE|KEYC_ESCAPE },
+ { TTYC_KPRV4, KEYC_PPAGE|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KPRV5, KEYC_PPAGE|KEYC_CTRL },
+ { TTYC_KPRV6, KEYC_PPAGE|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KPRV7, KEYC_PPAGE|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KRIT2, KEYC_RIGHT|KEYC_SHIFT },
+ { TTYC_KRIT3, KEYC_RIGHT|KEYC_ESCAPE },
+ { TTYC_KRIT4, KEYC_RIGHT|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KRIT5, KEYC_RIGHT|KEYC_CTRL },
+ { TTYC_KRIT6, KEYC_RIGHT|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KRIT7, KEYC_RIGHT|KEYC_ESCAPE|KEYC_CTRL },
+ { TTYC_KUP2, KEYC_UP|KEYC_SHIFT },
+ { TTYC_KUP3, KEYC_UP|KEYC_ESCAPE },
+ { TTYC_KUP4, KEYC_UP|KEYC_SHIFT|KEYC_ESCAPE },
+ { TTYC_KUP5, KEYC_UP|KEYC_CTRL },
+ { TTYC_KUP6, KEYC_UP|KEYC_SHIFT|KEYC_CTRL },
+ { TTYC_KUP7, KEYC_UP|KEYC_ESCAPE|KEYC_CTRL },
};
+/* Add key to tree. */
void
tty_keys_add(struct tty *tty, const char *s, int key)
{
@@ -343,27 +349,31 @@ tty_keys_add1(struct tty_key **tkp, const char *s, int key)
/* Initialise a key tree from the table. */
void
-tty_keys_init(struct tty *tty)
+tty_keys_build(struct tty *tty)
{
- const struct tty_key_ent *tke;
- u_int i;
- const char *s;
+ const struct tty_default_key_raw *tdkr;
+ const struct tty_default_key_code *tdkc;
+ u_int i;
+ const char *s;
+ if (tty->key_tree != NULL)
+ tty_keys_free (tty);
tty->key_tree = NULL;
- for (i = 0; i < nitems(tty_keys); i++) {
- tke = &tty_keys[i];
- if (tke->flags & TTYKEY_RAW)
- s = tke->string;
- else {
- if (!tty_term_has(tty->term, tke->code))
- continue;
- s = tty_term_string(tty->term, tke->code);
- }
- if (s[0] != '\033' || s[1] == '\0')
- continue;
+ for (i = 0; i < nitems(tty_default_raw_keys); i++) {
+ tdkr = &tty_default_raw_keys[i];
+
+ s = tdkr->string;
+ if (*s != '\0')
+ tty_keys_add(tty, s, tdkr->key);
+ }
+ for (i = 0; i < nitems(tty_default_code_keys); i++) {
+ tdkc = &tty_default_code_keys[i];
+
+ s = tty_term_string(tty->term, tdkc->code);
+ if (*s != '\0')
+ tty_keys_add(tty, s, tdkc->key);
- tty_keys_add(tty, s + 1, tke->key);
}
}
@@ -440,34 +450,18 @@ tty_keys_next(struct tty *tty)
cc_t bspace;
int key, delay;
+ /* Get key buffer. */
buf = EVBUFFER_DATA(tty->event->input);
len = EVBUFFER_LENGTH(tty->event->input);
if (len == 0)
return (0);
log_debug("keys are %zu (%.*s)", len, (int) len, buf);
- /* If a normal key, return it. */
- if (*buf != '\033') {
- key = (u_char) *buf;
- evbuffer_drain(tty->event->input, 1);
-
- /*
- * Check for backspace key using termios VERASE - the terminfo
- * kbs entry is extremely unreliable, so cannot be safely
- * used. termios should have a better idea.
- */
- bspace = tty->tio.c_cc[VERASE];
- if (bspace != _POSIX_VDISABLE && key == bspace)
- key = KEYC_BSPACE;
- goto handle_key;
- }
-
/* Is this device attributes response? */
switch (tty_keys_device(tty, buf, len, &size)) {
case 0: /* yes */
- evbuffer_drain(tty->event->input, size);
key = KEYC_NONE;
- goto handle_key;
+ goto complete_key;
case -1: /* no, or not valid */
break;
case 1: /* partial */
@@ -477,9 +471,8 @@ tty_keys_next(struct tty *tty)
/* Is this a mouse key press? */
switch (tty_keys_mouse(tty, buf, len, &size)) {
case 0: /* yes */
- evbuffer_drain(tty->event->input, size);
key = KEYC_MOUSE;
- goto handle_key;
+ goto complete_key;
case -1: /* no, or not valid */
break;
case 1: /* partial */
@@ -489,8 +482,7 @@ tty_keys_next(struct tty *tty)
/* Try to parse a key with an xterm-style modifier. */
switch (xterm_keys_find(buf, len, &size, &key)) {
case 0: /* found */
- evbuffer_drain(tty->event->input, size);
- goto handle_key;
+ goto complete_key;
case -1: /* not found */
break;
case 1:
@@ -498,108 +490,112 @@ tty_keys_next(struct tty *tty)
}
/* Look for matching key string and return if found. */
- tk = tty_keys_find(tty, buf + 1, len - 1, &size);
+ tk = tty_keys_find(tty, buf, len, &size);
if (tk != NULL) {
+ if (tk->next != NULL)
+ goto partial_key;
key = tk->key;
- goto found_key;
+ goto complete_key;
}
- /* Skip the escape. */
- buf++;
- len--;
-
- /* Is there a normal key following? */
- if (len != 0 && *buf != '\033') {
- key = *buf | KEYC_ESCAPE;
- evbuffer_drain(tty->event->input, 2);
- goto handle_key;
- }
+first_key:
+ /* Is this a meta key? */
+ if (len >= 2 && buf[0] == '\033') {
+ if (buf[1] != '\033') {
+ key = buf[1] | KEYC_ESCAPE;
+ size = 2;
+ goto complete_key;
+ }
- /* Or a key string? */
- if (len > 1) {
tk = tty_keys_find(tty, buf + 1, len - 1, &size);
if (tk != NULL) {
- key = tk->key | KEYC_ESCAPE;
size++; /* include escape */
- goto found_key;
+ if (tk->next != NULL)
+ goto partial_key;
+ key = tk->key;
+ if (key != KEYC_NONE)
+ key |= KEYC_ESCAPE;
+ goto complete_key;
}
}
- /* Escape and then nothing useful - fall through. */
+ /* No key found, take first. */
+ key = (u_char) *buf;
+ size = 1;
-partial_key:
/*
- * Escape but no key string. If have already seen an escape and the
- * timer has expired, give up waiting and send the escape.
+ * Check for backspace key using termios VERASE - the terminfo
+ * kbs entry is extremely unreliable, so cannot be safely
+ * used. termios should have a better idea.
*/
- if ((tty->flags & TTY_ESCAPE) &&
- evtimer_initialized(&tty->key_timer) &&
- !evtimer_pending(&tty->key_timer, NULL)) {
- evbuffer_drain(tty->event->input, 1);
- key = '\033';
- goto handle_key;
- }
+ bspace = tty->tio.c_cc[VERASE];
+ if (bspace != _POSIX_VDISABLE && key == bspace)
+ key = KEYC_BSPACE;
+
+ goto complete_key;
- /* Fall through to start the timer. */
+partial_key:
+ log_debug("partial key %.*s", (int) len, buf);
-start_timer:
- /* If already waiting for timer, do nothing. */
- if (evtimer_initialized(&tty->key_timer) &&
- evtimer_pending(&tty->key_timer, NULL))
+ /* If timer is going, check for expiration. */
+ if (tty->flags & TTY_TIMER) {
+ if (evtimer_initialized(&tty->key_timer) &&
+ !evtimer_pending(&tty->key_timer, NULL))
+ goto first_key;
return (0);
+ }
- /* Start the timer and wait for expiry or more data. */
+ /* Get the time period. */
delay = options_get_number(&global_options, "escape-time");
tv.tv_sec = delay / 1000;
tv.tv_usec = (delay % 1000) * 1000L;
+ /* Start the timer. */
if (event_initialized(&tty->key_timer))
evtimer_del(&tty->key_timer);
evtimer_set(&tty->key_timer, tty_keys_callback, tty);
evtimer_add(&tty->key_timer, &tv);
- tty->flags |= TTY_ESCAPE;
+ tty->flags |= TTY_TIMER;
return (0);
-found_key:
- if (tk->next != NULL) {
- /* Partial key. Start the timer if not already expired. */
- if (!(tty->flags & TTY_ESCAPE))
- goto start_timer;
-
- /* Otherwise, if no key, send the escape alone. */
- if (tk->key == KEYC_NONE)
- goto partial_key;
+complete_key:
+ log_debug("complete key %.*s %#x", (int) size, buf, key);
- /* Or fall through to send the partial key found. */
- }
- evbuffer_drain(tty->event->input, size + 1);
+ /* Remove data from buffer. */
+ evbuffer_drain(tty->event->input, size);
- goto handle_key;
-
-handle_key:
+ /* Remove key timer. */
if (event_initialized(&tty->key_timer))
evtimer_del(&tty->key_timer);
+ tty->flags &= ~TTY_TIMER;
+
+ /* Check for focus events. */
+ if (key == KEYC_FOCUS_OUT) {
+ tty->client->flags &= ~CLIENT_FOCUSED;
+ return (1);
+ } else if (key == KEYC_FOCUS_IN) {
+ tty->client->flags |= CLIENT_FOCUSED;
+ return (1);
+ }
+ /* Fire the key. */
if (key != KEYC_NONE)
server_client_handle_key(tty->client, key);
- tty->flags &= ~TTY_ESCAPE;
return (1);
}
/* Key timer callback. */
-/* ARGSUSED */
void
tty_keys_callback(unused int fd, unused short events, void *data)
{
struct tty *tty = data;
- if (!(tty->flags & TTY_ESCAPE))
- return;
-
- while (tty_keys_next(tty))
- ;
+ if (tty->flags & TTY_TIMER) {
+ while (tty_keys_next(tty))
+ ;
+ }
}
/*
@@ -611,20 +607,26 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
{
struct mouse_event *m = &tty->mouse;
struct utf8_data utf8data;
- u_int i, value, x, y, b;
+ u_int i, value, x, y, b, sgr, sgr_b, sgr_rel;
+ unsigned char c;
/*
* Standard mouse sequences are \033[M followed by three characters
- * indicating buttons, X and Y, all based at 32 with 1,1 top-left.
+ * indicating button, X and Y, all based at 32 with 1,1 top-left.
*
* UTF-8 mouse sequences are similar but the three are expressed as
* UTF-8 characters.
+ *
+ * SGR extended mouse sequences are \033[< followed by three numbers in
+ * decimal and separated by semicolons indicating button, X and Y. A
+ * trailing 'M' is click or scroll and trailing 'm' release. All are
+ * based at 0 with 1,1 top-left.
*/
*size = 0;
- x = y = b = 0;
+ x = y = b = sgr = sgr_b = sgr_rel = 0;
- /* First three bytes are always \033[M. */
+ /* First two bytes are always \033[. */
if (buf[0] != '\033')
return (-1);
if (len == 1)
@@ -633,50 +635,99 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
return (-1);
if (len == 2)
return (1);
- if (buf[2] != 'M')
- return (-1);
- if (len == 3)
- return (1);
-
- /* Read the three inputs. */
- *size = 3;
- for (i = 0; i < 3; i++) {
- if (len < *size)
- return (1);
- if (tty->mode & MODE_MOUSE_UTF8) {
- if (utf8_open(&utf8data, buf[*size])) {
- if (utf8data.size != 2)
- return (-1);
+ /*
+ * Third byte is M in old standard and UTF-8 extension, < in SGR
+ * extension.
+ */
+ if (buf[2] == 'M') {
+ /* Read the three inputs. */
+ *size = 3;
+ for (i = 0; i < 3; i++) {
+ if (len <= *size)
+ return (1);
+
+ if (tty->mode & MODE_MOUSE_UTF8) {
+ if (utf8_open(&utf8data, buf[*size])) {
+ if (utf8data.size != 2)
+ return (-1);
+ (*size)++;
+ if (len <= *size)
+ return (1);
+ utf8_append(&utf8data, buf[*size]);
+ value = utf8_combine(&utf8data);
+ } else
+ value = (u_char) buf[*size];
(*size)++;
- if (len < *size)
- return (1);
- utf8_append(&utf8data, buf[*size]);
- value = utf8_combine(&utf8data);
- } else
- value = (unsigned char)buf[*size];
- (*size)++;
- } else {
- value = (unsigned char)buf[*size];
- (*size)++;
- }
-
- if (i == 0)
- b = value;
- else if (i == 1)
- x = value;
- else
- y = value;
- }
- log_debug("mouse input: %.*s", (int) *size, buf);
+ } else {
+ value = (u_char) buf[*size];
+ (*size)++;
+ }
- /* Check and return the mouse input. */
- if (b < 32 || x < 33 || y < 33)
+ if (i == 0)
+ b = value;
+ else if (i == 1)
+ x = value;
+ else
+ y = value;
+ }
+ log_debug("mouse input: %.*s", (int) *size, buf);
+
+ /* Check and return the mouse input. */
+ if (b < 32 || x < 33 || y < 33)
+ return (-1);
+ b -= 32;
+ x -= 33;
+ y -= 33;
+ } else if (buf[2] == '<') {
+ /* Read the three inputs. */
+ *size = 3;
+ while (1) {
+ if (len <= *size)
+ return (1);
+ c = (u_char)buf[(*size)++];
+ if (c == ';')
+ break;
+ if (c < '0' || c > '9')
+ return (-1);
+ sgr_b = 10 * sgr_b + (c - '0');
+ }
+ while (1) {
+ if (len <= *size)
+ return (1);
+ c = (u_char)buf[(*size)++];
+ if (c == ';')
+ break;
+ if (c < '0' || c > '9')
+ return (-1);
+ x = 10 * x + (c - '0');
+ }
+ while (1) {
+ if (len <= *size)
+ return (1);
+ c = (u_char) buf[(*size)++];
+ if (c == 'M' || c == 'm')
+ break;
+ if (c < '0' || c > '9')
+ return (-1);
+ y = 10 * y + (c - '0');
+ }
+ log_debug("mouse input (sgr): %.*s", (int) *size, buf);
+
+ /* Check and return the mouse input. */
+ if (x < 1 || y < 1)
+ return (-1);
+ x--;
+ y--;
+ sgr = 1;
+ sgr_rel = (c == 'm');
+
+ /* Figure out what b would be in old format. */
+ b = sgr_b;
+ if (sgr_rel)
+ b |= 3;
+ } else
return (-1);
- b -= 32;
- x -= 33;
- y -= 33;
- log_debug("mouse position: x=%u y=%u b=%u", x, y, b);
/* Fill in mouse structure. */
if (~m->event & MOUSE_EVENT_WHEEL) {
@@ -684,6 +735,9 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
m->ly = m->y;
}
m->xb = b;
+ m->sgr = sgr;
+ m->sgr_xb = sgr_b;
+ m->sgr_rel = sgr_rel;
if (b & 64) { /* wheel button */
b &= 3;
if (b == 0)
diff --git a/tty.c b/tty.c
index e810f36f..ab75d948 100644
--- a/tty.c
+++ b/tty.c
@@ -149,19 +149,18 @@ tty_open(struct tty *tty, const char *overrides, char **cause)
}
tty->flags |= TTY_OPENED;
- tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_ESCAPE);
+ tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_TIMER);
tty->event = bufferevent_new(
tty->fd, tty_read_callback, NULL, tty_error_callback, tty);
tty_start_tty(tty);
- tty_keys_init(tty);
+ tty_keys_build(tty);
return (0);
}
-/* ARGSUSED */
void
tty_read_callback(unused struct bufferevent *bufev, void *data)
{
@@ -171,7 +170,6 @@ tty_read_callback(unused struct bufferevent *bufev, void *data)
;
}
-/* ARGSUSED */
void
tty_error_callback(
unused struct bufferevent *bufev, unused short what, unused void *data)
@@ -220,10 +218,10 @@ tty_start_tty(struct tty *tty)
tty_putcode(tty, TTYC_CNORM);
if (tty_term_has(tty->term, TTYC_KMOUS))
- tty_puts(tty, "\033[?1000l");
+ tty_puts(tty, "\033[?1000l\033[?1006l\033[?1005l");
if (tty_term_has(tty->term, TTYC_XT))
- tty_puts(tty, "\033[c");
+ tty_puts(tty, "\033[c\033[>4;1m\033[?1004h");
tty->cx = UINT_MAX;
tty->cy = UINT_MAX;
@@ -267,8 +265,6 @@ tty_stop_tty(struct tty *tty)
if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1)
return;
- setblocking(tty->fd, 1);
-
tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1));
if (tty_use_acs(tty))
tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
@@ -285,9 +281,14 @@ tty_stop_tty(struct tty *tty)
tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM));
if (tty_term_has(tty->term, TTYC_KMOUS))
- tty_raw(tty, "\033[?1000l");
+ tty_raw(tty, "\033[?1000l\033[?1006l\033[?1005l");
+
+ if (tty_term_has(tty->term, TTYC_XT))
+ tty_raw(tty, "\033[>4m\033[?1004l");
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
+
+ setblocking(tty->fd, 1);
}
void
@@ -332,7 +333,21 @@ tty_free(struct tty *tty)
void
tty_raw(struct tty *tty, const char *s)
{
- write(tty->fd, s, strlen(s));
+ ssize_t n, slen;
+ u_int i;
+
+ slen = strlen(s);
+ for (i = 0; i < 5; i++) {
+ n = write(tty->fd, s, slen);
+ if (n >= 0) {
+ s += n;
+ slen -= n;
+ if (slen == 0)
+ break;
+ } else if (n == -1 && errno != EAGAIN)
+ break;
+ usleep(100);
+ }
}
void
@@ -474,10 +489,21 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
}
tty->cstyle = s->cstyle;
}
- if (changed & ALL_MOUSE_MODES) {
+ if (changed & (ALL_MOUSE_MODES|MODE_MOUSE_UTF8)) {
if (mode & ALL_MOUSE_MODES) {
+ /*
+ * Enable the UTF-8 (1005) extension if configured to.
+ * Enable the SGR (1006) extension unconditionally, as
+ * this is safe from misinterpretation. Do it in this
+ * order, because in some terminals it's the last one
+ * that takes effect and SGR is the preferred one.
+ */
if (mode & MODE_MOUSE_UTF8)
tty_puts(tty, "\033[?1005h");
+ else
+ tty_puts(tty, "\033[?1005l");
+ tty_puts(tty, "\033[?1006h");
+
if (mode & MODE_MOUSE_ANY)
tty_puts(tty, "\033[?1003h");
else if (mode & MODE_MOUSE_BUTTON)
@@ -491,6 +517,8 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s)
tty_puts(tty, "\033[?1002l");
else if (tty->mode & MODE_MOUSE_STANDARD)
tty_puts(tty, "\033[?1000l");
+
+ tty_puts(tty, "\033[?1006l");
if (tty->mode & MODE_MOUSE_UTF8)
tty_puts(tty, "\033[?1005l");
}
diff --git a/window-choose.c b/window-choose.c
index 6dc149f0..3c68d101 100644
--- a/window-choose.c
+++ b/window-choose.c
@@ -31,6 +31,8 @@ void window_choose_key(struct window_pane *, struct session *, int);
void window_choose_mouse(
struct window_pane *, struct session *, struct mouse_event *);
+void window_choose_default_callback(struct window_choose_data *);
+
void window_choose_fire_callback(
struct window_pane *, struct window_choose_data *);
void window_choose_redraw_screen(struct window_pane *);
@@ -73,9 +75,9 @@ struct window_choose_mode_data {
char *input_str;
void (*callbackfn)(struct window_choose_data *);
- void (*freefn)(struct window_choose_data *);
};
+void window_choose_free1(struct window_choose_mode_data *);
int window_choose_key_index(struct window_choose_mode_data *, u_int);
int window_choose_index_key(struct window_choose_mode_data *, int);
void window_choose_prompt_input(enum window_choose_input_type,
@@ -101,8 +103,7 @@ window_choose_add(struct window_pane *wp, struct window_choose_data *wcd)
void
window_choose_ready(struct window_pane *wp, u_int cur,
- void (*callbackfn)(struct window_choose_data *),
- void (*freefn)(struct window_choose_data *))
+ void (*callbackfn)(struct window_choose_data *))
{
struct window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -112,7 +113,8 @@ window_choose_ready(struct window_pane *wp, u_int cur,
data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s);
data->callbackfn = callbackfn;
- data->freefn = freefn;
+ if (data->callbackfn == NULL)
+ data->callbackfn = window_choose_default_callback;
ARRAY_CONCAT(&data->old_list, &data->list);
@@ -129,7 +131,6 @@ window_choose_init(struct window_pane *wp)
wp->modedata = data = xmalloc(sizeof *data);
data->callbackfn = NULL;
- data->freefn = NULL;
data->input_type = WINDOW_CHOOSE_NORMAL;
data->input_str = xstrdup("");
data->input_prompt = NULL;
@@ -154,35 +155,104 @@ window_choose_init(struct window_pane *wp)
}
struct window_choose_data *
-window_choose_data_create(struct cmd_ctx *ctx)
+window_choose_data_create(int type, struct client *c, struct session *s)
{
struct window_choose_data *wcd;
wcd = xmalloc(sizeof *wcd);
+ wcd->type = type;
+
wcd->ft = format_create();
wcd->ft_template = NULL;
+
wcd->command = NULL;
+
wcd->wl = NULL;
- wcd->tree_session = NULL;
- wcd->client = ctx->curclient;
- wcd->session = ctx->curclient->session;
+ wcd->pane_id = -1;
wcd->idx = -1;
- wcd->type = 0;
+
+ wcd->tree_session = NULL;
+
+ wcd->start_client = c;
+ wcd->start_client->references++;
+ wcd->start_session = s;
+ wcd->start_session->references++;
return (wcd);
}
void
+window_choose_data_free(struct window_choose_data *wcd)
+{
+ wcd->start_client->references--;
+ wcd->start_session->references--;
+
+ if (wcd->tree_session != NULL)
+ wcd->tree_session->references--;
+
+ free(wcd->ft_template);
+ format_free(wcd->ft);
+
+ free(wcd->command);
+ free(wcd);
+}
+
+void
+window_choose_data_run(struct window_choose_data *cdata)
+{
+ struct cmd_list *cmdlist;
+ char *cause;
+
+ /*
+ * The command template will have already been replaced. But if it's
+ * NULL, bail here.
+ */
+ if (cdata->command == NULL)
+ return;
+
+ if (cmd_string_parse(cdata->command, &cmdlist, NULL, 0, &cause) != 0) {
+ if (cause != NULL) {
+ *cause = toupper((u_char) *cause);
+ status_message_set(cdata->start_client, "%s", cause);
+ free(cause);
+ }
+ return;
+ }
+
+ cmdq_run(cdata->start_client->cmdq, cmdlist);
+ cmd_list_free(cmdlist);
+}
+
+void
+window_choose_default_callback(struct window_choose_data *wcd)
+{
+ if (wcd == NULL)
+ return;
+ if (wcd->start_client->flags & CLIENT_DEAD)
+ return;
+
+ window_choose_data_run(wcd);
+}
+
+void
window_choose_free(struct window_pane *wp)
{
- struct window_choose_mode_data *data = wp->modedata;
+ if (wp->modedata != NULL)
+ window_choose_free1(wp->modedata);
+}
+
+void
+window_choose_free1(struct window_choose_mode_data *data)
+{
struct window_choose_mode_item *item;
u_int i;
+ if (data == NULL)
+ return;
+
for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) {
item = &ARRAY_ITEM(&data->old_list, i);
- if (data->freefn != NULL && item->wcd != NULL)
- data->freefn(item->wcd);
+ window_choose_data_free(item->wcd);
free(item->name);
}
ARRAY_FREE(&data->list);
@@ -209,17 +279,16 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
void
window_choose_fire_callback(
- struct window_pane *wp, struct window_choose_data *wcd)
+ struct window_pane *wp, struct window_choose_data *wcd)
{
struct window_choose_mode_data *data = wp->modedata;
- const struct window_mode *oldmode;
- oldmode = wp->mode;
- wp->mode = NULL;
+ wp->modedata = NULL;
+ window_pane_reset_mode(wp);
data->callbackfn(wcd);
- wp->mode = oldmode;
+ window_choose_free1(data);
}
void
@@ -299,7 +368,7 @@ window_choose_collapse_all(struct window_pane *wp)
struct session *s, *chosen;
u_int i;
- chosen = ARRAY_ITEM(&data->list, data->selected).wcd->session;
+ chosen = ARRAY_ITEM(&data->list, data->selected).wcd->start_session;
RB_FOREACH(s, sessions, &sessions)
window_choose_collapse(wp, s);
@@ -401,7 +470,6 @@ window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
}
}
-/* ARGSUSED */
void
window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
{
@@ -416,7 +484,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
items = ARRAY_LENGTH(&data->list);
if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
- switch (mode_key_lookup(&data->mdata, key)) {
+ switch (mode_key_lookup(&data->mdata, key, NULL)) {
case MODEKEYCHOICE_CANCEL:
data->input_type = WINDOW_CHOOSE_NORMAL;
window_choose_redraw_screen(wp);
@@ -430,7 +498,6 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
}
item = &ARRAY_ITEM(&data->list, n);
window_choose_fire_callback(wp, item->wcd);
- window_pane_reset_mode(wp);
break;
case MODEKEYCHOICE_BACKSPACE:
input_len = strlen(data->input_str);
@@ -448,15 +515,13 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
return;
}
- switch (mode_key_lookup(&data->mdata, key)) {
+ switch (mode_key_lookup(&data->mdata, key, NULL)) {
case MODEKEYCHOICE_CANCEL:
window_choose_fire_callback(wp, NULL);
- window_pane_reset_mode(wp);
break;
case MODEKEYCHOICE_CHOOSE:
item = &ARRAY_ITEM(&data->list, data->selected);
window_choose_fire_callback(wp, item->wcd);
- window_pane_reset_mode(wp);
break;
case MODEKEYCHOICE_TREE_TOGGLE:
item = &ARRAY_ITEM(&data->list, data->selected);
@@ -606,12 +671,10 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
item = &ARRAY_ITEM(&data->list, data->selected);
window_choose_fire_callback(wp, item->wcd);
- window_pane_reset_mode(wp);
break;
}
}
-/* ARGSUSED */
void
window_choose_mouse(
struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
@@ -635,7 +698,6 @@ window_choose_mouse(
item = &ARRAY_ITEM(&data->list, data->selected);
window_choose_fire_callback(wp, item->wcd);
- window_pane_reset_mode(wp);
}
void
@@ -681,7 +743,7 @@ window_choose_write_line(
(item->wcd->type & TREE_SESSION) ?
(item->state & TREE_EXPANDED ? "-" : "+") : "", item->name);
}
- while (s->cx < screen_size_x(s))
+ while (s->cx < screen_size_x(s) - 1)
screen_write_putc(ctx, &gc, ' ');
if (data->input_type != WINDOW_CHOOSE_NORMAL) {
@@ -707,7 +769,7 @@ window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
int mkey;
for (ptr = keys; *ptr != '\0'; ptr++) {
- mkey = mode_key_lookup(&data->mdata, *ptr);
+ mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
continue;
if (idx-- == 0)
@@ -727,7 +789,7 @@ window_choose_index_key(struct window_choose_mode_data *data, int key)
u_int idx = 0;
for (ptr = keys; *ptr != '\0'; ptr++) {
- mkey = mode_key_lookup(&data->mdata, *ptr);
+ mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
continue;
if (key == *ptr)
@@ -790,58 +852,23 @@ window_choose_scroll_down(struct window_pane *wp)
screen_write_stop(&ctx);
}
-void
-window_choose_ctx(struct window_choose_data *cdata)
-{
- struct cmd_ctx ctx;
- struct cmd_list *cmdlist;
- char *cause;
-
- /* The command template will have already been replaced. But if it's
- * NULL, bail here.
- */
- if (cdata->command == NULL)
- return;
-
- if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) {
- if (cause != NULL) {
- *cause = toupper((u_char) *cause);
- status_message_set(cdata->client, "%s", cause);
- free(cause);
- }
- return;
- }
-
- ctx.msgdata = NULL;
- ctx.curclient = cdata->client;
-
- ctx.error = key_bindings_error;
- ctx.print = key_bindings_print;
- ctx.info = key_bindings_info;
-
- ctx.cmdclient = NULL;
-
- cmd_list_exec(cmdlist, &ctx);
- cmd_list_free(cmdlist);
-}
-
struct window_choose_data *
-window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx,
- struct session *s, const char *template, char *action, u_int idx)
+window_choose_add_session(struct window_pane *wp, struct client *c,
+ struct session *s, const char *template, const char *action, u_int idx)
{
struct window_choose_data *wcd;
- wcd = window_choose_data_create(ctx);
- wcd->idx = s->idx;
+ wcd = window_choose_data_create(TREE_SESSION, c, c->session);
+ wcd->idx = s->id;
+
wcd->tree_session = s;
- wcd->type = TREE_SESSION;
- wcd->command = cmd_template_replace(action, s->name, 1);
+ wcd->tree_session->references++;
+
wcd->ft_template = xstrdup(template);
format_add(wcd->ft, "line", "%u", idx);
format_session(wcd->ft, s);
- wcd->client->references++;
- wcd->session->references++;
+ wcd->command = cmd_template_replace(action, s->name, 1);
window_choose_add(wp, wcd);
@@ -849,63 +876,60 @@ window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx,
}
struct window_choose_data *
-window_choose_add_item(struct window_pane *wp, struct cmd_ctx *ctx,
- struct winlink *wl, const char *template, char *action, u_int idx)
+window_choose_add_item(struct window_pane *wp, struct client *c,
+ struct winlink *wl, const char *template, const char *action, u_int idx)
{
struct window_choose_data *wcd;
- char *action_data;
+ char *expanded;
- wcd = window_choose_data_create(ctx);
+ wcd = window_choose_data_create(TREE_OTHER, c, c->session);
wcd->idx = wl->idx;
+
wcd->ft_template = xstrdup(template);
format_add(wcd->ft, "line", "%u", idx);
- format_session(wcd->ft, wcd->session);
- format_winlink(wcd->ft, wcd->session, wl);
+ format_session(wcd->ft, wcd->start_session);
+ format_winlink(wcd->ft, wcd->start_session, wl);
format_window_pane(wcd->ft, wl->window->active);
- wcd->client->references++;
- wcd->session->references++;
-
- window_choose_add(wp, wcd);
-
/*
- * Interpolate action_data here, since the data we pass back is the
- * expanded template itself.
+ * Interpolate action here, since the data we pass back is the expanded
+ * template itself.
*/
- xasprintf(&action_data, "%s", format_expand(wcd->ft, wcd->ft_template));
- wcd->command = cmd_template_replace(action, action_data, 1);
- free(action_data);
+ xasprintf(&expanded, "%s", format_expand(wcd->ft, wcd->ft_template));
+ wcd->command = cmd_template_replace(action, expanded, 1);
+ free(expanded);
+
+ window_choose_add(wp, wcd);
return (wcd);
}
struct window_choose_data *
-window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx,
+window_choose_add_window(struct window_pane *wp, struct client *c,
struct session *s, struct winlink *wl, const char *template,
- char *action, u_int idx)
+ const char *action, u_int idx)
{
struct window_choose_data *wcd;
- char *action_data;
-
- wcd = window_choose_data_create(ctx);
-
- xasprintf(&action_data, "%s:%d", s->name, wl->idx);
- wcd->command = cmd_template_replace(action, action_data, 1);
- free(action_data);
+ char *expanded;
+ wcd = window_choose_data_create(TREE_WINDOW, c, c->session);
wcd->idx = wl->idx;
+
wcd->wl = wl;
+
wcd->tree_session = s;
- wcd->type = TREE_WINDOW;
+ wcd->tree_session->references++;
+
wcd->ft_template = xstrdup(template);
format_add(wcd->ft, "line", "%u", idx);
format_session(wcd->ft, s);
format_winlink(wcd->ft, s, wl);
format_window_pane(wcd->ft, wl->window->active);
- wcd->client->references++;
- wcd->session->references++;
+ xasprintf(&expanded, "%s:%d", s->name, wl->idx);
+ wcd->command = cmd_template_replace(action, expanded, 1);
+ free(expanded);
window_choose_add(wp, wcd);
diff --git a/window-clock.c b/window-clock.c
index 4cd3f6a1..61cf1502 100644
--- a/window-clock.c
+++ b/window-clock.c
@@ -83,7 +83,6 @@ window_clock_resize(struct window_pane *wp, u_int sx, u_int sy)
window_clock_draw_screen(wp);
}
-/* ARGSUSED */
void
window_clock_key(
struct window_pane *wp, unused struct session *sess, unused int key)
diff --git a/window-copy.c b/window-copy.c
index c319aba6..51a8f108 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -52,6 +52,10 @@ void window_copy_goto_line(struct window_pane *, const char *);
void window_copy_update_cursor(struct window_pane *, u_int, u_int);
void window_copy_start_selection(struct window_pane *);
int window_copy_update_selection(struct window_pane *);
+void *window_copy_get_selection(struct window_pane *, size_t *);
+void window_copy_copy_buffer(struct window_pane *, int, void *, size_t);
+void window_copy_copy_pipe(
+ struct window_pane *, struct session *, int, const char *);
void window_copy_copy_selection(struct window_pane *, int);
void window_copy_clear_selection(struct window_pane *);
void window_copy_copy_line(
@@ -364,6 +368,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
u_int n;
int np, keys;
enum mode_key_cmd cmd;
+ const char *arg;
np = data->numprefix;
if (np <= 0)
@@ -405,7 +410,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
return;
}
- cmd = mode_key_lookup(&data->mdata, key);
+ cmd = mode_key_lookup(&data->mdata, key, &arg);
switch (cmd) {
case MODEKEYCOPY_CANCEL:
window_pane_reset_mode(wp);
@@ -533,6 +538,13 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
window_copy_clear_selection(wp);
window_copy_redraw_screen(wp);
break;
+ case MODEKEYCOPY_COPYPIPE:
+ if (sess != NULL) {
+ window_copy_copy_pipe(wp, sess, data->numprefix, arg);
+ window_pane_reset_mode(wp);
+ return;
+ }
+ break;
case MODEKEYCOPY_COPYSELECTION:
if (sess != NULL) {
window_copy_copy_selection(wp, data->numprefix);
@@ -735,7 +747,7 @@ window_copy_key_input(struct window_pane *wp, int key)
size_t inputlen;
int np;
- switch (mode_key_lookup(&data->mdata, key)) {
+ switch (mode_key_lookup(&data->mdata, key, NULL)) {
case MODEKEYEDIT_CANCEL:
data->numprefix = -1;
return (-1);
@@ -814,7 +826,6 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
return (0);
}
-/* ARGSUSED */
void
window_copy_mouse(
struct window_pane *wp, struct session *sess, struct mouse_event *m)
@@ -1260,19 +1271,19 @@ window_copy_update_selection(struct window_pane *wp)
return (1);
}
-void
-window_copy_copy_selection(struct window_pane *wp, int idx)
+void *
+window_copy_get_selection(struct window_pane *wp, size_t *len)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
char *buf;
size_t off;
- u_int i, xx, yy, sx, sy, ex, ey, limit;
+ u_int i, xx, yy, sx, sy, ex, ey;
u_int firstsx, lastex, restex, restsx;
int keys;
if (!s->sel.flag)
- return;
+ return (NULL);
buf = xmalloc(1);
off = 0;
@@ -1365,19 +1376,61 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
/* Don't bother if no data. */
if (off == 0) {
free(buf);
- return;
+ return (NULL);
}
- off--; /* remove final \n */
+ *len = off - 1; /* remove final \n */
+ return (buf);
+}
+
+void
+window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len)
+{
+ u_int limit;
+ struct screen_write_ctx ctx;
- if (options_get_number(&global_options, "set-clipboard"))
- screen_write_setselection(&wp->ictx.ctx, buf, off);
+ if (options_get_number(&global_options, "set-clipboard")) {
+ screen_write_start(&ctx, wp, NULL);
+ screen_write_setselection(&ctx, buf, len);
+ screen_write_stop(&ctx);
+ }
- /* Add the buffer to the stack. */
if (idx == -1) {
limit = options_get_number(&global_options, "buffer-limit");
- paste_add(&global_buffers, buf, off, limit);
+ paste_add(&global_buffers, buf, len, limit);
} else
- paste_replace(&global_buffers, idx, buf, off);
+ paste_replace(&global_buffers, idx, buf, len);
+}
+
+void
+window_copy_copy_pipe(
+ struct window_pane *wp, struct session *sess, int idx, const char *arg)
+{
+ void *buf;
+ size_t len;
+ struct job *job;
+
+
+ buf = window_copy_get_selection(wp, &len);
+ if (buf == NULL)
+ return;
+
+ job = job_run(arg, sess, NULL, NULL, NULL);
+ bufferevent_write(job->event, buf, len);
+
+ window_copy_copy_buffer(wp, idx, buf, len);
+}
+
+void
+window_copy_copy_selection(struct window_pane *wp, int idx)
+{
+ void* buf;
+ size_t len;
+
+ buf = window_copy_get_selection(wp, &len);
+ if (buf == NULL)
+ return;
+
+ window_copy_copy_buffer(wp, idx, buf, len);
}
void
diff --git a/window.c b/window.c
index aed7596b..2be51e93 100644
--- a/window.c
+++ b/window.c
@@ -307,24 +307,36 @@ window_create1(u_int sx, u_int sy)
struct window *
window_create(const char *name, const char *cmd, const char *shell,
const char *cwd, struct environ *env, struct termios *tio,
- u_int sx, u_int sy, u_int hlimit,char **cause)
+ u_int sx, u_int sy, u_int hlimit, char **cause)
{
struct window *w;
struct window_pane *wp;
+ const char *prefix;
+ char *cmd1;
w = window_create1(sx, sy);
wp = window_add_pane(w, hlimit);
- layout_init(w);
- if (window_pane_spawn(wp, cmd, shell, cwd, env, tio, cause) != 0) {
+ layout_init(w, wp);
+
+ if (*cmd != '\0') {
+ prefix = options_get_string(&w->options, "command-prefix");
+ xasprintf(&cmd1, "%s%s", prefix, cmd);
+ } else
+ cmd1 = xstrdup("");
+ if (window_pane_spawn(wp, cmd1, shell, cwd, env, tio, cause) != 0) {
window_destroy(w);
+ free(cmd1);
return (NULL);
}
+ free(cmd1);
+
w->active = TAILQ_FIRST(&w->panes);
if (name != NULL) {
w->name = xstrdup(name);
options_set_number(&w->options, "automatic-rename", 0);
} else
w->name = default_window_name(w);
+
return (w);
}
@@ -333,6 +345,8 @@ window_destroy(struct window *w)
{
u_int i;
+ window_unzoom(w);
+
if (window_index(w, &i) != 0)
fatalx("index not found");
ARRAY_SET(&windows, i, NULL);
@@ -455,6 +469,58 @@ window_find_string(struct window *w, const char *s)
return (window_get_active_at(w, x, y));
}
+int
+window_zoom(struct window_pane *wp)
+{
+ struct window *w = wp->window;
+ struct window_pane *wp1;
+
+ if (w->flags & WINDOW_ZOOMED)
+ return (-1);
+
+ if (!window_pane_visible(wp))
+ return (-1);
+
+ if (window_count_panes(w) == 1)
+ return (-1);
+
+ if (w->active != wp)
+ window_set_active_pane(w, wp);
+
+ TAILQ_FOREACH(wp1, &w->panes, entry) {
+ wp1->saved_layout_cell = wp1->layout_cell;
+ wp1->layout_cell = NULL;
+ }
+
+ w->saved_layout_root = w->layout_root;
+ layout_init(w, wp);
+ w->flags |= WINDOW_ZOOMED;
+
+ return (0);
+}
+
+int
+window_unzoom(struct window *w)
+{
+ struct window_pane *wp, *wp1;
+
+ if (!(w->flags & WINDOW_ZOOMED))
+ return (-1);
+ wp = w->active;
+
+ w->flags &= ~WINDOW_ZOOMED;
+ layout_free(w);
+ w->layout_root = w->saved_layout_root;
+
+ TAILQ_FOREACH(wp1, &w->panes, entry) {
+ wp1->layout_cell = wp1->saved_layout_cell;
+ wp1->saved_layout_cell = NULL;
+ }
+ layout_fix_panes(w, w->sx, w->sy);
+
+ return (0);
+}
+
struct window_pane *
window_add_pane(struct window *w, u_int hlimit)
{
@@ -585,6 +651,8 @@ window_printable_flags(struct session *s, struct winlink *wl)
flags[pos++] = '*';
if (wl == TAILQ_FIRST(&s->lastw))
flags[pos++] = '-';
+ if (wl->window->flags & WINDOW_ZOOMED)
+ flags[pos++] = 'Z';
if (pos == 0)
flags[pos++] = ' ';
flags[pos] = '\0';
@@ -701,6 +769,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
wp->cwd = xstrdup(cwd);
}
+ log_debug("spawn: %s -- %s", wp->shell, wp->cmd);
+
memset(&ws, 0, sizeof ws);
ws.ws_col = screen_size_x(&wp->base);
ws.ws_row = screen_size_y(&wp->base);
@@ -803,7 +873,6 @@ window_pane_timer_callback(unused int fd, unused short events, void *data)
wp->changes = 0;
}
-/* ARGSUSED */
void
window_pane_read_callback(unused struct bufferevent *bufev, void *data)
{
@@ -830,7 +899,6 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data)
fatal("gettimeofday failed.");
}
-/* ARGSUSED */
void
window_pane_error_callback(
unused struct bufferevent *bufev, unused short what, void *data)
@@ -843,32 +911,16 @@ window_pane_error_callback(
void
window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{
- struct winsize ws;
-
if (sx == wp->sx && sy == wp->sy)
return;
wp->sx = sx;
wp->sy = sy;
- memset(&ws, 0, sizeof ws);
- ws.ws_col = sx;
- ws.ws_row = sy;
-
screen_resize(&wp->base, sx, sy, wp->saved_grid == NULL);
if (wp->mode != NULL)
wp->mode->resize(wp, sx, sy);
- if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
-#ifdef __sun
- /*
- * Some versions of Solaris apparently can return an error when
- * resizing; don't know why this happens, can't reproduce on
- * other platforms and ignoring it doesn't seem to cause any
- * issues.
- */
- if (errno != EINVAL)
-#endif
- fatal("ioctl failed");
+ wp->flags |= PANE_RESIZE;
}
/*
@@ -1034,6 +1086,8 @@ window_pane_visible(struct window_pane *wp)
{
struct window *w = wp->window;
+ if (wp->layout_cell == NULL)
+ return (0);
if (wp->xoff >= w->sx || wp->yoff >= w->sy)
return (0);
if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy)
diff --git a/xterm-keys.c b/xterm-keys.c
index f09072c2..8c885875 100644
--- a/xterm-keys.c
+++ b/xterm-keys.c
@@ -87,6 +87,34 @@ const struct xterm_keys_entry xterm_keys_table[] = {
{ KEYC_NPAGE, "\033[6;_~" },
{ KEYC_IC, "\033[2;_~" },
{ KEYC_DC, "\033[3;_~" },
+
+ { '!', "\033[27;_;33~" },
+ { '#', "\033[27;_;35~" },
+ { '(', "\033[27;_;40~" },
+ { ')', "\033[27;_;41~" },
+ { '+', "\033[27;_;43~" },
+ { ',', "\033[27;_;44~" },
+ { '-', "\033[27;_;45~" },
+ { '.', "\033[27;_;46~" },
+ { '0', "\033[27;_;48~" },
+ { '1', "\033[27;_;49~" },
+ { '2', "\033[27;_;50~" },
+ { '3', "\033[27;_;51~" },
+ { '4', "\033[27;_;52~" },
+ { '5', "\033[27;_;53~" },
+ { '6', "\033[27;_;54~" },
+ { '7', "\033[27;_;55~" },
+ { '8', "\033[27;_;56~" },
+ { '9', "\033[27;_;57~" },
+ { ':', "\033[27;_;58~" },
+ { ';', "\033[27;_;59~" },
+ { '<', "\033[27;_;60~" },
+ { '=', "\033[27;_;61~" },
+ { '>', "\033[27;_;62~" },
+ { '?', "\033[27;_;63~" },
+ { '\'', "\033[27;_;39~" },
+ { '\r', "\033[27;_;13~" },
+ { '\t', "\033[27;_;9~" },
};
/*