summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2009-07-17 15:03:11 +0000
committerNicholas Marriott <nicm@openbsd.org>2009-07-17 15:03:11 +0000
commitce53936a2b56521903d69bac565391e37ad7e115 (patch)
tree5a77d399e686fe3db9687c157b109d5945eaf38e
parent1938c994e7d9a27741735e6821217a16a134f039 (diff)
Tidy up new-session and attach-session and change them to work from inside
tmux, switching the current client to the new or requested session. Written with Josh Elsasser.
-rw-r--r--cmd-attach-session.c55
-rw-r--r--cmd-new-session.c121
-rw-r--r--tmux.16
-rw-r--r--tmux.h10
4 files changed, 127 insertions, 65 deletions
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index 196d5d13..aae8abe7 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -44,10 +44,9 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
+ struct client *c;
char *cause;
-
- if (ctx->curclient != NULL)
- return (0);
+ u_int i;
if (ARRAY_LENGTH(&sessions) == 0) {
ctx->error(ctx, "no sessions");
@@ -56,24 +55,44 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
- if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
- ctx->error(ctx, "not a terminal");
- return (-1);
- }
+ if (ctx->cmdclient == NULL) {
+ if (data->chflags & CMD_CHFLAG('d')) {
+ /*
+ * Can't use server_write_session in case attaching to
+ * the same session as currently attached to.
+ */
+ for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
+ c = ARRAY_ITEM(&clients, i);
+ if (c == NULL || c->session != s)
+ continue;
+ if (c == ctx->curclient)
+ continue;
+ server_write_client(c, MSG_DETACH, NULL, 0);
+ }
+ }
+
+ ctx->curclient->session = s;
+ server_redraw_client(ctx->curclient);
+ } else {
+ if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
+ ctx->error(ctx, "not a terminal");
+ return (-1);
+ }
- if (tty_open(&ctx->cmdclient->tty, &cause) != 0) {
- ctx->error(ctx, "terminal open failed: %s", cause);
- xfree(cause);
- return (-1);
- }
+ if (tty_open(&ctx->cmdclient->tty, &cause) != 0) {
+ ctx->error(ctx, "terminal open failed: %s", cause);
+ xfree(cause);
+ return (-1);
+ }
- if (data->chflags & CMD_CHFLAG('d'))
- server_write_session(s, MSG_DETACH, NULL, 0);
- ctx->cmdclient->session = s;
+ if (data->chflags & CMD_CHFLAG('d'))
+ server_write_session(s, MSG_DETACH, NULL, 0);
- server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
+ ctx->cmdclient->session = s;
+ server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
+ server_redraw_client(ctx->cmdclient);
+ }
recalculate_sizes();
- server_redraw_client(ctx->cmdclient);
- return (1);
+ return (1); /* 1 means don't tell command client to exit */
}
diff --git a/cmd-new-session.c b/cmd-new-session.c
index cf086a87..53e752ac 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -111,65 +111,80 @@ int
cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_new_session_data *data = self->data;
- struct client *c = ctx->cmdclient;
struct session *s;
char *cmd, *cwd, *cause;
u_int sx, sy;
- if (ctx->curclient != NULL)
- return (0);
+ if (data->newname != NULL && session_find(data->newname) != NULL) {
+ ctx->error(ctx, "duplicate session: %s", data->newname);
+ return (-1);
+ }
- if (!data->flag_detached) {
- if (c == NULL) {
- ctx->error(ctx, "no client to attach to");
+ /*
+ * There are two cases:
+ *
+ * 1. If cmdclient is non-NULL, new-session has been called from the
+ * command-line - cmdclient is to become a new attached, interactive
+ * client. Unless -d is given, the terminal must be opened and then
+ * the client sent MSG_READY.
+ *
+ * 2. If cmdclient is NULL, new-session has been called from an
+ * existing client (such as a key binding).
+ *
+ * In both cases, a new additional session needs to be created and
+ * (unless -d) set as the current session for the client.
+ */
+
+ /* Open the terminal if necessary. */
+ if (!data->flag_detached && ctx->cmdclient != NULL) {
+ if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
+ ctx->error(ctx, "not a terminal");
return (-1);
}
- if (!(c->flags & CLIENT_TERMINAL)) {
- ctx->error(ctx, "not a terminal");
+
+ if (tty_open(&ctx->cmdclient->tty, &cause) != 0) {
+ ctx->error(ctx, "open terminal failed: %s", cause);
+ xfree(cause);
return (-1);
}
}
- if (data->newname != NULL && session_find(data->newname) != NULL) {
- ctx->error(ctx, "duplicate session: %s", data->newname);
- return (-1);
+ /* Find new session size and options. */
+ if (data->flag_detached) {
+ sx = 80;
+ sy = 25;
+ } else {
+ if (ctx->cmdclient != NULL) {
+ sx = ctx->cmdclient->tty.sx;
+ sy = ctx->cmdclient->tty.sy;
+ } else {
+ sx = ctx->curclient->tty.sx;
+ sy = ctx->curclient->tty.sy;
+ }
}
-
- cmd = data->cmd;
- if (cmd == NULL)
- cmd = options_get_string(&global_s_options, "default-command");
- if (c == NULL || c->cwd == NULL)
+ if (sy > 0 && options_get_number(&global_s_options, "status"))
+ sy--;
+ if (sx == 0)
+ sx = 1;
+ if (sy == 0)
+ sy = 1;
+ if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
+ cwd = ctx->cmdclient->cwd;
+ else
cwd = options_get_string(&global_s_options, "default-path");
+ if (data->cmd != NULL)
+ cmd = data->cmd;
else
- cwd = c->cwd;
-
- sx = 80;
- sy = 25;
- if (!data->flag_detached) {
- sx = c->tty.sx;
- sy = c->tty.sy;
- }
-
- if (options_get_number(&global_s_options, "status")) {
- if (sy == 0)
- sy = 1;
- else
- sy--;
- }
-
- if (!data->flag_detached && tty_open(&c->tty, &cause) != 0) {
- ctx->error(ctx, "open terminal failed: %s", cause);
- xfree(cause);
- return (-1);
- }
-
+ cmd = options_get_string(&global_s_options, "default-command");
+ /* Create the new session. */
s = session_create(data->newname, cmd, cwd, sx, sy, &cause);
if (s == NULL) {
ctx->error(ctx, "create session failed: %s", cause);
xfree(cause);
return (-1);
}
+
if (data->winname != NULL) {
xfree(s->curw->window->name);
s->curw->window->name = xstrdup(data->winname);
@@ -177,17 +192,31 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
&s->curw->window->options, "automatic-rename", 0);
}
- if (data->flag_detached) {
- if (c != NULL)
- server_write_client(c, MSG_EXIT, NULL, 0);
- } else {
- c->session = s;
- server_write_client(c, MSG_READY, NULL, 0);
- server_redraw_client(c);
+ /*
+ * If a command client exists, it is either taking this session (and
+ * needs to get MSG_READY and stay around), or -d is given and it needs
+ * to exit.
+ */
+ if (ctx->cmdclient != NULL) {
+ if (!data->flag_detached)
+ server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
+ else
+ server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
+ }
+
+ /* Set the client to the new session. */
+ if (!data->flag_detached) {
+ if (ctx->cmdclient != NULL) {
+ ctx->cmdclient->session = s;
+ server_redraw_client(ctx->cmdclient);
+ } else {
+ ctx->curclient->session = s;
+ server_redraw_client(ctx->curclient);
+ }
}
recalculate_sizes();
- return (1);
+ return (1); /* 1 means don't tell command client to exit */
}
void
diff --git a/tmux.1 b/tmux.1
index 34501931..dcc30a25 100644
--- a/tmux.1
+++ b/tmux.1
@@ -596,7 +596,11 @@ The following commands are available:
.Op Fl t Ar target-session
.Xc
.D1 (alias: Ic attach )
-Create a new client in the current terminal and attach it to a session.
+If run from outside
+.Nm ,
+create a new client in the current terminal and attach it to
+.Ar target-session .
+If used from inside, switch the current client.
If
.Fl d
is specified, any other clients attached to the session are detached.
diff --git a/tmux.h b/tmux.h
index 0720b25b..60455df1 100644
--- a/tmux.h
+++ b/tmux.h
@@ -835,8 +835,18 @@ struct client_ctx {
struct cmd_ctx {
struct client *cmdclient;
+ /*
+ * curclient is the client where this command was executed if inside
+ * tmux. This is NULL if the command came from the command-line.
+ *
+ * cmdclient is the client which sent the MSG_COMMAND to the server, if
+ * any. This is NULL unless the command came from the command-line.
+ *
+ * One of curclient or cmdclient is always NULL and the other not.
+ */
struct client *curclient;
struct session *cursession;
+
struct msg_command_data *msgdata;
void (*print)(struct cmd_ctx *, const char *, ...);