diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 03cb7c8d..913bb501 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -27,6 +27,7 @@ * Switch client to a different session. */ +void cmd_switch_client_init(struct cmd *, int); int cmd_switch_client_parse(struct cmd *, int, char **, char **); int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *); void cmd_switch_client_free(struct cmd *); @@ -35,28 +36,50 @@ size_t cmd_switch_client_print(struct cmd *, char *, size_t); struct cmd_switch_client_data { char *name; char *target; + int flag_next; + int flag_previous; }; const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", - "[-c target-client] [-t target-session]", + "[-np] [-c target-client] [-t target-session]", 0, "", - NULL, + cmd_switch_client_init, cmd_switch_client_parse, cmd_switch_client_exec, cmd_switch_client_free, cmd_switch_client_print }; +void +cmd_switch_client_init(struct cmd *self, int key) +{ + struct cmd_switch_client_data *data; + + self->data = data = xmalloc(sizeof *data); + data->name = NULL; + data->target = NULL; + data->flag_next = 0; + data->flag_previous = 0; + + switch (key) { + case '(': + data->flag_previous = 1; + break; + case ')': + data->flag_next = 1; + break; + } +} + int cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_switch_client_data *data; int opt; - self->data = data = xmalloc(sizeof *data); - data->name = NULL; - data->target = NULL; + self->entry->init(self, KEYC_NONE); + data = self->data; while ((opt = getopt(argc, argv, "c:t:")) != -1) { switch (opt) { @@ -65,9 +88,21 @@ cmd_switch_client_parse(struct cmd *self, int argc, char **argv, char **cause) data->name = xstrdup(optarg); break; case 't': + if (data->flag_next || data->flag_previous) + goto usage; if (data->target == NULL) data->target = xstrdup(optarg); break; + case 'n': + if (data->flag_previous || data->target != NULL) + goto usage; + data->flag_next = 1; + break; + case 'p': + if (data->flag_next || data->target != NULL) + goto usage; + data->flag_next = 1; + break; default: goto usage; } @@ -98,9 +133,22 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx) if ((c = cmd_find_client(ctx, data->name)) == NULL) return (-1); - if ((s = cmd_find_session(ctx, data->target)) == NULL) - return (-1); + if (data->flag_next) { + if ((s = session_next_session(c->session)) == NULL) { + ctx->error(ctx, "can't find next session"); + return (-1); + } + } else if (data->flag_previous) { + if ((s = session_previous_session(c->session)) == NULL) { + ctx->error(ctx, "can't find previous session"); + return (-1); + } + } else + s = cmd_find_session(ctx, data->target); + + if (s == NULL) + return (-1); c->session = s; recalculate_sizes(); @@ -130,6 +178,10 @@ cmd_switch_client_print(struct cmd *self, char *buf, size_t len) off += xsnprintf(buf, len, "%s", self->entry->name); if (data == NULL) return (off); + if (off < len && data->flag_next) + off += xsnprintf(buf + off, len - off, "%s", " -n"); + if (off < len && data->flag_previous) + off += xsnprintf(buf + off, len - off, "%s", " -p"); if (off < len && data->name != NULL) off += cmd_prarg(buf + off, len - off, " -c ", data->name); if (off < len && data->target != NULL) diff --git a/key-bindings.c b/key-bindings.c index 2a039af0..61d392d3 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -108,6 +108,8 @@ key_bindings_init(void) { '#', 0, &cmd_list_buffers_entry }, { '%', 0, &cmd_split_window_entry }, { '&', 0, &cmd_confirm_before_entry }, + { '(', 0, &cmd_switch_client_entry }, + { ')', 0, &cmd_switch_client_entry }, { ',', 0, &cmd_command_prompt_entry }, { '-', 0, &cmd_delete_buffer_entry }, { '.', 0, &cmd_command_prompt_entry }, diff --git a/session.c b/session.c index b164eef8..7d3fb32d 100644 --- a/session.c +++ b/session.c @@ -169,6 +169,48 @@ session_index(struct session *s, u_int *i) return (-1); } +/* Find the next usable session. */ +struct session * +session_next_session(struct session *s) +{ + struct session *s2; + u_int i; + + if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) + return (NULL); + + do { + if (i == ARRAY_LENGTH(&sessions) - 1) + i = 0; + else + i++; + s2 = ARRAY_ITEM(&sessions, i); + } while (s2 == NULL || s2->flags & SESSION_DEAD); + + return (s2); +} + +/* Find the previous usable session. */ +struct session * +session_previous_session(struct session *s) +{ + struct session *s2; + u_int i; + + if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) + return (NULL); + + do { + if (i == 0) + i = ARRAY_LENGTH(&sessions) - 1; + else + i--; + s2 = ARRAY_ITEM(&sessions, i); + } while (s2 == NULL || s2->flags & SESSION_DEAD); + + return (s2); +} + /* Create a new window on a session. */ struct winlink * session_new(struct session *s, diff --git a/tmux.1 b/tmux.1 index 38f0687f..f1894113 100644 --- a/tmux.1 +++ b/tmux.1 @@ -660,6 +660,7 @@ Suspend a client by sending .Dv SIGTSTP (tty stop). .It Xo Ic switch-client +.Op Fl np .Op Fl c Ar target-client .Op Fl t Ar target-session .Xc @@ -668,6 +669,11 @@ Switch the current session for client .Ar target-client to .Ar target-session . +If +.Fl n +or +.Fl p +is used, the client is moved to the next or previous session respectively. .El .Sh WINDOWS AND PANES A diff --git a/tmux.h b/tmux.h index a68bd0ea..34274b50 100644 --- a/tmux.h +++ b/tmux.h @@ -1965,6 +1965,8 @@ struct session *session_create(const char *, const char *, const char *, char **); void session_destroy(struct session *); int session_index(struct session *, u_int *); +struct session *session_next_session(struct session *); +struct session *session_previous_session(struct session *); struct winlink *session_new(struct session *, const char *, const char *, const char *, int, char **); struct winlink *session_attach(