1
0
mirror of https://github.com/tmate-io/tmate-ssh-server.git synced 2020-11-18 19:53:51 -08:00

Sync OpenBSD patchset 294:

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).
This commit is contained in:
Tiago Cunha 2009-08-25 13:53:39 +00:00
parent c1653ff654
commit 8fd77cbb5b
8 changed files with 373 additions and 79 deletions

149
cmd-choose-client.c Normal file
View File

@ -0,0 +1,149 @@
/* $Id: cmd-choose-client.c,v 1.1 2009-08-25 13:53:39 tcunha 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);
}

View File

@ -1,4 +1,4 @@
/* $Id: cmd-choose-session.c,v 1.10 2009-07-28 22:12:16 tcunha Exp $ */ /* $Id: cmd-choose-session.c,v 1.11 2009-08-25 13:53:39 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,11 +27,12 @@
int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *); int cmd_choose_session_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_session_callback(void *, int); void cmd_choose_session_callback(void *, int);
void cmd_choose_session_free(void *);
const struct cmd_entry cmd_choose_session_entry = { const struct cmd_entry cmd_choose_session_entry = {
"choose-session", NULL, "choose-session", NULL,
CMD_TARGET_WINDOW_USAGE, CMD_TARGET_WINDOW_USAGE " [template]",
0, 0, CMD_ARG01, 0,
cmd_target_init, cmd_target_init,
cmd_target_parse, cmd_target_parse,
cmd_choose_session_exec, cmd_choose_session_exec,
@ -40,7 +41,8 @@ const struct cmd_entry cmd_choose_session_entry = {
}; };
struct cmd_choose_session_data { struct cmd_choose_session_data {
u_int client; u_int client;
char *template;
}; };
int int
@ -79,10 +81,14 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
} }
cdata = xmalloc(sizeof *cdata); 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); cdata->client = server_client_index(ctx->curclient);
window_choose_ready( window_choose_ready(wl->window->active,
wl->window->active, cur, cmd_choose_session_callback, xfree, cdata); cur, cmd_choose_session_callback, cmd_choose_session_free, cdata);
return (0); return (0);
} }
@ -92,13 +98,53 @@ cmd_choose_session_callback(void *data, int idx)
{ {
struct cmd_choose_session_data *cdata = data; struct cmd_choose_session_data *cdata = data;
struct client *c; struct client *c;
struct session *s;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *template, *cause;
if (idx != -1 && cdata->client <= ARRAY_LENGTH(&clients) - 1) { if (idx == -1)
c = ARRAY_ITEM(&clients, cdata->client); return;
if (c != NULL && (u_int) idx <= ARRAY_LENGTH(&sessions) - 1) { if (cdata->client > ARRAY_LENGTH(&clients) - 1)
c->session = ARRAY_ITEM(&sessions, idx); return;
recalculate_sizes(); c = ARRAY_ITEM(&clients, cdata->client);
server_redraw_client(c);
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);
} }

View File

@ -1,4 +1,4 @@
/* $Id: cmd-choose-window.c,v 1.14 2009-08-09 16:41:17 tcunha Exp $ */ /* $Id: cmd-choose-window.c,v 1.15 2009-08-25 13:53:39 tcunha Exp $ */
/* /*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -27,11 +27,12 @@
int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *); int cmd_choose_window_exec(struct cmd *, struct cmd_ctx *);
void cmd_choose_window_callback(void *, int); void cmd_choose_window_callback(void *, int);
void cmd_choose_window_free(void *);
const struct cmd_entry cmd_choose_window_entry = { const struct cmd_entry cmd_choose_window_entry = {
"choose-window", NULL, "choose-window", NULL,
CMD_TARGET_WINDOW_USAGE, CMD_TARGET_WINDOW_USAGE " [template]",
0, 0, CMD_ARG01, 0,
cmd_target_init, cmd_target_init,
cmd_target_parse, cmd_target_parse,
cmd_choose_window_exec, cmd_choose_window_exec,
@ -40,7 +41,9 @@ const struct cmd_entry cmd_choose_window_entry = {
}; };
struct cmd_choose_window_data { struct cmd_choose_window_data {
u_int session; u_int client;
u_int session;
char *template;
}; };
int int
@ -104,9 +107,14 @@ cmd_choose_window_exec(struct cmd *self, struct cmd_ctx *ctx)
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
if (session_index(s, &cdata->session) != 0) if (session_index(s, &cdata->session) != 0)
fatalx("session not found"); 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( window_choose_ready(wl->window->active,
wl->window->active, cur, cmd_choose_window_callback, xfree, cdata); cur, cmd_choose_window_callback, cmd_choose_window_free, cdata);
return (0); return (0);
} }
@ -115,12 +123,56 @@ void
cmd_choose_window_callback(void *data, int idx) cmd_choose_window_callback(void *data, int idx)
{ {
struct cmd_choose_window_data *cdata = data; struct cmd_choose_window_data *cdata = data;
struct client *c;
struct session *s; struct session *s;
struct cmd_list *cmdlist;
struct cmd_ctx ctx;
char *target, *template, *cause;
if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) { if (idx == -1)
s = ARRAY_ITEM(&sessions, cdata->session); return;
if (s != NULL && session_select(s, idx) == 0) if (cdata->client > ARRAY_LENGTH(&clients) - 1)
server_redraw_session(s); return;
recalculate_sizes(); 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);
} }

View File

@ -1,4 +1,4 @@
/* $Id: cmd-command-prompt.c,v 1.24 2009-08-24 16:24:18 tcunha Exp $ */ /* $Id: cmd-command-prompt.c,v 1.25 2009-08-25 13:53:39 tcunha Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * 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 *); int cmd_command_prompt_callback(void *, const char *);
void cmd_command_prompt_cfree(void *); void cmd_command_prompt_cfree(void *);
char *cmd_command_prompt_replace(char *, const char *, int);
const struct cmd_entry cmd_command_prompt_entry = { const struct cmd_entry cmd_command_prompt_entry = {
"command-prompt", NULL, "command-prompt", NULL,
@ -216,7 +215,7 @@ cmd_command_prompt_callback(void *data, const char *s)
if (s == NULL) if (s == NULL)
return (0); return (0);
newtempl = cmd_command_prompt_replace(cdata->template, s, cdata->idx); newtempl = cmd_template_replace(cdata->template, s, cdata->idx);
xfree(cdata->template); xfree(cdata->template);
cdata->template = newtempl; cdata->template = newtempl;
@ -265,43 +264,3 @@ cmd_command_prompt_cfree(void *data)
xfree(cdata->template); xfree(cdata->template);
xfree(cdata); 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);
}

44
cmd.c
View File

@ -1,4 +1,4 @@
/* $Id: cmd.c,v 1.113 2009-08-24 16:24:18 tcunha Exp $ */ /* $Id: cmd.c,v 1.114 2009-08-25 13:53:39 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -30,6 +30,7 @@ const struct cmd_entry *cmd_table[] = {
&cmd_attach_session_entry, &cmd_attach_session_entry,
&cmd_bind_key_entry, &cmd_bind_key_entry,
&cmd_break_pane_entry, &cmd_break_pane_entry,
&cmd_choose_client_entry,
&cmd_choose_session_entry, &cmd_choose_session_entry,
&cmd_choose_window_entry, &cmd_choose_window_entry,
&cmd_clear_history_entry, &cmd_clear_history_entry,
@ -857,3 +858,44 @@ error:
xfree(winptr); xfree(winptr);
return (NULL); 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);
}

View File

@ -1,4 +1,4 @@
/* $Id: key-bindings.c,v 1.80 2009-08-24 16:24:18 tcunha Exp $ */ /* $Id: key-bindings.c,v 1.81 2009-08-25 13:53:39 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -130,6 +130,7 @@ key_bindings_init(void)
{ ']', 0, &cmd_paste_buffer_entry }, { ']', 0, &cmd_paste_buffer_entry },
{ 'c', 0, &cmd_new_window_entry }, { 'c', 0, &cmd_new_window_entry },
{ 'd', 0, &cmd_detach_client_entry }, { 'd', 0, &cmd_detach_client_entry },
{ 'D', 0, &cmd_choose_client_entry },
{ 'f', 0, &cmd_command_prompt_entry }, { 'f', 0, &cmd_command_prompt_entry },
{ 'i', 0, &cmd_display_message_entry }, { 'i', 0, &cmd_display_message_entry },
{ 'l', 0, &cmd_last_window_entry }, { 'l', 0, &cmd_last_window_entry },
@ -143,7 +144,7 @@ key_bindings_init(void)
{ 'x', 0, &cmd_confirm_before_entry }, { 'x', 0, &cmd_confirm_before_entry },
{ '{', 0, &cmd_swap_pane_entry }, { '{', 0, &cmd_swap_pane_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 }, { '1' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry }, { '2' | KEYC_ESCAPE, 0, &cmd_select_layout_entry },
{ '3' | 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_LEFT | KEYC_CTRL, 1, &cmd_resize_pane_entry },
{ KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, { KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry },
{ 'o' | KEYC_ESCAPE, 0, &cmd_rotate_window_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; u_int i;
struct cmd *cmd; struct cmd *cmd;

59
tmux.1
View File

@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.157 2009-08-24 16:35:24 tcunha Exp $ .\" $Id: tmux.1,v 1.158 2009-08-25 13:53:39 tcunha Exp $
.\" .\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\" .\"
@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" 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 .Dt TMUX 1
.Os .Os
.Sh NAME .Sh NAME
@ -622,14 +622,57 @@ off from its containing window to make it the only pane in a new window.
If If
.Fl d .Fl d
is given, the new window does not become the current window. is given, the new window does not become the current window.
.It Ic choose-session Op Fl t Ar target-window .It Xo
Put a window into session choice mode, where the session for the current .Ic choose-client
client may be selected interactively from a list. .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 This command works only from inside
.Nm . .Nm .
.It Ic choose-window Op Fl t Ar target-window .It Xo
Put a window into window choice mode, where the window for the session .Ic choose-session
attached to the current client may be selected interactively from a list. .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 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 This command works only from inside
.Nm . .Nm .
.It Ic down-pane Op Fl t Ar target-pane .It Ic down-pane Op Fl t Ar target-pane

4
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.428 2009-08-25 13:11:24 tcunha Exp $ */ /* $Id: tmux.h,v 1.429 2009-08-25 13:53:39 tcunha Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -1266,10 +1266,12 @@ int cmd_find_index(
struct cmd_ctx *, const char *, struct session **); struct cmd_ctx *, const char *, struct session **);
struct winlink *cmd_find_pane(struct cmd_ctx *, struct winlink *cmd_find_pane(struct cmd_ctx *,
const char *, struct session **, struct window_pane **); 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_table[];
extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_attach_session_entry;
extern const struct cmd_entry cmd_bind_key_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_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_session_entry;
extern const struct cmd_entry cmd_choose_window_entry; extern const struct cmd_entry cmd_choose_window_entry;
extern const struct cmd_entry cmd_clear_history_entry; extern const struct cmd_entry cmd_clear_history_entry;