summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2009-08-25 12:18:52 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2009-08-25 12:18:52 +0000
commit3b82430ff83eff28d489555fa5840fb1e0735d19 (patch)
tree01b26d1875690d638c182ba7dfd45ad8fe59522b
parent3a2cf682677a24dc0f66604f7d0701f10275a58b (diff)
Add a choose-client command and extend choose-{session,window} to accept a
template. After a choice is made, %% (or %1) in the template is replaced by the name of the session, window or client suitable for -t and the result executed as a command. So, for example, "choose-window "killw -t '%%'"" will kill the selected window. The defaults if no template is given are (as now) select-window for choose-window, switch-client for choose-session, and detach-client for choose-client (now bound to D).
-rw-r--r--usr.bin/tmux/Makefile4
-rw-r--r--usr.bin/tmux/cmd-choose-client.c149
-rw-r--r--usr.bin/tmux/cmd-choose-session.c72
-rw-r--r--usr.bin/tmux/cmd-choose-window.c76
-rw-r--r--usr.bin/tmux/cmd-command-prompt.c45
-rw-r--r--usr.bin/tmux/cmd.c44
-rw-r--r--usr.bin/tmux/key-bindings.c7
-rw-r--r--usr.bin/tmux/tmux.159
-rw-r--r--usr.bin/tmux/tmux.h4
9 files changed, 377 insertions, 83 deletions
diff --git a/usr.bin/tmux/Makefile b/usr.bin/tmux/Makefile
index c9dc241d674..f829da21e8c 100644
--- a/usr.bin/tmux/Makefile
+++ b/usr.bin/tmux/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.13 2009/08/11 17:18:35 nicm Exp $
+# $OpenBSD: Makefile,v 1.14 2009/08/25 12:18:51 nicm Exp $
PROG= tmux
SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
@@ -25,7 +25,7 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \
cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \
cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \
- cmd-set-environment.c cmd-show-environment.c \
+ cmd-set-environment.c cmd-show-environment.c cmd-choose-client.c \
cmd-up-pane.c cmd-display-message.c cmd.c \
colour.c environ.c grid-view.c grid.c input-keys.c \
imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \
diff --git a/usr.bin/tmux/cmd-choose-client.c b/usr.bin/tmux/cmd-choose-client.c
new file mode 100644
index 00000000000..805d5e9049b
--- /dev/null
+++ b/usr.bin/tmux/cmd-choose-client.c
@@ -0,0 +1,149 @@
+/* $OpenBSD: cmd-choose-client.c,v 1.1 2009/08/25 12:18:51 nicm Exp $ */
+
+/*
+ * Copyright (c) 2009 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 "tmux.h"
+
+/*
+ * Enter choice mode to choose a client.
+ */
+
+int cmd_choose_client_exec(struct cmd *, struct cmd_ctx *);
+
+void cmd_choose_client_callback(void *, int);
+void cmd_choose_client_free(void *);
+
+const struct cmd_entry cmd_choose_client_entry = {
+ "choose-client", NULL,
+ CMD_TARGET_WINDOW_USAGE " [template]",
+ CMD_ARG01, 0,
+ cmd_target_init,
+ cmd_target_parse,
+ cmd_choose_client_exec,
+ cmd_target_free,
+ cmd_target_print
+};
+
+struct cmd_choose_client_data {
+ u_int client;
+ char *template;
+};
+
+int
+cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
+{
+ struct cmd_target_data *data = self->data;
+ struct cmd_choose_client_data *cdata;
+ struct winlink *wl;
+ struct client *c;
+ u_int i, idx, cur;
+
+ if (ctx->curclient == NULL) {
+ ctx->error(ctx, "must be run interactively");
+ return (-1);
+ }
+
+ if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
+ return (-1);
+
+ if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
+ return (0);
+
+ cur = idx = 0;
+ for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
+ c = ARRAY_ITEM(&clients, i);
+ if (c == NULL || c->session == NULL)
+ continue;
+ if (c == ctx->curclient)
+ cur = idx;
+ idx++;
+
+ window_choose_add(wl->window->active, i,
+ "%s: %s [%ux%u %s]%s", c->tty.path,
+ c->session->name, c->tty.sx, c->tty.sy,
+ c->tty.termname, c->tty.flags & TTY_UTF8 ? " (utf8)" : "");
+ }
+
+ cdata = xmalloc(sizeof *cdata);
+ if (data->arg != NULL)
+ cdata->template = xstrdup(data->arg);
+ else
+ cdata->template = xstrdup("detach-client -t '%%'");
+ cdata->client = server_client_index(ctx->curclient);
+
+ window_choose_ready(wl->window->active,
+ cur, cmd_choose_client_callback, cmd_choose_client_free, cdata);
+
+ return (0);
+}
+
+void
+cmd_choose_client_callback(void *data, int idx)
+{
+ struct cmd_choose_client_data *cdata = data;
+ struct client *c, *c2;
+ struct cmd_list *cmdlist;
+ struct cmd_ctx ctx;
+ char *template, *cause;
+
+ if (idx == -1)
+ return;
+ if (cdata->client > ARRAY_LENGTH(&clients) - 1)
+ return;
+ c = ARRAY_ITEM(&clients, cdata->client);
+
+ if ((u_int) idx > ARRAY_LENGTH(&clients) - 1)
+ return;
+ c2 = ARRAY_ITEM(&clients, idx);
+ if (c2 == NULL || c2->session == NULL)
+ return;
+ template = cmd_template_replace(cdata->template, c2->tty.path, 1);
+
+ if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
+ if (cause != NULL) {
+ *cause = toupper((u_char) *cause);
+ status_message_set(c, "%s", cause);
+ xfree(cause);
+ }
+ xfree(template);
+ return;
+ }
+ xfree(template);
+
+ 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);
+ cmd_list_free(cmdlist);
+}
+
+void
+cmd_choose_client_free(void *data)
+{
+ struct cmd_choose_client_data *cdata = data;
+
+ xfree(cdata->template);
+ xfree(cdata);
+}
diff --git a/usr.bin/tmux/cmd-choose-session.c b/usr.bin/tmux/cmd-choose-session.c
index 81719f0fc55..dfdf18a6ca0 100644
--- a/usr.bin/tmux/cmd-choose-session.c
+++ b/usr.bin/tmux/cmd-choose-session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-choose-session.c,v 1.4 2009/07/26 12:58:44 nicm Exp $ */
+/* $OpenBSD: cmd-choose-session.c,v 1.5 2009/08/25 12:18:51 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,11 +27,12 @@
int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_session_callback(void *, int);
+void cmd_choose_session_free(void *);
const struct cmd_entry cmd_choose_session_entry = {
"choose-session", NULL,
- CMD_TARGET_WINDOW_USAGE,
- 0, 0,
+ CMD_TARGET_WINDOW_USAGE " [template]",
+ CMD_ARG01, 0,
cmd_target_init,
cmd_target_parse,
cmd_choose_session_exec,
@@ -40,7 +41,8 @@ const struct cmd_entry cmd_choose_session_entry = {
};
struct cmd_choose_session_data {
- u_int client;
+ u_int client;
+ char *template;
};
int
@@ -79,10 +81,14 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
}
cdata = xmalloc(sizeof *cdata);
+ if (data->arg != NULL)
+ cdata->template = xstrdup(data->arg);
+ else
+ cdata->template = xstrdup("switch-client -t '%%'");
cdata->client = server_client_index(ctx->curclient);
- window_choose_ready(
- wl->window->active, cur, cmd_choose_session_callback, xfree, cdata);
+ window_choose_ready(wl->window->active,
+ cur, cmd_choose_session_callback, cmd_choose_session_free, cdata);
return (0);
}
@@ -92,13 +98,53 @@ cmd_choose_session_callback(void *data, int idx)
{
struct cmd_choose_session_data *cdata = data;
struct client *c;
-
- if (idx != -1 && cdata->client <= ARRAY_LENGTH(&clients) - 1) {
- c = ARRAY_ITEM(&clients, cdata->client);
- if (c != NULL && (u_int) idx <= ARRAY_LENGTH(&sessions) - 1) {
- c->session = ARRAY_ITEM(&sessions, idx);
- recalculate_sizes();
- server_redraw_client(c);
+ struct session *s;
+ struct cmd_list *cmdlist;
+ struct cmd_ctx ctx;
+ char *template, *cause;
+
+ if (idx == -1)
+ return;
+ if (cdata->client > ARRAY_LENGTH(&clients) - 1)
+ return;
+ c = ARRAY_ITEM(&clients, cdata->client);
+
+ if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1)
+ return;
+ s = ARRAY_ITEM(&sessions, idx);
+ if (s == NULL)
+ return;
+ template = cmd_template_replace(cdata->template, s->name, 1);
+
+ if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
+ if (cause != NULL) {
+ *cause = toupper((u_char) *cause);
+ status_message_set(c, "%s", cause);
+ xfree(cause);
}
+ xfree(template);
+ return;
}
+ xfree(template);
+
+ 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);
+ cmd_list_free(cmdlist);
+}
+
+void
+cmd_choose_session_free(void *data)
+{
+ struct cmd_choose_session_data *cdata = data;
+
+ xfree(cdata->template);
+ xfree(cdata);
}
diff --git a/usr.bin/tmux/cmd-choose-window.c b/usr.bin/tmux/cmd-choose-window.c
index 486f0830d54..b60915c9f01 100644
--- a/usr.bin/tmux/cmd-choose-window.c
+++ b/usr.bin/tmux/cmd-choose-window.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-choose-window.c,v 1.6 2009/08/04 14:28:23 nicm Exp $ */
+/* $OpenBSD: cmd-choose-window.c,v 1.7 2009/08/25 12:18:51 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -27,11 +27,12 @@
int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_window_callback(void *, int);
+void cmd_choose_window_free(void *);
const struct cmd_entry cmd_choose_window_entry = {
"choose-window", NULL,
- CMD_TARGET_WINDOW_USAGE,
- 0, 0,
+ CMD_TARGET_WINDOW_USAGE " [template]",
+ CMD_ARG01, 0,
cmd_target_init,
cmd_target_parse,
cmd_choose_window_exec,
@@ -40,7 +41,9 @@ const struct cmd_entry cmd_choose_window_entry = {
};
struct cmd_choose_window_data {
- u_int session;
+ u_int client;
+ u_int session;
+ char *template;
};
int
@@ -104,9 +107,14 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cdata = xmalloc(sizeof *cdata);
if (session_index(s, &cdata->session) != 0)
fatalx("session not found");
+ if (data->arg != NULL)
+ cdata->template = xstrdup(data->arg);
+ else
+ cdata->template = xstrdup("select-window -t '%%'");
+ cdata->client = server_client_index(ctx->curclient);
- window_choose_ready(
- wl->window->active, cur, cmd_choose_window_callback, xfree, cdata);
+ window_choose_ready(wl->window->active,
+ cur, cmd_choose_window_callback, cmd_choose_window_free, cdata);
return (0);
}
@@ -115,12 +123,56 @@ void
cmd_choose_window_callback(void *data, int idx)
{
struct cmd_choose_window_data *cdata = data;
+ struct client *c;
struct session *s;
-
- if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
- s = ARRAY_ITEM(&sessions, cdata->session);
- if (s != NULL && session_select(s, idx) == 0)
- server_redraw_session(s);
- recalculate_sizes();
+ struct cmd_list *cmdlist;
+ struct cmd_ctx ctx;
+ char *target, *template, *cause;
+
+ if (idx == -1)
+ return;
+ if (cdata->client > ARRAY_LENGTH(&clients) - 1)
+ return;
+ c = ARRAY_ITEM(&clients, cdata->client);
+ if (cdata->session > ARRAY_LENGTH(&sessions) - 1)
+ return;
+ s = ARRAY_ITEM(&sessions, cdata->session);
+ if (c->session != s)
+ return;
+
+ xasprintf(&target, "%s:%d", s->name, idx);
+ template = cmd_template_replace(cdata->template, target, 1);
+ xfree(target);
+
+ if (cmd_string_parse(template, &cmdlist, &cause) != 0) {
+ if (cause != NULL) {
+ *cause = toupper((u_char) *cause);
+ status_message_set(c, "%s", cause);
+ xfree(cause);
+ }
+ xfree(template);
+ return;
}
+ xfree(template);
+
+ 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);
+ cmd_list_free(cmdlist);
+}
+
+void
+cmd_choose_window_free(void *data)
+{
+ struct cmd_choose_window_data *cdata = data;
+
+ xfree(cdata->template);
+ xfree(cdata);
}
diff --git a/usr.bin/tmux/cmd-command-prompt.c b/usr.bin/tmux/cmd-command-prompt.c
index bc65e877937..df4ef5e9997 100644
--- a/usr.bin/tmux/cmd-command-prompt.c
+++ b/usr.bin/tmux/cmd-command-prompt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-command-prompt.c,v 1.9 2009/08/23 16:45:00 nicm Exp $ */
+/* $OpenBSD: cmd-command-prompt.c,v 1.10 2009/08/25 12:18:51 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -35,7 +35,6 @@ size_t cmd_command_prompt_print(struct cmd *, char *, size_t);
int cmd_command_prompt_callback(void *, const char *);
void cmd_command_prompt_cfree(void *);
-char *cmd_command_prompt_replace(char *, const char *, int);
const struct cmd_entry cmd_command_prompt_entry = {
"command-prompt", NULL,
@@ -216,7 +215,7 @@ cmd_command_prompt_callback(void *data, const char *s)
if (s == NULL)
return (0);
- newtempl = cmd_command_prompt_replace(cdata->template, s, cdata->idx);
+ newtempl = cmd_template_replace(cdata->template, s, cdata->idx);
xfree(cdata->template);
cdata->template = newtempl;
@@ -265,43 +264,3 @@ cmd_command_prompt_cfree(void *data)
xfree(cdata->template);
xfree(cdata);
}
-
-char *
-cmd_command_prompt_replace(char *template, const char *s, int idx)
-{
- char ch;
- char *buf, *ptr;
- int replaced;
- size_t len;
-
- if (strstr(template, "%") == NULL)
- return (xstrdup(template));
-
- buf = xmalloc(1);
- *buf = '\0';
- len = 0;
- replaced = 0;
-
- ptr = template;
- while (*ptr != '\0') {
- switch (ch = *ptr++) {
- case '%':
- if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
- if (*ptr != '%' || replaced)
- break;
- replaced = 1;
- }
- ptr++;
-
- len += strlen(s);
- buf = xrealloc(buf, 1, len + 1);
- strlcat(buf, s, len + 1);
- continue;
- }
- buf = xrealloc(buf, 1, len + 2);
- buf[len++] = ch;
- buf[len] = '\0';
- }
-
- return (buf);
-}
diff --git a/usr.bin/tmux/cmd.c b/usr.bin/tmux/cmd.c
index 7bd5af4de7d..9288bcba82f 100644
--- a/usr.bin/tmux/cmd.c
+++ b/usr.bin/tmux/cmd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd.c,v 1.14 2009/08/23 16:45:00 nicm Exp $ */
+/* $OpenBSD: cmd.c,v 1.15 2009/08/25 12:18:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -31,6 +31,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_attach_session_entry,
&cmd_bind_key_entry,
&cmd_break_pane_entry,
+ &cmd_choose_client_entry,
&cmd_choose_session_entry,
&cmd_choose_window_entry,
&cmd_clear_history_entry,
@@ -858,3 +859,44 @@ error:
xfree(winptr);
return (NULL);
}
+
+/* Replace the first %% or %idx in template by s. */
+char *
+cmd_template_replace(char *template, const char *s, int idx)
+{
+ char ch;
+ char *buf, *ptr;
+ int replaced;
+ size_t len;
+
+ if (strstr(template, "%") == NULL)
+ return (xstrdup(template));
+
+ buf = xmalloc(1);
+ *buf = '\0';
+ len = 0;
+ replaced = 0;
+
+ ptr = template;
+ while (*ptr != '\0') {
+ switch (ch = *ptr++) {
+ case '%':
+ if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
+ if (*ptr != '%' || replaced)
+ break;
+ replaced = 1;
+ }
+ ptr++;
+
+ len += strlen(s);
+ buf = xrealloc(buf, 1, len + 1);
+ strlcat(buf, s, len + 1);
+ continue;
+ }
+ buf = xrealloc(buf, 1, len + 2);
+ buf[len++] = ch;
+ buf[len] = '\0';
+ }
+
+ return (buf);
+}
diff --git a/usr.bin/tmux/key-bindings.c b/usr.bin/tmux/key-bindings.c
index 43eb27ee2d4..67605369587 100644
--- a/usr.bin/tmux/key-bindings.c
+++ b/usr.bin/tmux/key-bindings.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: key-bindings.c,v 1.9 2009/08/23 16:45:00 nicm Exp $ */
+/* $OpenBSD: key-bindings.c,v 1.10 2009/08/25 12:18:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -130,6 +130,7 @@ key_bindings_init(void)
{ ']', 0, &cmd_paste_buffer_entry },
{ 'c', 0, &cmd_new_window_entry },
{ 'd', 0, &cmd_detach_client_entry },
+ { 'D', 0, &cmd_choose_client_entry },
{ 'f', 0, &cmd_command_prompt_entry },
{ 'i', 0, &cmd_display_message_entry },
{ 'l', 0, &cmd_last_window_entry },
@@ -143,7 +144,7 @@ key_bindings_init(void)
{ 'x', 0, &cmd_confirm_before_entry },
{ '{', 0, &cmd_swap_pane_entry },
{ '}', 0, &cmd_swap_pane_entry },
- { '\002', 0, &cmd_send_prefix_entry },
+ { '\002', /* C-b */ 0, &cmd_send_prefix_entry },
{ '1' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '3' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
@@ -162,7 +163,7 @@ key_bindings_init(void)
{ KEYC_LEFT | KEYC_CTRL, 1, &cmd_resize_pane_entry },
{ KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry },
{ 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_entry },
- { '\017', 0, &cmd_rotate_window_entry },
+ { '\017', /* C-o */ 0, &cmd_rotate_window_entry },
};
u_int i;
struct cmd *cmd;
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index 6f297d80646..a178f032db2 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.75 2009/08/23 18:21:02 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.76 2009/08/25 12:18:51 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 23 2009 $
+.Dd $Mdocdate: August 25 2009 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -622,14 +622,57 @@ off from its containing window to make it the only pane in a new window.
If
.Fl d
is given, the new window does not become the current window.
-.It Ic choose-session Op Fl t Ar target-window
-Put a window into session choice mode, where the session for the current
-client may be selected interactively from a list.
+.It Xo
+.Ic choose-client
+.Op Fl t Ar target-window
+.Op Ar template
+.Xc
+Put a window into client choice mode, allowing a client to be selected
+interactively from a list.
+After a client is chosen,
+.Ql %%
+is replaced by the client
+.Xr pty 4
+path in
+.Ar template
+and the result executed as a command.
+If
+.Ar template
+is not given, "detach-client -t '%%'" is used.
+This command works only from inside
+.Nm .
+.It Xo
+.Ic choose-session
+.Op Fl t Ar target-window
+.Op Ar template
+.Xc
+Put a window into session choice mode, where a session may be selected
+interactively from a list.
+When one is chosen,
+.Ql %%
+is replaced by the session name in
+.Ar template
+and the result executed as a command.
+If
+.Ar template
+is not given, "switch-client -t '%%'" is used.
This command works only from inside
.Nm .
-.It Ic choose-window Op Fl t Ar target-window
-Put a window into window choice mode, where the window for the session
-attached to the current client may be selected interactively from a list.
+.It Xo
+.Ic choose-window
+.Op Fl t Ar target-window
+.Op Ar template
+.Xc
+Put a window into window choice mode, where a window may be chosen
+interactively from a list.
+After a window is selected,
+.Ql %%
+is replaced by the session name and window index in
+.Ar template
+and the result executed as a command.
+If
+.Ar template
+is not given, "select-window -t '%%'" is used.
This command works only from inside
.Nm .
.It Ic down-pane Op Fl t Ar target-pane
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index b3bcd058427..b3f59c15bee 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.90 2009/08/24 08:03:11 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.91 2009/08/25 12:18:51 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -1268,10 +1268,12 @@ 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);
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;
extern const struct cmd_entry cmd_break_pane_entry;
+extern const struct cmd_entry cmd_choose_client_entry;
extern const struct cmd_entry cmd_choose_session_entry;
extern const struct cmd_entry cmd_choose_window_entry;
extern const struct cmd_entry cmd_clear_history_entry;