Discussion:
[PATCH V5 2/3] Add hooks infrastructure
Thomas Adam
2015-01-27 15:44:17 UTC
Permalink
Define a structure for holding hook information, as well as set/show hook
commands.
---
Makefile.am | 3 ++
cmd-set-hook.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++
cmd-show-hooks.c | 62 ++++++++++++++++++++++++++++++
cmd.c | 2 +
hooks.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
session.c | 2 +
tmux.c | 2 +
tmux.h | 27 ++++++++++++++
8 files changed, 305 insertions(+)
create mode 100644 cmd-set-hook.c
create mode 100644 cmd-show-hooks.c
create mode 100644 hooks.c

diff --git a/Makefile.am b/Makefile.am
index 071c3a1..7739f24 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -118,8 +118,10 @@ dist_tmux_SOURCES = \
cmd-send-keys.c \
cmd-set-buffer.c \
cmd-set-environment.c \
+ cmd-set-hook.c \
cmd-set-option.c \
cmd-show-environment.c \
+ cmd-show-hooks.c \
cmd-show-messages.c \
cmd-show-options.c \
cmd-source-file.c \
@@ -139,6 +141,7 @@ dist_tmux_SOURCES = \
grid-cell.c \
grid-view.c \
grid.c \
+ hooks.c \
input-keys.c \
input.c \
job.c \
diff --git a/cmd-set-hook.c b/cmd-set-hook.c
new file mode 100644
index 0000000..75aebb9
--- /dev/null
+++ b/cmd-set-hook.c
@@ -0,0 +1,95 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <***@xteddy.org>
+ *
+ * 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"
+
+/*
+ * Set a global or session hook.
+ */
+
+enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmd_q *);
+void cmd_set_hook_prepare(struct cmd *, struct cmd_q *);
+
+const struct cmd_entry cmd_set_hook_entry = {
+ "set-hook", NULL,
+ "gt:u", 1, 2,
+ "[-gu]" CMD_TARGET_SESSION_USAGE " hook-name [command]",
+ CMD_PREPARESESSION,
+ cmd_set_hook_exec,
+ NULL
+};
+
+enum cmd_retval
+cmd_set_hook_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ struct session *s;
+ struct cmd_list *cmdlist;
+ struct hooks *hooks;
+ struct hook *hook;
+ char *cause;
+ const char *name, *cmd;
+
+ s = cmdq->state.s;
+ if (s == NULL || args_has(args, 'g'))
+ hooks = &global_hooks;
+ else
+ hooks = &s->hooks;
+
+ name = args->argv[0];
+ if (*name == '\0') {
+ cmdq_error(cmdq, "invalid hook name");
+ return (CMD_RETURN_ERROR);
+ }
+ if (args->argc < 2)
+ cmd = NULL;
+ else
+ cmd = args->argv[1];
+
+ if (args_has(args, 'u')) {
+ if (cmd != NULL) {
+ cmdq_error(cmdq, "command passed to unset hook: %s",
+ name);
+ return (CMD_RETURN_ERROR);
+ }
+ if ((hook = hooks_find(hooks, name)) != NULL)
+ hooks_remove(hooks, hook);
+ return (CMD_RETURN_NORMAL);
+ }
+
+ if (cmd == NULL) {
+ cmdq_error(cmdq, "no command to set hook: %s", name);
+ return (CMD_RETURN_ERROR);
+ }
+ if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
+ if (cause != NULL) {
+ cmdq_error(cmdq, "%s", cause);
+ free(cause);
+ }
+ return (CMD_RETURN_ERROR);
+ }
+ hooks_add(hooks, name, cmdlist);
+ cmd_list_free(cmdlist);
+
+ return (CMD_RETURN_NORMAL);
+}
diff --git a/cmd-show-hooks.c b/cmd-show-hooks.c
new file mode 100644
index 0000000..4babd76
--- /dev/null
+++ b/cmd-show-hooks.c
@@ -0,0 +1,62 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <***@xteddy.org>
+ *
+ * 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"
+
+/*
+ * Show global or session hooks.
+ */
+
+enum cmd_retval cmd_show_hooks_exec(struct cmd *, struct cmd_q *);
+
+const struct cmd_entry cmd_show_hooks_entry = {
+ "show-hooks", NULL,
+ "gt:", 0, 1,
+ "[-g] " CMD_TARGET_SESSION_USAGE,
+ CMD_PREPARESESSION,
+ cmd_show_hooks_exec,
+ NULL
+};
+
+enum cmd_retval
+cmd_show_hooks_exec(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ struct session *s;
+ struct hooks *hooks;
+ struct hook *hook;
+ char tmp[BUFSIZ];
+ size_t used;
+
+ if ((s = cmdq->state.s) == NULL)
+ return (CMD_RETURN_ERROR);
+ hooks = args_has(args, 'g') ? &global_hooks : &s->hooks;
+
+ RB_FOREACH(hook, hooks_tree, &hooks->tree) {
+ used = xsnprintf(tmp, sizeof tmp, "%s -> ", hook->name);
+ cmd_list_print(hook->cmdlist, tmp + used, (sizeof tmp) - used);
+ cmdq_print(cmdq, "%s", tmp);
+ }
+
+ return (CMD_RETURN_NORMAL);
+}
diff --git a/cmd.c b/cmd.c
index 66716bd..205b241 100644
--- a/cmd.c
+++ b/cmd.c
@@ -95,10 +95,12 @@ const struct cmd_entry *cmd_table[] = {
&cmd_server_info_entry,
&cmd_set_buffer_entry,
&cmd_set_environment_entry,
+ &cmd_set_hook_entry,
&cmd_set_option_entry,
&cmd_set_window_option_entry,
&cmd_show_buffer_entry,
&cmd_show_environment_entry,
+ &cmd_show_hooks_entry,
&cmd_show_messages_entry,
&cmd_show_options_entry,
&cmd_show_window_options_entry,
diff --git a/hooks.c b/hooks.c
new file mode 100644
index 0000000..c41a5e3
--- /dev/null
+++ b/hooks.c
@@ -0,0 +1,112 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2012 Thomas Adam <***@xteddy.org>
+ *
+ * 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"
+
+RB_GENERATE(hooks_tree, hook, entry, hooks_cmp);
+
+struct hook *hooks_find1(struct hooks *, const char *);
+
+int
+hooks_cmp(struct hook *hook1, struct hook *hook2)
+{
+ return (strcmp(hook1->name, hook2->name));
+}
+
+void
+hooks_init(struct hooks *hooks, struct hooks *parent)
+{
+ RB_INIT(&hooks->tree);
+ hooks->parent = parent;
+}
+
+void
+hooks_free(struct hooks *hooks)
+{
+ struct hook *hook, *hook1;
+
+ RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1)
+ hooks_remove(hooks, hook);
+}
+
+void
+hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist)
+{
+ struct hook *hook;
+
+ if ((hook = hooks_find1(hooks, name)) != NULL)
+ hooks_remove(hooks, hook);
+
+ hook = xcalloc(1, sizeof *hook);
+ hook->name = xstrdup(name);
+ hook->cmdlist = cmdlist;
+ hook->cmdlist->references++;
+
+ RB_INSERT(hooks_tree, &hooks->tree, hook);
+}
+
+void
+hooks_remove(struct hooks *hooks, struct hook *hook)
+{
+ RB_REMOVE(hooks_tree, &hooks->tree, hook);
+ cmd_list_free(hook->cmdlist);
+ free((char *) hook->name);
+ free(hook);
+}
+
+struct hook *
+hooks_find1(struct hooks *hooks, const char *name)
+{
+ struct hook hook;
+
+ hook.name = name;
+ return (RB_FIND(hooks_tree, &hooks->tree, &hook));
+}
+
+struct hook *
+hooks_find(struct hooks *hooks, const char *name)
+{
+ struct hook hook0, *hook;
+
+ hook0.name = name;
+ hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
+ while (hook == NULL) {
+ hooks = hooks->parent;
+ if (hooks == NULL)
+ break;
+ hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
+ }
+ return (hook);
+}
+
+void
+hooks_run(struct hook *hook, struct cmd_q *cmdq)
+{
+ struct cmd *cmd;
+
+ TAILQ_FOREACH(cmd, &hook->cmdlist->list, qentry) {
+ cmd_prepare(cmd, cmdq);
+ /* TA: FIXME: How do we handle errors here, if at all??? */
+ cmd->entry->exec(cmd, cmdq);
+ }
+}
diff --git a/session.c b/session.c
index 3ac9fb2..4453164 100644
--- a/session.c
+++ b/session.c
@@ -105,6 +105,7 @@ session_create(const char *name, int argc, char **argv, const char *path,
TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);

+ hooks_init(&s->hooks, &global_hooks);
options_init(&s->options, &global_s_options);
environ_init(&s->environ);
if (env != NULL)
@@ -163,6 +164,7 @@ session_destroy(struct session *s)
session_group_remove(s);
environ_free(&s->environ);
options_free(&s->options);
+ hooks_free(&s->hooks);

while (!TAILQ_EMPTY(&s->lastw))
winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw));
diff --git a/tmux.c b/tmux.c
index 5a1988e..36ca7a8 100644
--- a/tmux.c
+++ b/tmux.c
@@ -39,6 +39,7 @@ struct options global_options; /* server options */
struct options global_s_options; /* session options */
struct options global_w_options; /* window options */
struct environ global_environ;
+struct hooks global_hooks;

struct event_base *ev_base;

@@ -289,6 +290,7 @@ main(int argc, char **argv)
flags |= CLIENT_UTF8;
}

+ hooks_init(&global_hooks, NULL);
environ_init(&global_environ);
for (var = environ; *var != NULL; var++)
environ_put(&global_environ, *var);
diff --git a/tmux.h b/tmux.h
index ab191c6..ba79969 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1027,6 +1027,18 @@ struct environ_entry {
};
RB_HEAD(environ, environ_entry);

+/* Hooks. */
+struct hook {
+ const char *name;
+ struct cmd_list *cmdlist;
+ RB_ENTRY(hook) entry;
+};
+
+struct hooks {
+ RB_HEAD(hooks_tree, hook) tree;
+ struct hooks *parent;
+};
+
/* Client session. */
struct session_group {
TAILQ_HEAD(, session) sessions;
@@ -1052,6 +1064,7 @@ struct session {
struct winlink_stack lastw;
struct winlinks windows;

+ struct hooks hooks;
struct options options;

#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
@@ -1503,6 +1516,7 @@ struct options_table_entry {
#define CMD_BUFFER_USAGE "[-b buffer-name]"

/* tmux.c */
+extern struct hooks global_hooks;
extern struct options global_options;
extern struct options global_s_options;
extern struct options global_w_options;
@@ -1551,6 +1565,17 @@ void format_window_pane(struct format_tree *,
void format_paste_buffer(struct format_tree *,
struct paste_buffer *, int);

+/* hooks.c */
+int hooks_cmp(struct hook *, struct hook *);
+RB_PROTOTYPE(hooks_tree, hook, entry, hooks_cmp);
+void hooks_init(struct hooks *, struct hooks *);
+void hooks_free(struct hooks *);
+void hooks_add(struct hooks *, const char *, struct cmd_list *);
+void hooks_copy(struct hooks *, struct hooks *);
+void hooks_remove(struct hooks *, struct hook *);
+void hooks_run(struct hook *, struct cmd_q *);
+struct hook *hooks_find(struct hooks *, const char *);
+
/* mode-key.c */
extern const struct mode_key_table mode_key_tables[];
extern struct mode_key_tree mode_key_tree_vi_edit;
@@ -1828,10 +1853,12 @@ extern const struct cmd_entry cmd_send_prefix_entry;
extern const struct cmd_entry cmd_server_info_entry;
extern const struct cmd_entry cmd_set_buffer_entry;
extern const struct cmd_entry cmd_set_environment_entry;
+extern const struct cmd_entry cmd_set_hook_entry;
extern const struct cmd_entry cmd_set_option_entry;
extern const struct cmd_entry cmd_set_window_option_entry;
extern const struct cmd_entry cmd_show_buffer_entry;
extern const struct cmd_entry cmd_show_environment_entry;
+extern const struct cmd_entry cmd_show_hooks_entry;
extern const struct cmd_entry cmd_show_messages_entry;
extern const struct cmd_entry cmd_show_options_entry;
extern const struct cmd_entry cmd_show_window_options_entry;
--
2.1.4
Thomas Adam
2015-01-27 15:44:16 UTC
Permalink
Commands now set their running context separately from executing. The
state is used at execution time of commands, and by separating this out, the
command state can be queried for any hooked commands.
---
cmd.c | 32 ++++++++++++++++++++++++++++++++
tmux.h | 32 ++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+)

diff --git a/cmd.c b/cmd.c
index eeffe4c..66716bd 100644
--- a/cmd.c
+++ b/cmd.c
@@ -312,6 +312,38 @@ usage:
return (NULL);
}

+void
+cmd_prepare(struct cmd *cmd, struct cmd_q *cmdq)
+{
+ struct args *args = cmd->args;
+ const char *tflag = args_get(args, 't');
+ struct cmd_state *state = &cmdq->state;
+
+ /* FIXME: Handle this! What should happen during cfg_load? */
+ if (cfg_finished == 0)
+ return;
+
+ /*
+ * Prepare the context for the command. It might be the case that a
+ * hooked command is being called. If this command doesn't have a
+ * tflag, use the same one as the command being hooked.
+ */
+ if (tflag == NULL && cmdq->state.prior_tflag != NULL)
+ tflag = state->prior_tflag;
+
+ if (cmd->entry->flags & CMD_PREPARESESSION)
+ state->s = cmd_find_session(cmdq, tflag, 0);
+ if (cmd->entry->flags & CMD_PREPAREWINDOW)
+ state->wl = cmd_find_window(cmdq, tflag, NULL);
+ if (cmd->entry->flags & CMD_PREPAREPANE)
+ state->wl = cmd_find_pane(cmdq, tflag, &state->s, &state->wp);
+ if (cmd->entry->flags & CMD_PREPARECLIENT)
+ state->c = cmd_find_client(cmdq, tflag, 0);
+
+ if (cmd->entry->prepare != NULL)
+ cmd->entry->prepare(cmd, cmdq);
+}
+
size_t
cmd_print(struct cmd *cmd, char *buf, size_t len)
{
diff --git a/tmux.h b/tmux.h
index 8fbda56..ab191c6 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1347,6 +1347,31 @@ struct args {
char **argv;
};

+/* Context for a command about to be executed. */
+struct cmd_state {
+ struct client *c;
+
+ struct session *s;
+ struct session *s2;
+
+ struct winlink *wl;
+ struct winlink *wl2;
+
+ struct window *w;
+ struct window *w2;
+
+ struct window_pane *wp;
+ struct window_pane *wp2;
+
+ int idx;
+
+ const char *tflag;
+ const char *sflag;
+
+ const char *prior_tflag;
+ const char *prior_sflag;
+};
+
/* Command and list of commands. */
struct cmd {
const struct cmd_entry *entry;
@@ -1391,6 +1416,7 @@ struct cmd_q {
struct cmd_q_items queue;
struct cmd_q_item *item;
struct cmd *cmd;
+ struct cmd_state state;

time_t time;
u_int number;
@@ -1415,9 +1441,14 @@ struct cmd_entry {
#define CMD_STARTSERVER 0x1
#define CMD_CANTNEST 0x2
#define CMD_READONLY 0x4
+#define CMD_PREPARESESSION 0x8
+#define CMD_PREPAREWINDOW 0x10
+#define CMD_PREPAREPANE 0x20
+#define CMD_PREPARECLIENT 0x40
int flags;

enum cmd_retval (*exec)(struct cmd *, struct cmd_q *);
+ void (*prepare)(struct cmd *, struct cmd_q *);
};

/* Key binding. */
@@ -1713,6 +1744,7 @@ char **cmd_copy_argv(int, char **);
void cmd_free_argv(int, char **);
char *cmd_stringify_argv(int, char **);
struct cmd *cmd_parse(int, char **, const char *, u_int, char **);
+void cmd_prepare(struct cmd *, struct cmd_q *);
size_t cmd_print(struct cmd *, char *, size_t);
struct session *cmd_current_session(struct cmd_q *, int);
struct client *cmd_current_client(struct cmd_q *);
--
2.1.4
Thomas Adam
2015-01-27 15:44:18 UTC
Permalink
Switch over all tmux commands to make use of prepare.
---
cmd-attach-session.c | 11 +++++++---
cmd-bind-key.c | 3 ++-
cmd-break-pane.c | 9 +++++---
cmd-capture-pane.c | 7 +++---
cmd-choose-buffer.c | 9 ++++----
cmd-choose-client.c | 10 +++++----
cmd-choose-tree.c | 22 ++++++++++++-------
cmd-clear-history.c | 11 +++++-----
cmd-clock-mode.c | 10 ++++-----
cmd-command-prompt.c | 7 +++---
cmd-confirm-before.c | 7 +++---
cmd-copy-mode.c | 8 +++----
cmd-delete-buffer.c | 3 ++-
cmd-detach-client.c | 28 +++++++++++++++++-------
cmd-display-message.c | 42 ++++++++++++++++++++++++-----------
cmd-display-panes.c | 10 ++++-----
cmd-find-window.c | 9 ++++----
cmd-has-session.c | 11 +++++-----
cmd-if-shell.c | 34 ++++++++++++++++++++---------
cmd-join-pane.c | 31 +++++++++++++++++++-------
cmd-kill-pane.c | 10 +++++----
cmd-kill-server.c | 6 +++--
cmd-kill-session.c | 8 ++++---
cmd-kill-window.c | 12 +++++-----
cmd-list-buffers.c | 3 ++-
cmd-list-clients.c | 14 +++++-------
cmd-list-keys.c | 6 +++--
cmd-list-panes.c | 25 ++++++++++++++++-----
cmd-list-sessions.c | 3 ++-
cmd-list-windows.c | 18 +++++++++++----
cmd-load-buffer.c | 3 ++-
cmd-lock-server.c | 28 +++++++++++++++++-------
cmd-move-window.c | 33 ++++++++++++++++++++++------
cmd-new-session.c | 6 +++--
cmd-new-window.c | 25 ++++++++++++++++-----
cmd-paste-buffer.c | 10 +++++----
cmd-pipe-pane.c | 8 ++++---
cmd-queue.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++
cmd-refresh-client.c | 7 +++---
cmd-rename-session.c | 8 ++++---
cmd-rename-window.c | 9 ++++----
cmd-resize-pane.c | 8 ++++---
cmd-respawn-pane.c | 9 +++++---
cmd-respawn-window.c | 8 ++++---
cmd-rotate-window.c | 8 +++----
cmd-run-shell.c | 17 ++++++---------
cmd-save-buffer.c | 6 +++--
cmd-select-layout.c | 17 +++++++++------
cmd-select-pane.c | 31 ++++++++++++++++++++------
cmd-select-window.c | 52 +++++++++++++++++++++++++++++++++-----------
cmd-send-keys.c | 15 ++++++++-----
cmd-set-buffer.c | 3 ++-
cmd-set-environment.c | 8 ++++---
cmd-set-option.c | 6 +++--
cmd-show-environment.c | 8 ++++---
cmd-show-messages.c | 12 +++++-----
cmd-show-options.c | 28 ++++++++++++++++++------
cmd-source-file.c | 3 ++-
cmd-split-window.c | 13 +++++++----
cmd-swap-pane.c | 9 ++++----
cmd-swap-window.c | 27 ++++++++++++++++-------
cmd-switch-client.c | 20 ++++++++++++++---
cmd-unbind-key.c | 3 ++-
cmd-wait-for.c | 3 ++-
64 files changed, 620 insertions(+), 277 deletions(-)

diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index 160f2a8..6a469a9 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -31,13 +31,15 @@
*/

enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *);
+void cmd_attach_session_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_attach_session_entry = {
"attach-session", "attach",
"c:drt:", 0, 0,
"[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
- CMD_CANTNEST|CMD_STARTSERVER,
- cmd_attach_session_exec
+ CMD_CANTNEST|CMD_STARTSERVER|CMD_PREPARESESSION,
+ cmd_attach_session_exec,
+ NULL
};

enum cmd_retval
@@ -76,6 +78,9 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
if (w != NULL)
wl = winlink_find_by_window(&s->windows, w);
}
+ /* TA: Likely broken! */
+ if ((s = cmdq->state.s) == NULL)
+ return (CMD_RETURN_ERROR);

if (cmdq->client == NULL)
return (CMD_RETURN_NORMAL);
@@ -190,5 +195,5 @@ 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'), args_get(args, 'c')));
+ args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c')));
}
diff --git a/cmd-bind-key.c b/cmd-bind-key.c
index 5d68d48..6eda84d 100644
--- a/cmd-bind-key.c
+++ b/cmd-bind-key.c
@@ -36,7 +36,8 @@ const struct cmd_entry cmd_bind_key_entry = {
"cnrt:", 1, -1,
"[-cnr] [-t mode-table] key command [arguments]",
0,
- cmd_bind_key_exec
+ cmd_bind_key_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-break-pane.c b/cmd-break-pane.c
index 0025167..c2f2ea1 100644
--- a/cmd-break-pane.c
+++ b/cmd-break-pane.c
@@ -34,8 +34,9 @@ const struct cmd_entry cmd_break_pane_entry = {
"break-pane", "breakp",
"dPF:t:", 0, 0,
"[-dP] [-F format] " CMD_TARGET_PANE_USAGE,
- 0,
- cmd_break_pane_exec
+ CMD_PREPAREPANE,
+ cmd_break_pane_exec,
+ NULL
};

enum cmd_retval
@@ -54,8 +55,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq)
const char *template;
char *cp;

- if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
+ wp = cmdq->state.wp;
+ s = cmdq->state.s;

if (window_count_panes(wl->window) == 1) {
cmdq_error(cmdq, "can't break with only one pane");
diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c
index ce60b4c..74a2dc1 100644
--- a/cmd-capture-pane.c
+++ b/cmd-capture-pane.c
@@ -40,8 +40,9 @@ const struct cmd_entry cmd_capture_pane_entry = {
"ab:CeE:JpPqS:t:", 0, 0,
"[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] [-S start-line]"
CMD_TARGET_PANE_USAGE,
- 0,
- cmd_capture_pane_exec
+ CMD_PREPAREPANE,
+ cmd_capture_pane_exec,
+ NULL
};

char *
@@ -178,7 +179,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
const char *bufname;
size_t len;

- if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
+ if ((wp = cmdq->state.wp) == NULL)
return (CMD_RETURN_ERROR);

len = 0;
diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index 19f5fba..674ad82 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -36,8 +36,9 @@ const struct cmd_entry cmd_choose_buffer_entry = {
"choose-buffer", NULL,
"F:t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
- 0,
- cmd_choose_buffer_exec
+ CMD_PREPAREWINDOW,
+ cmd_choose_buffer_exec,
+ NULL
};

enum cmd_retval
@@ -53,7 +54,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
u_int idx;
int utf8flag;

- if ((c = cmd_current_client(cmdq)) == NULL) {
+ if ((c = cmdq->state.c) == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
@@ -61,7 +62,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
if ((template = args_get(args, 'F')) == NULL)
template = CHOOSE_BUFFER_TEMPLATE;

- if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
utf8flag = options_get_number(&wl->window->options, "utf8");

diff --git a/cmd-choose-client.c b/cmd-choose-client.c
index 5a1892f..f3237b2 100644
--- a/cmd-choose-client.c
+++ b/cmd-choose-client.c
@@ -34,6 +34,7 @@
"(last used #{client_activity_string})"

enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *);
+void cmd_choose_client_prepare(struct cmd *, struct cmd_q *);

void cmd_choose_client_callback(struct window_choose_data *);

@@ -41,8 +42,9 @@ const struct cmd_entry cmd_choose_client_entry = {
"choose-client", NULL,
"F:t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
- 0,
- cmd_choose_client_exec
+ CMD_PREPAREWINDOW,
+ cmd_choose_client_exec,
+ NULL
};

struct cmd_choose_client_data {
@@ -61,12 +63,12 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq)
char *action;
u_int i, idx, cur;

- if ((c = cmd_current_client(cmdq)) == NULL) {
+ if ((c = cmdq->state.c) == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}

- if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);

if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c
index 823d042..4be9f6c 100644
--- a/cmd-choose-tree.c
+++ b/cmd-choose-tree.c
@@ -48,24 +48,27 @@ const struct cmd_entry cmd_choose_tree_entry = {
"S:W:swub:c:t:", 0, 1,
"[-suw] [-b session-template] [-c window template] [-S format] " \
"[-W format] " CMD_TARGET_WINDOW_USAGE,
- 0,
- cmd_choose_tree_exec
+ CMD_PREPAREWINDOW,
+ cmd_choose_tree_exec,
+ NULL
};

const struct cmd_entry cmd_choose_session_entry = {
"choose-session", NULL,
"F:t:", 0, 1,
CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
- 0,
- cmd_choose_tree_exec
+ CMD_PREPAREWINDOW,
+ cmd_choose_tree_exec,
+ NULL
};

const struct cmd_entry cmd_choose_window_entry = {
"choose-window", NULL,
"F:t:", 0, 1,
CMD_TARGET_WINDOW_USAGE "[-F format] [template]",
- 0,
- cmd_choose_tree_exec
+ CMD_PREPAREWINDOW,
+ cmd_choose_tree_exec,
+ NULL
};

enum cmd_retval
@@ -87,12 +90,15 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq)
ses_template = win_template = NULL;
ses_action = win_action = NULL;

- if ((c = cmd_current_client(cmdq)) == NULL) {
+ if ((c = cmdq->state.c) == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}

- if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
+ if ((s = cmdq->state.c->session) == NULL)
+ return (CMD_RETURN_ERROR);
+
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);

if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
diff --git a/cmd-clear-history.c b/cmd-clear-history.c
index e134288..e345238 100644
--- a/cmd-clear-history.c
+++ b/cmd-clear-history.c
@@ -25,23 +25,24 @@
*/

enum cmd_retval cmd_clear_history_exec(struct cmd *, struct cmd_q *);
+void cmd_clear_history_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_clear_history_entry = {
"clear-history", "clearhist",
"t:", 0, 0,
CMD_TARGET_PANE_USAGE,
- 0,
- cmd_clear_history_exec
+ CMD_PREPAREPANE,
+ cmd_clear_history_exec,
+ NULL
};

enum cmd_retval
-cmd_clear_history_exec(struct cmd *self, struct cmd_q *cmdq)
+cmd_clear_history_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
struct window_pane *wp;
struct grid *gd;

- if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
+ if ((wp = cmdq->state.wp) == NULL)
return (CMD_RETURN_ERROR);
gd = wp->base.grid;

diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c
index 8083581..32e8d47 100644
--- a/cmd-clock-mode.c
+++ b/cmd-clock-mode.c
@@ -30,17 +30,17 @@ const struct cmd_entry cmd_clock_mode_entry = {
"clock-mode", NULL,
"t:", 0, 0,
CMD_TARGET_PANE_USAGE,
- 0,
- cmd_clock_mode_exec
+ CMD_PREPAREPANE,
+ cmd_clock_mode_exec,
+ NULL
};

enum cmd_retval
-cmd_clock_mode_exec(struct cmd *self, struct cmd_q *cmdq)
+cmd_clock_mode_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
struct window_pane *wp;

- if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
+ if ((wp = cmdq->state.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 22b1d84..7f66fc4 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -38,8 +38,9 @@ const struct cmd_entry cmd_command_prompt_entry = {
"command-prompt", NULL,
"I:p:t:", 0, 1,
"[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]",
- 0,
- cmd_command_prompt_exec
+ CMD_PREPARECLIENT,
+ cmd_command_prompt_exec,
+ NULL
};

struct cmd_command_prompt_cdata {
@@ -62,7 +63,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_q *cmdq)
char *prompt, *ptr, *input = NULL;
size_t n;

- if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((c = cmdq->state.c) == NULL)
return (CMD_RETURN_ERROR);

if (c->prompt_string != NULL)
diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c
index 0bf5844..d5ecd8b 100644
--- a/cmd-confirm-before.c
+++ b/cmd-confirm-before.c
@@ -37,8 +37,9 @@ const struct cmd_entry cmd_confirm_before_entry = {
"confirm-before", "confirm",
"p:t:", 1, 1,
"[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
- 0,
- cmd_confirm_before_exec
+ CMD_PREPARECLIENT,
+ cmd_confirm_before_exec,
+ NULL
};

struct cmd_confirm_before_data {
@@ -55,7 +56,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_q *cmdq)
char *cmd, *copy, *new_prompt, *ptr;
const char *prompt;

- if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((c = cmdq->state.c) == NULL)
return (CMD_RETURN_ERROR);

if ((prompt = args_get(args, 'p')) != NULL)
diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c
index 8933529..c06967d 100644
--- a/cmd-copy-mode.c
+++ b/cmd-copy-mode.c
@@ -30,17 +30,17 @@ const struct cmd_entry cmd_copy_mode_entry = {
"copy-mode", NULL,
"t:u", 0, 0,
"[-u] " CMD_TARGET_PANE_USAGE,
- 0,
- cmd_copy_mode_exec
+ CMD_PREPAREPANE,
+ cmd_copy_mode_exec,
+ NULL
};

enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
struct window_pane *wp;

- if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
+ if ((wp = cmdq->state.wp) == NULL)
return (CMD_RETURN_ERROR);

if (wp->mode != &window_copy_mode) {
diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c
index 42268b7..a7a6dc7 100644
--- a/cmd-delete-buffer.c
+++ b/cmd-delete-buffer.c
@@ -33,7 +33,8 @@ const struct cmd_entry cmd_delete_buffer_entry = {
"b:", 0, 0,
CMD_BUFFER_USAGE,
0,
- cmd_delete_buffer_exec
+ cmd_delete_buffer_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-detach-client.c b/cmd-detach-client.c
index 600554a..cd11542 100644
--- a/cmd-detach-client.c
+++ b/cmd-detach-client.c
@@ -27,23 +27,37 @@
*/

enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *);
+void cmd_detach_client_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_detach_client_entry = {
"detach-client", "detach",
"as:t:P", 0, 0,
"[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE,
- CMD_READONLY,
- cmd_detach_client_exec
+ CMD_READONLY|CMD_PREPARECLIENT|CMD_PREPARESESSION,
+ cmd_detach_client_exec,
+ cmd_detach_client_prepare
};

const struct cmd_entry cmd_suspend_client_entry = {
"suspend-client", "suspendc",
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
- 0,
- cmd_detach_client_exec
+ CMD_PREPARECLIENT,
+ cmd_detach_client_exec,
+ cmd_detach_client_prepare
};

+void
+cmd_detach_client_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (args_has(args, 's'))
+ cmdq->state.s = cmd_find_session(cmdq, args_get(args, 's'), 0);
+ else
+ cmdq->state.c = cmd_find_client(cmdq, args_get(args, 't'), 0);
+}
+
enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -68,8 +82,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
msgtype = MSG_DETACH;

if (args_has(args, 's')) {
- s = cmd_find_session(cmdq, args_get(args, 's'), 0);
- if (s == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);

for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -80,8 +93,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
strlen(c->session->name) + 1);
}
} else {
- c = cmd_find_client(cmdq, args_get(args, 't'), 0);
- if (c == NULL)
+ if ((c = cmdq->state.c) == NULL)
return (CMD_RETURN_ERROR);

if (args_has(args, 'a')) {
diff --git a/cmd-display-message.c b/cmd-display-message.c
index f3547b0..226d159 100644
--- a/cmd-display-message.c
+++ b/cmd-display-message.c
@@ -33,16 +33,37 @@
"- (%H:%M %d-%b-%y)"

enum cmd_retval cmd_display_message_exec(struct cmd *, struct cmd_q *);
+void cmd_display_message_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_display_message_entry = {
"display-message", "display",
"c:pt:F:", 0, 1,
"[-p] [-c target-client] [-F format] " CMD_TARGET_PANE_USAGE
" [message]",
- 0,
- cmd_display_message_exec
+ CMD_PREPAREWINDOW|CMD_PREPARECLIENT,
+ cmd_display_message_exec,
+ cmd_display_message_prepare
};

+void
+cmd_display_message_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (args_has(args, 't')) {
+ cmdq->state.wl = cmd_find_pane(cmdq, args_get(args, 't'),
+ &cmdq->state.s, &cmdq->state.wp);
+ } else {
+ cmdq->state.wl = cmd_find_pane(cmdq, NULL, &cmdq->state.s,
+ &cmdq->state.wp);
+ }
+
+ if (args_has(args, 'c'))
+ cmdq->state.c = cmd_find_client(cmdq, args_get(args, 'c'), 0);
+ else
+ cmdq->state.c = cmd_current_client(cmdq);
+}
+
enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -58,27 +79,22 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
time_t t;
size_t len;

- if (args_has(args, 't')) {
- wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
- if (wl == NULL)
- return (CMD_RETURN_ERROR);
- } else {
- wl = cmd_find_pane(cmdq, NULL, &s, &wp);
- if (wl == NULL)
- return (CMD_RETURN_ERROR);
- }
+ if ((wl = cmdq->state.wl) == NULL)
+ return (CMD_RETURN_ERROR);
+
+ wp = cmdq->state.wp;
+ s = cmdq->state.s;

if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(cmdq, "only one of -F or argument must be given");
return (CMD_RETURN_ERROR);
}

+ c = cmdq->state.c;
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);
diff --git a/cmd-display-panes.c b/cmd-display-panes.c
index 9ce8971..8b9cf58 100644
--- a/cmd-display-panes.c
+++ b/cmd-display-panes.c
@@ -30,17 +30,17 @@ const struct cmd_entry cmd_display_panes_entry = {
"display-panes", "displayp",
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
- 0,
- cmd_display_panes_exec
+ CMD_PREPARECLIENT,
+ cmd_display_panes_exec,
+ NULL
};

enum cmd_retval
-cmd_display_panes_exec(struct cmd *self, struct cmd_q *cmdq)
+cmd_display_panes_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
struct client *c;

- if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((c = cmdq->state.c) == NULL)
return (CMD_RETURN_ERROR);

server_set_identify(c);
diff --git a/cmd-find-window.c b/cmd-find-window.c
index 88e4879..7273633 100644
--- a/cmd-find-window.c
+++ b/cmd-find-window.c
@@ -51,8 +51,9 @@ const struct cmd_entry cmd_find_window_entry = {
"find-window", "findw",
"F:CNt:T", 1, 4,
"[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string",
- 0,
- cmd_find_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_find_window_exec,
+ NULL
};

struct cmd_find_window_data {
@@ -143,13 +144,13 @@ cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
const char *template;
u_int i, match_flags;

- if ((c = cmd_current_client(cmdq)) == NULL) {
+ if ((c = cmdq->state.c) == NULL) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
s = c->session;

- if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);

if ((template = args_get(args, 'F')) == NULL)
diff --git a/cmd-has-session.c b/cmd-has-session.c
index a873b20..78a62f7 100644
--- a/cmd-has-session.c
+++ b/cmd-has-session.c
@@ -30,16 +30,15 @@ const struct cmd_entry cmd_has_session_entry = {
"has-session", "has",
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
- 0,
- cmd_has_session_exec
+ CMD_PREPAREWINDOW,
+ cmd_has_session_exec,
+ NULL
};

enum cmd_retval
-cmd_has_session_exec(struct cmd *self, struct cmd_q *cmdq)
+cmd_has_session_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
-
- if (cmd_find_session(cmdq, args_get(args, 't'), 0) == NULL)
+ if (cmdq->state.s == NULL)
return (CMD_RETURN_ERROR);

return (CMD_RETURN_NORMAL);
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 1543291..29783a8 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -30,6 +30,7 @@
*/

enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmd_q *);
+void cmd_if_shell_prepare(struct cmd *, struct cmd_q *);

void cmd_if_shell_callback(struct job *);
void cmd_if_shell_done(struct cmd_q *);
@@ -40,7 +41,8 @@ const struct cmd_entry cmd_if_shell_entry = {
"bFt:", 2, 3,
"[-bF] " CMD_TARGET_PANE_USAGE " shell-command command [command]",
0,
- cmd_if_shell_exec
+ cmd_if_shell_exec,
+ NULL
};

struct cmd_if_shell_data {
@@ -51,6 +53,18 @@ struct cmd_if_shell_data {
int started;
};

+void
+cmd_if_shell_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (args_has(args, 't')) {
+ cmdq->state.wl = cmd_find_pane(cmdq, args_get(args, 't'),
+ &cmdq->state.s, &cmdq->state.wp);
+ } else
+ cmdq->state.c = cmd_find_client(cmdq, NULL, 1);
+}
+
enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -64,15 +78,15 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
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);
- else {
- c = cmd_find_client(cmdq, NULL, 1);
- if (c != NULL && c->session != NULL) {
- s = c->session;
- wl = s->curw;
- wp = wl->window->active;
- }
+ wl = cmdq->state.wl;
+ s = cmdq->state.s;
+ wp = cmdq->state.wp;
+ c = cmdq->state.c;
+
+ if (!args_has(args, 't') && c != NULL && c->session != NULL) {
+ s = c->session;
+ wl = s->curw;
+ wp = wl->window->active;
}

ft = format_create();
diff --git a/cmd-join-pane.c b/cmd-join-pane.c
index 5603541..a6be1bf 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -29,6 +29,7 @@
*/

enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmd_q *);
+void cmd_join_pane_prepare(struct cmd *, struct cmd_q *);

enum cmd_retval join_pane(struct cmd *, struct cmd_q *, int);

@@ -36,18 +37,31 @@ const struct cmd_entry cmd_join_pane_entry = {
"join-pane", "joinp",
"bdhvp:l:s:t:", 0, 0,
"[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
- 0,
- cmd_join_pane_exec
+ CMD_PREPAREPANE,
+ cmd_join_pane_exec,
+ cmd_join_pane_prepare
};

const struct cmd_entry cmd_move_pane_entry = {
"move-pane", "movep",
"bdhvp:l:s:t:", 0, 0,
"[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
- 0,
- cmd_join_pane_exec
+ CMD_PREPAREWINDOW,
+ cmd_join_pane_exec,
+ cmd_join_pane_prepare
};

+
+void
+cmd_join_pane_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ cmdq->state.wl = cmd_find_pane(cmdq, args_get(args, 't'),
+ &cmdq->state.s, &cmdq->state.wp);
+ cmdq->state.wl2 = cmd_find_pane(cmdq, args_get(args, 's'), NULL,
+ &cmdq->state.wp2);
+}
enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -67,16 +81,17 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
enum layout_type type;
struct layout_cell *lc;

- dst_wl = cmd_find_pane(cmdq, args_get(args, 't'), &dst_s, &dst_wp);
- if (dst_wl == NULL)
+ if ((dst_wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
+ dst_s = cmdq->state.s;
+ dst_wp = cmdq->state.wp;
dst_w = dst_wl->window;
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);

- src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp);
- if (src_wl == NULL)
+ if ((src_wl = cmdq->state.wl2) == NULL)
return (CMD_RETURN_ERROR);
+ src_wp = cmdq->state.wp2;
src_w = src_wl->window;
server_unzoom_window(src_w);

diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c
index f4735fd..26f0e0c 100644
--- a/cmd-kill-pane.c
+++ b/cmd-kill-pane.c
@@ -27,24 +27,26 @@
*/

enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmd_q *);
+void cmd_kill_pane_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_kill_pane_entry = {
"kill-pane", "killp",
"at:", 0, 0,
"[-a] " CMD_TARGET_PANE_USAGE,
- 0,
- cmd_kill_pane_exec
+ CMD_PREPAREPANE,
+ cmd_kill_pane_exec,
+ NULL
};

enum cmd_retval
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(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
+ wp = cmdq->state.wp;
server_unzoom_window(wl->window);

if (window_count_panes(wl->window) == 1) {
diff --git a/cmd-kill-server.c b/cmd-kill-server.c
index 07d9430..930bef5 100644
--- a/cmd-kill-server.c
+++ b/cmd-kill-server.c
@@ -34,7 +34,8 @@ const struct cmd_entry cmd_kill_server_entry = {
"", 0, 0,
"",
0,
- cmd_kill_server_exec
+ cmd_kill_server_exec,
+ NULL
};

const struct cmd_entry cmd_start_server_entry = {
@@ -42,7 +43,8 @@ const struct cmd_entry cmd_start_server_entry = {
"", 0, 0,
"",
CMD_STARTSERVER,
- cmd_kill_server_exec
+ cmd_kill_server_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-kill-session.c b/cmd-kill-session.c
index d7e2a21..3515a67 100644
--- a/cmd-kill-session.c
+++ b/cmd-kill-session.c
@@ -28,13 +28,15 @@
*/

enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *);
+void cmd_kill_session_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_kill_session_entry = {
"kill-session", NULL,
"at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE,
- 0,
- cmd_kill_session_exec
+ CMD_PREPARESESSION,
+ cmd_kill_session_exec,
+ NULL
};

enum cmd_retval
@@ -43,7 +45,7 @@ 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(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);

if (args_has(args, 'a')) {
diff --git a/cmd-kill-window.c b/cmd-kill-window.c
index d402acc..3689440 100644
--- a/cmd-kill-window.c
+++ b/cmd-kill-window.c
@@ -30,8 +30,9 @@ const struct cmd_entry cmd_kill_window_entry = {
"kill-window", "killw",
"at:", 0, 0,
"[-a] " CMD_TARGET_WINDOW_USAGE,
- 0,
- cmd_kill_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_kill_window_exec,
+ NULL
};

const struct cmd_entry cmd_unlink_window_entry = {
@@ -39,7 +40,8 @@ const struct cmd_entry cmd_unlink_window_entry = {
"kt:", 0, 0,
"[-k] " CMD_TARGET_WINDOW_USAGE,
0,
- cmd_kill_window_exec
+ cmd_kill_window_exec,
+ NULL
};

enum cmd_retval
@@ -52,9 +54,10 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct session_group *sg;
u_int references;

- if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;
+ s = cmdq->state.s;

if (self->entry == &cmd_unlink_window_entry) {
sg = session_group_find(s);
@@ -66,7 +69,6 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_q *cmdq)
cmdq_error(cmdq, "window only linked to one session");
return (CMD_RETURN_ERROR);
}
- server_unlink_window(s, wl);
} else {
if (args_has(args, 'a')) {
RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c
index 8eb1610..6c5db2c 100644
--- a/cmd-list-buffers.c
+++ b/cmd-list-buffers.c
@@ -37,7 +37,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
"F:", 0, 0,
"[-F format]",
0,
- cmd_list_buffers_exec
+ cmd_list_buffers_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-list-clients.c b/cmd-list-clients.c
index 292be72..9b51e05 100644
--- a/cmd-list-clients.c
+++ b/cmd-list-clients.c
@@ -39,8 +39,9 @@ const struct cmd_entry cmd_list_clients_entry = {
"list-clients", "lsc",
"F:t:", 0, 0,
"[-F format] " CMD_TARGET_SESSION_USAGE,
- CMD_READONLY,
- cmd_list_clients_exec
+ CMD_READONLY|CMD_PREPARESESSION,
+ cmd_list_clients_exec,
+ NULL
};

enum cmd_retval
@@ -54,12 +55,9 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_q *cmdq)
u_int i;
char *line;

- if (args_has(args, 't')) {
- s = cmd_find_session(cmdq, args_get(args, 't'), 0);
- if (s == NULL)
- return (CMD_RETURN_ERROR);
- } else
- s = NULL;
+ s = cmdq->state.s;
+ if (args_has(args, 't') && s == NULL)
+ return (CMD_RETURN_ERROR);

if ((template = args_get(args, 'F')) == NULL)
template = LIST_CLIENTS_TEMPLATE;
diff --git a/cmd-list-keys.c b/cmd-list-keys.c
index 0733ee2..de8310e 100644
--- a/cmd-list-keys.c
+++ b/cmd-list-keys.c
@@ -36,7 +36,8 @@ const struct cmd_entry cmd_list_keys_entry = {
"t:", 0, 0,
"[-t key-table]",
0,
- cmd_list_keys_exec
+ cmd_list_keys_exec,
+ NULL
};

const struct cmd_entry cmd_list_commands_entry = {
@@ -44,7 +45,8 @@ const struct cmd_entry cmd_list_commands_entry = {
"", 0, 0,
"",
0,
- cmd_list_keys_exec
+ cmd_list_keys_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-list-panes.c b/cmd-list-panes.c
index 7f62177..caeb48e 100644
--- a/cmd-list-panes.c
+++ b/cmd-list-panes.c
@@ -28,6 +28,7 @@
*/

enum cmd_retval cmd_list_panes_exec(struct cmd *, struct cmd_q *);
+void cmd_list_panes_prepare(struct cmd *, struct cmd_q *);

void cmd_list_panes_server(struct cmd *, struct cmd_q *);
void cmd_list_panes_session(
@@ -39,10 +40,24 @@ const struct cmd_entry cmd_list_panes_entry = {
"list-panes", "lsp",
"asF:t:", 0, 0,
"[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
- 0,
- cmd_list_panes_exec
+ CMD_PREPARESESSION|CMD_PREPAREWINDOW,
+ cmd_list_panes_exec,
+ cmd_list_panes_prepare
};

+void
+cmd_list_panes_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (args_has(args, 's'))
+ cmdq->state.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+ else if (args_has(args, 't')) {
+ cmdq->state.wl = cmd_find_window(cmdq, args_get(args, 't'),
+ &cmdq->state.s);
+ }
+}
+
enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -50,16 +65,16 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_q *cmdq)
struct session *s;
struct winlink *wl;

+ s = cmdq->state.s;
+
if (args_has(args, 'a'))
cmd_list_panes_server(self, cmdq);
else if (args_has(args, 's')) {
- s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
cmd_list_panes_session(self, s, cmdq, 1);
} else {
- wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
- if (wl == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
cmd_list_panes_window(self, s, wl, cmdq, 0);
}
diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c
index ea8f3e3..5b4472f 100644
--- a/cmd-list-sessions.c
+++ b/cmd-list-sessions.c
@@ -43,7 +43,8 @@ const struct cmd_entry cmd_list_sessions_entry = {
"F:", 0, 0,
"[-F format]",
0,
- cmd_list_sessions_exec
+ cmd_list_sessions_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-list-windows.c b/cmd-list-windows.c
index 5f73e8d..3cd980c 100644
--- a/cmd-list-windows.c
+++ b/cmd-list-windows.c
@@ -40,6 +40,7 @@
"[#{window_width}x#{window_height}] "

enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmd_q *);
+void cmd_list_windows_prepare(struct cmd *, struct cmd_q *);

void cmd_list_windows_server(struct cmd *, struct cmd_q *);
void cmd_list_windows_session(struct cmd *, struct session *,
@@ -49,10 +50,20 @@ const struct cmd_entry cmd_list_windows_entry = {
"list-windows", "lsw",
"F:at:", 0, 0,
"[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
- 0,
- cmd_list_windows_exec
+ CMD_PREPARESESSION,
+ cmd_list_windows_exec,
+ cmd_list_windows_prepare
};

+void
+cmd_list_windows_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (!args_has(args, 'a'))
+ cmdq->state.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+}
+
enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -62,8 +73,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 'a'))
cmd_list_windows_server(self, cmdq);
else {
- s = cmd_find_session(cmdq, args_get(args, 't'), 0);
- if (s == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);
cmd_list_windows_session(self, s, cmdq, 0);
}
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 785a701..fcf603d 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -39,7 +39,8 @@ const struct cmd_entry cmd_load_buffer_entry = {
"b:", 1, 1,
CMD_BUFFER_USAGE " path",
0,
- cmd_load_buffer_exec
+ cmd_load_buffer_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-lock-server.c b/cmd-lock-server.c
index de76475..4c4ca6e 100644
--- a/cmd-lock-server.c
+++ b/cmd-lock-server.c
@@ -25,13 +25,15 @@
*/

enum cmd_retval cmd_lock_server_exec(struct cmd *, struct cmd_q *);
+void cmd_lock_server_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_lock_server_entry = {
"lock-server", "lock",
"", 0, 0,
"",
0,
- cmd_lock_server_exec
+ cmd_lock_server_exec,
+ cmd_lock_server_prepare,
};

const struct cmd_entry cmd_lock_session_entry = {
@@ -39,7 +41,8 @@ const struct cmd_entry cmd_lock_session_entry = {
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
- cmd_lock_server_exec
+ cmd_lock_server_exec,
+ cmd_lock_server_prepare
};

const struct cmd_entry cmd_lock_client_entry = {
@@ -47,26 +50,35 @@ const struct cmd_entry cmd_lock_client_entry = {
"t:", 0, 0,
CMD_TARGET_CLIENT_USAGE,
0,
- cmd_lock_server_exec
+ cmd_lock_server_exec,
+ cmd_lock_server_prepare
};

+void
+cmd_lock_server_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (self->entry == &cmd_lock_session_entry)
+ cmdq->state.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+ else if (self->entry == &cmd_lock_client_entry)
+ cmdq->state.c = cmd_find_client(cmdq, args_get(args, 't'), 0);
+}
+
enum cmd_retval
cmd_lock_server_exec(struct cmd *self, unused struct cmd_q *cmdq)
{
- struct args *args = self->args;
struct client *c;
struct session *s;

if (self->entry == &cmd_lock_server_entry)
server_lock();
else if (self->entry == &cmd_lock_session_entry) {
- s = cmd_find_session(cmdq, args_get(args, 't'), 0);
- if (s == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);
server_lock_session(s);
} else {
- c = cmd_find_client(cmdq, args_get(args, 't'), 0);
- if (c == NULL)
+ if ((c = cmdq->state.c) == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
diff --git a/cmd-move-window.c b/cmd-move-window.c
index 3064cd6..c32ad64 100644
--- a/cmd-move-window.c
+++ b/cmd-move-window.c
@@ -27,23 +27,41 @@
*/

enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *);
+void cmd_move_window_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_move_window_entry = {
"move-window", "movew",
"dkrs:t:", 0, 0,
"[-dkr] " CMD_SRCDST_WINDOW_USAGE,
0,
- cmd_move_window_exec
+ cmd_move_window_exec,
+ NULL
};

const struct cmd_entry cmd_link_window_entry = {
"link-window", "linkw",
"dks:t:", 0, 0,
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
- 0,
- cmd_move_window_exec
+ CMD_PREPARESESSION|CMD_PREPAREWINDOW,
+ cmd_move_window_exec,
+ cmd_move_window_prepare
};

+void
+cmd_move_window_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (args_has(args, 'r'))
+ cmdq->state.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+ else {
+ cmdq->state.wl = cmd_find_window(cmdq, args_get(args, 's'),
+ &cmdq->state.s);
+ cmdq->state.idx = cmd_find_index(cmdq, args_get(args, 't'),
+ &cmdq->state.s2);
+ }
+}
+
enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -54,8 +72,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
int idx, kflag, dflag;

if (args_has(args, 'r')) {
- s = cmd_find_session(cmdq, args_get(args, 't'), 0);
- if (s == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);

session_renumber_windows(s);
@@ -63,10 +80,12 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)

return (CMD_RETURN_NORMAL);
}
+ src = cmdq->state.s;
+ dst = cmdq->state.s2;

- if ((wl = cmd_find_window(cmdq, args_get(args, 's'), &src)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
- if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &dst)) == -2)
+ if ((idx = cmdq->state.idx) == -2)
return (CMD_RETURN_ERROR);

kflag = args_has(self->args, 'k');
diff --git a/cmd-new-session.c b/cmd-new-session.c
index e244f88..0a05cde 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -42,7 +42,8 @@ const struct cmd_entry cmd_new_session_entry = {
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[-y height] [command]",
CMD_STARTSERVER|CMD_CANTNEST,
- cmd_new_session_exec
+ cmd_new_session_exec,
+ NULL
};

const struct cmd_entry cmd_has_session_entry = {
@@ -50,7 +51,8 @@ const struct cmd_entry cmd_has_session_entry = {
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
0,
- cmd_new_session_exec
+ cmd_new_session_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-new-window.c b/cmd-new-window.c
index 7f14b21..4e222ba 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -32,23 +32,37 @@

#define NEW_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"

-enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *);
+enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *);
+void cmd_new_window_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
"ac:dF:kn:Pt:", 0, -1,
"[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]",
- 0,
- cmd_new_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_new_window_exec,
+ cmd_new_window_prepare
};

+void
+cmd_new_window_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (args_has(args, 'a')) {
+ cmdq->state.wl = cmd_find_window(cmdq, args_get(args, 't'),
+ &cmdq->state.s);
+ } else
+ cmd_find_index(cmdq, args_get(args, 't'), &cmdq->state.s);
+}
+
enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
- struct session *s;
- struct winlink *wl;
+ struct session *s = cmdq->state.s;
+ struct winlink *wl = cmdq->state.wl;
struct client *c;
const char *cmd, *path, *template;
char **argv, *cause, *cp;
@@ -57,7 +71,6 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct environ_entry *envent;

if (args_has(args, 'a')) {
- wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
if (wl == NULL)
return (CMD_RETURN_ERROR);
idx = wl->idx + 1;
diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c
index 5d91aef..c99cb51 100644
--- a/cmd-paste-buffer.c
+++ b/cmd-paste-buffer.c
@@ -36,8 +36,9 @@ const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb",
"db:prs:t:", 0, 0,
"[-dpr] [-s separator] " CMD_BUFFER_USAGE " " CMD_TARGET_PANE_USAGE,
- 0,
- cmd_paste_buffer_exec
+ CMD_PREPAREPANE,
+ cmd_paste_buffer_exec,
+ NULL
};

enum cmd_retval
@@ -45,17 +46,18 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct window_pane *wp;
- struct session *s;
struct paste_buffer *pb;
const char *sepstr, *bufname;

- if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
+ if (cmdq->state.wl == NULL)
return (CMD_RETURN_ERROR);

bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');

+ wp = cmdq->state.wp;
+
if (bufname == NULL)
pb = paste_get_top();
else {
diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c
index 4ab1824..facab6f 100644
--- a/cmd-pipe-pane.c
+++ b/cmd-pipe-pane.c
@@ -39,8 +39,9 @@ const struct cmd_entry cmd_pipe_pane_entry = {
"pipe-pane", "pipep",
"ot:", 0, 1,
"[-o] " CMD_TARGET_PANE_USAGE " [command]",
- 0,
- cmd_pipe_pane_exec
+ CMD_PREPAREPANE,
+ cmd_pipe_pane_exec,
+ NULL
};

enum cmd_retval
@@ -52,8 +53,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
char *command;
int old_fd, pipe_fd[2], null_fd;

- if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
+ if (cmdq->state.wl == NULL)
return (CMD_RETURN_ERROR);
+ wp = cmdq->state.wp;
c = cmd_find_client(cmdq, NULL, 1);

/* Destroy the old pipe. */
diff --git a/cmd-queue.c b/cmd-queue.c
index a98fa9b..12a3fe2 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -21,9 +21,36 @@
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
+#include <string.h>

#include "tmux.h"

+void cmdq_set_state(struct cmd_q *);
+void cmdq_run_hook(struct hooks *, const char *, struct cmd *,
+ struct cmd_q *);
+
+/* Fill in state members. */
+void
+cmdq_set_state(struct cmd_q *cmdq)
+{
+ memset(&cmdq->state, 0, sizeof cmdq->state);
+
+ cmdq->state.c = cmdq->client;
+
+ cmdq->state.s = cmdq->client != NULL ?
+ cmdq->client->session : NULL;
+ cmdq->state.s2 = NULL;
+ cmdq->state.w = NULL;
+ cmdq->state.wl = NULL;
+ cmdq->state.wp = NULL;
+ cmdq->state.tflag = NULL;
+ cmdq->state.sflag = NULL;
+
+ cmd_prepare(cmdq->cmd, cmdq);
+
+ cmdq->state.prior_tflag = args_get(cmdq->cmd->args, 't');
+}
+
/* Create new command queue. */
struct cmd_q *
cmdq_new(struct client *c)
@@ -145,6 +172,20 @@ cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist)
}
}

+/* Run hooks based on the hooks prefix (before/after). */
+void
+cmdq_run_hook(struct hooks *hooks, const char *prefix, struct cmd *cmd,
+ struct cmd_q *cmdq)
+{
+ struct hook *hook;
+ char *s;
+
+ xasprintf(&s, "%s-%s", prefix, cmd->entry->name);
+ if ((hook = hooks_find(hooks, s)) != NULL)
+ hooks_run(hook, cmdq);
+ free(s);
+}
+
/* Add command list to queue. */
void
cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist)
@@ -162,6 +203,7 @@ int
cmdq_continue(struct cmd_q *cmdq)
{
struct cmd_q_item *next;
+ struct hooks *hooks;
enum cmd_retval retval;
int empty, guard, flags;
char s[1024];
@@ -180,6 +222,17 @@ cmdq_continue(struct cmd_q *cmdq)

do {
while (cmdq->cmd != NULL) {
+ /*
+ * Set the execution context for this command. This
+ * then allows for session hooks to be used if this
+ * command has any.
+ */
+ cmdq_set_state(cmdq);
+ if (cmdq->state.s != NULL)
+ hooks = &cmdq->state.s->hooks;
+ else
+ hooks = &global_hooks;
+
cmd_print(cmdq->cmd, s, sizeof s);
log_debug("cmdq %p: %s (client %d)", cmdq, s,
cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
@@ -190,7 +243,13 @@ cmdq_continue(struct cmd_q *cmdq)
flags = !!(cmdq->cmd->flags & CMD_CONTROL);
guard = cmdq_guard(cmdq, "begin", flags);

+ cmdq_run_hook(hooks, "before", cmdq->cmd, cmdq);
+
retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
+ if (retval == CMD_RETURN_ERROR)
+ break;
+
+ cmdq_run_hook(hooks, "after", cmdq->cmd, cmdq);

if (guard) {
if (retval == CMD_RETURN_ERROR)
diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c
index f693872..969605b 100644
--- a/cmd-refresh-client.c
+++ b/cmd-refresh-client.c
@@ -30,8 +30,9 @@ const struct cmd_entry cmd_refresh_client_entry = {
"refresh-client", "refresh",
"C:St:", 0, 0,
"[-S] [-C size] " CMD_TARGET_CLIENT_USAGE,
- 0,
- cmd_refresh_client_exec
+ CMD_PREPARECLIENT,
+ cmd_refresh_client_exec,
+ NULL
};

enum cmd_retval
@@ -42,7 +43,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq)
const char *size;
u_int w, h;

- if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((c = cmdq->state.c) == NULL)
return (CMD_RETURN_ERROR);

if (args_has(args, 'C')) {
diff --git a/cmd-rename-session.c b/cmd-rename-session.c
index 481154c..e44c45b 100644
--- a/cmd-rename-session.c
+++ b/cmd-rename-session.c
@@ -27,13 +27,15 @@
*/

enum cmd_retval cmd_rename_session_exec(struct cmd *, struct cmd_q *);
+void cmd_rename_session_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_rename_session_entry = {
"rename-session", "rename",
"t:", 1, 1,
CMD_TARGET_SESSION_USAGE " new-name",
- 0,
- cmd_rename_session_exec
+ CMD_PREPARESESSION,
+ cmd_rename_session_exec,
+ NULL
};

enum cmd_retval
@@ -53,7 +55,7 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
}

- if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);

RB_REMOVE(sessions, &sessions, s);
diff --git a/cmd-rename-window.c b/cmd-rename-window.c
index 2f677a4..aeee5b9 100644
--- a/cmd-rename-window.c
+++ b/cmd-rename-window.c
@@ -27,23 +27,24 @@
*/

enum cmd_retval cmd_rename_window_exec(struct cmd *, struct cmd_q *);
+void cmd_rename_window_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_rename_window_entry = {
"rename-window", "renamew",
"t:", 1, 1,
CMD_TARGET_WINDOW_USAGE " new-name",
- 0,
- cmd_rename_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_rename_window_exec,
+ NULL
};

enum cmd_retval
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(cmdq, args_get(args, 't'), &s)) == NULL)
+ if ((wl = cmdq->state.wl) == 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 42f0f39..b55b2c3 100644
--- a/cmd-resize-pane.c
+++ b/cmd-resize-pane.c
@@ -32,8 +32,9 @@ const struct cmd_entry cmd_resize_pane_entry = {
"resize-pane", "resizep",
"DLRt:Ux:y:Z", 0, 1,
"[-DLRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]",
- 0,
- cmd_resize_pane_exec
+ CMD_PREPAREPANE,
+ cmd_resize_pane_exec,
+ NULL
};

enum cmd_retval
@@ -48,9 +49,10 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
u_int adjust;
int x, y;

- if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;
+ wp = cmdq->state.wp;

if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED)
diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c
index 4703153..2aaee6b 100644
--- a/cmd-respawn-pane.c
+++ b/cmd-respawn-pane.c
@@ -34,8 +34,9 @@ const struct cmd_entry cmd_respawn_pane_entry = {
"respawn-pane", "respawnp",
"kt:", 0, -1,
"[-k] " CMD_TARGET_PANE_USAGE " [command]",
- 0,
- cmd_respawn_pane_exec
+ CMD_PREPAREPANE,
+ cmd_respawn_pane_exec,
+ NULL
};

enum cmd_retval
@@ -52,9 +53,11 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
u_int idx;
struct environ_entry *envent;

- if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;
+ s = cmdq->state.s;
+ wp = cmdq->state.wp;

if (!args_has(self->args, 'k') && wp->fd != -1) {
if (window_pane_index(wp, &idx) != 0)
diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c
index 06102ed..af21f2f 100644
--- a/cmd-respawn-window.c
+++ b/cmd-respawn-window.c
@@ -33,8 +33,9 @@ const struct cmd_entry cmd_respawn_window_entry = {
"respawn-window", "respawnw",
"kt:", 0, -1,
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
- 0,
- cmd_respawn_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_respawn_window_exec,
+ NULL
};

enum cmd_retval
@@ -50,9 +51,10 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
char *cause;
struct environ_entry *envent;

- if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;
+ s = cmdq->state.s;

if (!args_has(self->args, 'k')) {
TAILQ_FOREACH(wp, &w->panes, entry) {
diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c
index 859ff04..310268c 100644
--- a/cmd-rotate-window.c
+++ b/cmd-rotate-window.c
@@ -30,21 +30,21 @@ const struct cmd_entry cmd_rotate_window_entry = {
"rotate-window", "rotatew",
"Dt:U", 0, 0,
"[-DU] " CMD_TARGET_WINDOW_USAGE,
- 0,
- cmd_rotate_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_rotate_window_exec,
+ NULL
};

enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
struct winlink *wl;
struct window *w;
struct window_pane *wp, *wp2;
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;

- if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
w = wl->window;

diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index b47c282..2fb50c0 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -39,8 +39,9 @@ const struct cmd_entry cmd_run_shell_entry = {
"run-shell", "run",
"bt:", 1, 1,
"[-b] " CMD_TARGET_PANE_USAGE " shell-command",
- 0,
- cmd_run_shell_exec
+ CMD_PREPAREPANE|CMD_PREPARESESSION,
+ cmd_run_shell_exec,
+ NULL
};

struct cmd_run_shell_data {
@@ -75,21 +76,17 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
struct args *args = self->args;
struct cmd_run_shell_data *cdata;
char *shellcmd;
- struct client *c;
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);
+ wl = cmdq->state.wl;
else {
- c = cmd_find_client(cmdq, NULL, 1);
- if (c != NULL && c->session != NULL) {
- s = c->session;
- wl = s->curw;
- wp = wl->window->active;
- }
+ s = cmdq->state.s;
+ wl = cmdq->state.wl;
+ wp = cmdq->state.wp;
}

ft = format_create();
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 47a263d..e3ed06b 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -38,7 +38,8 @@ const struct cmd_entry cmd_save_buffer_entry = {
"ab:", 1, 1,
"[-a] " CMD_BUFFER_USAGE " path",
0,
- cmd_save_buffer_exec
+ cmd_save_buffer_exec,
+ NULL
};

const struct cmd_entry cmd_show_buffer_entry = {
@@ -46,7 +47,8 @@ const struct cmd_entry cmd_show_buffer_entry = {
"b:", 0, 0,
CMD_BUFFER_USAGE,
0,
- cmd_save_buffer_exec
+ cmd_save_buffer_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-select-layout.c b/cmd-select-layout.c
index 77137b7..4eb3719 100644
--- a/cmd-select-layout.c
+++ b/cmd-select-layout.c
@@ -30,24 +30,27 @@ const struct cmd_entry cmd_select_layout_entry = {
"select-layout", "selectl",
"npt:", 0, 1,
"[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]",
- 0,
- cmd_select_layout_exec
+ CMD_PREPAREWINDOW,
+ cmd_select_layout_exec,
+ NULL
};

const struct cmd_entry cmd_next_layout_entry = {
"next-layout", "nextl",
"t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
- 0,
- cmd_select_layout_exec
+ CMD_PREPAREWINDOW,
+ cmd_select_layout_exec,
+ NULL
};

const struct cmd_entry cmd_previous_layout_entry = {
"previous-layout", "prevl",
"t:", 0, 0,
CMD_TARGET_WINDOW_USAGE,
- 0,
- cmd_select_layout_exec
+ CMD_PREPAREWINDOW,
+ cmd_select_layout_exec,
+ NULL
};

enum cmd_retval
@@ -58,7 +61,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_q *cmdq)
const char *layoutname;
int next, previous, layout;

- if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
server_unzoom_window(wl->window);

diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index 5810eea..e4bebc5 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -25,23 +25,39 @@
*/

enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *);
+void cmd_select_pane_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_select_pane_entry = {
"select-pane", "selectp",
"DdeLlRt:U", 0, 0,
"[-DdeLlRU] " CMD_TARGET_PANE_USAGE,
- 0,
- cmd_select_pane_exec
+ CMD_PREPAREPANE,
+ cmd_select_pane_exec,
+ cmd_select_pane_prepare
};

const struct cmd_entry cmd_last_pane_entry = {
"last-pane", "lastp",
"det:", 0, 0,
"[-de] " CMD_TARGET_WINDOW_USAGE,
- 0,
- cmd_select_pane_exec
+ CMD_PREPAREPANE,
+ cmd_select_pane_exec,
+ cmd_select_pane_prepare
};

+void
+cmd_select_pane_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
+ cmdq->state.wl = cmd_find_window(cmdq, args_get(args, 't'),
+ NULL);
+ } else {
+ cmdq->state.wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL,
+ &cmdq->state.wp);
+ }
+}
enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -50,8 +66,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp;

if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
- wl = cmd_find_window(cmdq, args_get(args, 't'), NULL);
- if (wl == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);

if (wl->window->last == NULL) {
@@ -73,9 +88,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
}

- if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);

+ wp = cmdq->state.wp;
+
server_unzoom_window(wp->window);
if (!window_pane_visible(wp)) {
cmdq_error(cmdq, "pane not visible");
diff --git a/cmd-select-window.c b/cmd-select-window.c
index f530f1f..bbd7f71 100644
--- a/cmd-select-window.c
+++ b/cmd-select-window.c
@@ -27,43 +27,70 @@
*/

enum cmd_retval cmd_select_window_exec(struct cmd *, struct cmd_q *);
+void cmd_select_window_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_select_window_entry = {
"select-window", "selectw",
"lnpTt:", 0, 0,
"[-lnpT] " CMD_TARGET_WINDOW_USAGE,
- 0,
- cmd_select_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_select_window_exec,
+ cmd_select_window_prepare
};

const struct cmd_entry cmd_next_window_entry = {
"next-window", "next",
"at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE,
- 0,
- cmd_select_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_select_window_exec,
+ cmd_select_window_prepare
};

const struct cmd_entry cmd_previous_window_entry = {
"previous-window", "prev",
"at:", 0, 0,
"[-a] " CMD_TARGET_SESSION_USAGE,
- 0,
- cmd_select_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_select_window_exec,
+ cmd_select_window_prepare
};

const struct cmd_entry cmd_last_window_entry = {
"last-window", "last",
"t:", 0, 0,
CMD_TARGET_SESSION_USAGE,
- 0,
- cmd_select_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_select_window_exec,
+ cmd_select_window_prepare
};

+void
+cmd_select_window_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+ int next, previous, last;
+
+ next = self->entry == &cmd_next_window_entry;
+ if (args_has(self->args, 'n'))
+ next = 1;
+ previous = self->entry == &cmd_previous_window_entry;
+ if (args_has(self->args, 'p'))
+ previous = 1;
+ last = self->entry == &cmd_last_window_entry;
+ if (args_has(self->args, 'l'))
+ last = 1;
+
+ if (next || previous || last)
+ cmdq->state.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+ else {
+ cmdq->state.wl = cmd_find_window(cmdq, args_get(args, 't'),
+ &cmdq->state.s);
+ }
+}
enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
struct winlink *wl;
struct session *s;
int next, previous, last, activity;
@@ -79,8 +106,7 @@ cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)
last = 1;

if (next || previous || last) {
- s = cmd_find_session(cmdq, args_get(args, 't'), 0);
- if (s == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);

activity = args_has(self->args, 'a');
@@ -103,9 +129,9 @@ cmd_select_window_exec(struct cmd *self, struct cmd_q *cmdq)

server_redraw_session(s);
} else {
- wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
- if (wl == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
+ s = cmdq->state.s;

/*
* If -T and select-window is invoked on same window as
diff --git a/cmd-send-keys.c b/cmd-send-keys.c
index 7a4d97d..fb38d00 100644
--- a/cmd-send-keys.c
+++ b/cmd-send-keys.c
@@ -28,21 +28,24 @@
*/

enum cmd_retval cmd_send_keys_exec(struct cmd *, struct cmd_q *);
+void cmd_send_keys_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_send_keys_entry = {
"send-keys", "send",
"lRt:", 0, -1,
"[-lR] " CMD_TARGET_PANE_USAGE " key ...",
- 0,
- cmd_send_keys_exec
+ CMD_PREPAREPANE,
+ cmd_send_keys_exec,
+ NULL
};

const struct cmd_entry cmd_send_prefix_entry = {
"send-prefix", NULL,
"2t:", 0, 0,
"[-2] " CMD_TARGET_PANE_USAGE,
- 0,
- cmd_send_keys_exec
+ CMD_PREPAREPANE,
+ cmd_send_keys_exec,
+ NULL
};

enum cmd_retval
@@ -55,8 +58,10 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
const u_char *str;
int i, key;

- if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
+ if (cmdq->state.wl == NULL)
return (CMD_RETURN_ERROR);
+ s = cmdq->state.s;
+ wp = cmdq->state.wp;

if (self->entry == &cmd_send_prefix_entry) {
if (args_has(args, '2'))
diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index 0ec362b..afa7069 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -34,7 +34,8 @@ const struct cmd_entry cmd_set_buffer_entry = {
"ab:n:", 0, 1,
"[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
0,
- cmd_set_buffer_exec
+ cmd_set_buffer_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-set-environment.c b/cmd-set-environment.c
index 83e63b4..bf65a3f 100644
--- a/cmd-set-environment.c
+++ b/cmd-set-environment.c
@@ -28,13 +28,15 @@
*/

enum cmd_retval cmd_set_environment_exec(struct cmd *, struct cmd_q *);
+void cmd_set_environment_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_set_environment_entry = {
"set-environment", "setenv",
"grt:u", 1, 2,
"[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
- 0,
- cmd_set_environment_exec
+ CMD_PREPARESESSION,
+ cmd_set_environment_exec,
+ NULL
};

enum cmd_retval
@@ -63,7 +65,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g'))
env = &global_environ;
else {
- if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);
env = &s->environ;
}
diff --git a/cmd-set-option.c b/cmd-set-option.c
index 01d691d..6bc0e56 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -69,7 +69,8 @@ const struct cmd_entry cmd_set_option_entry = {
"agoqst:uw", 1, 2,
"[-agosquw] [-t target-session|target-window] option [value]",
0,
- cmd_set_option_exec
+ cmd_set_option_exec,
+ NULL
};

const struct cmd_entry cmd_set_window_option_entry = {
@@ -77,7 +78,8 @@ const struct cmd_entry cmd_set_window_option_entry = {
"agoqt:u", 1, 2,
"[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
0,
- cmd_set_option_exec
+ cmd_set_option_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-show-environment.c b/cmd-show-environment.c
index 7737752..e5bacd6 100644
--- a/cmd-show-environment.c
+++ b/cmd-show-environment.c
@@ -28,13 +28,15 @@
*/

enum cmd_retval cmd_show_environment_exec(struct cmd *, struct cmd_q *);
+void cmd_show_environment_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_show_environment_entry = {
"show-environment", "showenv",
"gt:", 0, 1,
"[-g] " CMD_TARGET_SESSION_USAGE " [name]",
- 0,
- cmd_show_environment_exec
+ CMD_PREPARESESSION,
+ cmd_show_environment_exec,
+ NULL
};

enum cmd_retval
@@ -48,7 +50,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g'))
env = &global_environ;
else {
- if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);
env = &s->environ;
}
diff --git a/cmd-show-messages.c b/cmd-show-messages.c
index 308668f..aa74be4 100644
--- a/cmd-show-messages.c
+++ b/cmd-show-messages.c
@@ -34,8 +34,9 @@ const struct cmd_entry cmd_show_messages_entry = {
"show-messages", "showmsgs",
"IJTt:", 0, 0,
"[-IJT] " CMD_TARGET_CLIENT_USAGE,
- 0,
- cmd_show_messages_exec
+ CMD_PREPARECLIENT,
+ cmd_show_messages_exec,
+ NULL
};

const struct cmd_entry cmd_server_info_entry = {
@@ -43,7 +44,8 @@ const struct cmd_entry cmd_server_info_entry = {
"", 0, 0,
"",
0,
- cmd_show_messages_exec
+ cmd_show_messages_exec,
+ NULL
};

void cmd_show_messages_server(struct cmd_q *);
@@ -123,7 +125,7 @@ cmd_show_messages_jobs(struct cmd_q *cmdq)
}

enum cmd_retval
-cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq)
+cmd_show_messages_exec(unused struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct client *c;
@@ -152,7 +154,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq)
if (done)
return (CMD_RETURN_NORMAL);

- if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL)
+ if ((c = cmdq->state.c) == NULL)
return (CMD_RETURN_ERROR);

for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
diff --git a/cmd-show-options.c b/cmd-show-options.c
index a5011e7..dc596ca 100644
--- a/cmd-show-options.c
+++ b/cmd-show-options.c
@@ -28,6 +28,7 @@
*/

enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmd_q *);
+void cmd_show_options_prepare(struct cmd *, struct cmd_q *);

enum cmd_retval cmd_show_options_one(struct cmd *, struct cmd_q *,
struct options *, int);
@@ -38,8 +39,9 @@ const struct cmd_entry cmd_show_options_entry = {
"show-options", "show",
"gqst:vw", 0, 1,
"[-gqsvw] [-t target-session|target-window] [option]",
- 0,
- cmd_show_options_exec
+ CMD_PREPARESESSION|CMD_PREPAREWINDOW,
+ cmd_show_options_exec,
+ cmd_show_options_prepare
};

const struct cmd_entry cmd_show_window_options_entry = {
@@ -47,9 +49,23 @@ const struct cmd_entry cmd_show_window_options_entry = {
"gvt:", 0, 1,
"[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
0,
- cmd_show_options_exec
+ cmd_show_options_exec,
+ cmd_show_options_prepare
};

+void
+cmd_show_options_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ if (args_has(args, 'g') && args_has(args, 'w') &&
+ self->entry == &cmd_show_window_options_entry) {
+ cmdq->state.wl = cmd_find_window(cmdq, args_get(args, 't'),
+ NULL);
+ } else
+ cmdq->state.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+}
+
enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -69,8 +85,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g'))
oo = &global_w_options;
else {
- wl = cmd_find_window(cmdq, args_get(args, 't'), NULL);
- if (wl == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
oo = &wl->window->options;
}
@@ -79,8 +94,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(self->args, 'g'))
oo = &global_s_options;
else {
- s = cmd_find_session(cmdq, args_get(args, 't'), 0);
- if (s == NULL)
+ if ((s = cmdq->state.s) == NULL)
return (CMD_RETURN_ERROR);
oo = &s->options;
}
diff --git a/cmd-source-file.c b/cmd-source-file.c
index e5710a0..247e72f 100644
--- a/cmd-source-file.c
+++ b/cmd-source-file.c
@@ -35,7 +35,8 @@ const struct cmd_entry cmd_source_file_entry = {
"", 1, 1,
"path",
0,
- cmd_source_file_exec
+ cmd_source_file_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-split-window.c b/cmd-split-window.c
index 6b90125..88c2635 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -39,8 +39,9 @@ const struct cmd_entry cmd_split_window_entry = {
"bc:dF:l:hp:Pt:v", 0, -1,
"[-bdhvP] [-c start-directory] [-F format] [-p percentage|-l size] "
CMD_TARGET_PANE_USAGE " [command]",
- 0,
- cmd_split_window_exec
+ CMD_PREPAREPANE,
+ cmd_split_window_exec,
+ NULL
};

enum cmd_retval
@@ -62,9 +63,13 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct format_tree *ft;
struct environ_entry *envent;

- if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
+ if ((wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
- w = wl->window;
+ else {
+ w = wl->window;
+ s = cmdq->state.s;
+ wp = cmdq->state.wp;
+ }
server_unzoom_window(w);

environ_init(&env);
diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c
index 918a2e4..75094cb 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -32,8 +32,9 @@ const struct cmd_entry cmd_swap_pane_entry = {
"swap-pane", "swapp",
"dDs:t:U", 0, 0,
"[-dDU] " CMD_SRCDST_PANE_USAGE,
- 0,
- cmd_swap_pane_exec
+ CMD_PREPAREPANE,
+ cmd_swap_pane_exec,
+ NULL
};

enum cmd_retval
@@ -46,10 +47,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff;

- dst_wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &dst_wp);
- if (dst_wl == NULL)
+ if ((dst_wl = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
dst_w = dst_wl->window;
+ dst_wp = cmdq->state.wp;
server_unzoom_window(dst_w);

if (!args_has(args, 's')) {
diff --git a/cmd-swap-window.c b/cmd-swap-window.c
index 655b910..745b2bf 100644
--- a/cmd-swap-window.c
+++ b/cmd-swap-window.c
@@ -27,31 +27,42 @@
*/

enum cmd_retval cmd_swap_window_exec(struct cmd *, struct cmd_q *);
+void cmd_swap_window_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_swap_window_entry = {
"swap-window", "swapw",
"ds:t:", 0, 0,
"[-d] " CMD_SRCDST_WINDOW_USAGE,
- 0,
- cmd_swap_window_exec
+ CMD_PREPAREWINDOW,
+ cmd_swap_window_exec,
+ cmd_swap_window_prepare
};

+void
+cmd_swap_window_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ cmdq->state.wl = cmd_find_window(cmdq, args_get(args, 's'),
+ &cmdq->state.s);
+ cmdq->state.wl2 = cmd_find_window(cmdq, args_get(args, 't'),
+ &cmdq->state.s2);
+}
+
enum cmd_retval
cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
- const char *target_src, *target_dst;
struct session *src, *dst;
struct session_group *sg_src, *sg_dst;
struct winlink *wl_src, *wl_dst;
struct window *w;

- target_src = args_get(args, 's');
- if ((wl_src = cmd_find_window(cmdq, target_src, &src)) == NULL)
+ if ((wl_src = cmdq->state.wl) == NULL)
return (CMD_RETURN_ERROR);
- target_dst = args_get(args, 't');
- if ((wl_dst = cmd_find_window(cmdq, target_dst, &dst)) == NULL)
+ src = cmdq->state.s;
+ if ((wl_dst = cmdq->state.wl2) == NULL)
return (CMD_RETURN_ERROR);
+ dst = cmdq->state.s2;

sg_src = session_group_find(src);
sg_dst = session_group_find(dst);
diff --git a/cmd-switch-client.c b/cmd-switch-client.c
index 439f593..b95f250 100644
--- a/cmd-switch-client.c
+++ b/cmd-switch-client.c
@@ -28,15 +28,26 @@
*/

enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *);
+void cmd_switch_client_prepare(struct cmd *, struct cmd_q *);

const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc",
"lc:npt:r", 0, 0,
"[-lnpr] [-c target-client] [-t target-session]",
- CMD_READONLY,
- cmd_switch_client_exec
+ CMD_READONLY|CMD_PREPARECLIENT|CMD_PREPARESESSION,
+ cmd_switch_client_exec,
+ cmd_switch_client_prepare
};

+void
+cmd_switch_client_prepare(struct cmd *self, struct cmd_q *cmdq)
+{
+ struct args *args = self->args;
+
+ cmdq->state.c = cmd_find_client(cmdq, args_get(args, 'c'), 0);
+ cmdq->state.s = cmd_find_session(cmdq, args_get(args, 't'), 0);
+}
+
enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -48,7 +59,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp = NULL;
const char *tflag;

- if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL)
+ if ((c = cmdq->state.c) == NULL)
return (CMD_RETURN_ERROR);

if (args_has(args, 'r')) {
@@ -104,6 +115,9 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
}
}

+ if ((s = cmdq->state.s) == NULL)
+ return (CMD_RETURN_ERROR);
+
if (c->session != NULL)
c->last_session = c->session;
c->session = s;
diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c
index 710210c..284c86e 100644
--- a/cmd-unbind-key.c
+++ b/cmd-unbind-key.c
@@ -34,7 +34,8 @@ const struct cmd_entry cmd_unbind_key_entry = {
"acnt:", 0, 1,
"[-acn] [-t mode-table] key",
0,
- cmd_unbind_key_exec
+ cmd_unbind_key_exec,
+ NULL
};

enum cmd_retval
diff --git a/cmd-wait-for.c b/cmd-wait-for.c
index a3e8585..c90427d 100644
--- a/cmd-wait-for.c
+++ b/cmd-wait-for.c
@@ -35,7 +35,8 @@ const struct cmd_entry cmd_wait_for_entry = {
"LSU", 1, 1,
"[-L|-S|-U] channel",
0,
- cmd_wait_for_exec
+ cmd_wait_for_exec,
+ NULL
};

struct wait_channel {
--
2.1.4
Loading...