aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd-new-session.c49
-rw-r--r--cmd-swap-window.c4
-rw-r--r--format.c4
-rw-r--r--server-fn.c12
-rw-r--r--server.c3
-rw-r--r--session.c93
-rw-r--r--tmux.133
-rw-r--r--tmux.h22
8 files changed, 135 insertions, 85 deletions
diff --git a/cmd-new-session.c b/cmd-new-session.c
index deda88f2..08fc6065 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -68,12 +68,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct client *c = item->client;
- struct session *s, *as;
- struct session *groupwith = item->state.tflag.s;
+ struct session *s, *as, *groupwith;
struct window *w;
struct environ *env;
struct termios tio, *tiop;
- const char *newname, *target, *errstr, *template;
+ struct session_group *sg;
+ const char *newname, *errstr, *template, *group, *prefix;
const char *path, *cmd, *cwd, *to_free = NULL;
char **argv, *cause, *cp;
int detached, already_attached, idx, argc;
@@ -119,13 +119,29 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
}
}
- if ((target = args_get(args, 't')) != NULL) {
+ /* Is this going to be part of a session group? */
+ group = args_get(args, 't');
+ if (group != NULL) {
+ groupwith = item->state.tflag.s;
if (groupwith == NULL) {
- cmdq_error(item, "no such session: %s", target);
- goto error;
- }
- } else
+ if (!session_check_name(group)) {
+ cmdq_error(item, "bad group name: %s", group);
+ goto error;
+ }
+ sg = session_group_find(group);
+ } else
+ sg = session_group_contains(groupwith);
+ if (sg != NULL)
+ prefix = sg->name;
+ else if (groupwith != NULL)
+ prefix = groupwith->name;
+ else
+ prefix = group;
+ } else {
groupwith = NULL;
+ sg = NULL;
+ prefix = NULL;
+ }
/* Set -d if no client. */
detached = args_has(args, 'd');
@@ -213,7 +229,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 't') && args->argc != 0) {
argc = args->argc;
argv = args->argv;
- } else if (groupwith == NULL) {
+ } else if (sg == NULL && groupwith == NULL) {
cmd = options_get_string(global_s_options, "default-command");
if (cmd != NULL && *cmd != '\0') {
argc = 1;
@@ -239,8 +255,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
/* Create the new session. */
idx = -1 - options_get_number(global_s_options, "base-index");
- s = session_create(newname, argc, argv, path, cwd, env, tiop, idx, sx,
- sy, &cause);
+ s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop,
+ idx, sx, sy, &cause);
environ_free(env);
if (s == NULL) {
cmdq_error(item, "create session failed: %s", cause);
@@ -259,8 +275,15 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* If a target session is given, this is to be part of a session group,
* so add it to the group and synchronize.
*/
- if (groupwith != NULL) {
- session_group_add(groupwith, s);
+ if (group != NULL) {
+ if (sg == NULL) {
+ if (groupwith != NULL) {
+ sg = session_group_new(groupwith->name);
+ session_group_add(sg, groupwith);
+ } else
+ sg = session_group_new(group);
+ }
+ session_group_add(sg, s);
session_group_synchronize_to(s);
session_select(s, RB_MIN(winlinks, &s->windows)->idx);
}
diff --git a/cmd-swap-window.c b/cmd-swap-window.c
index 0a93fa6e..38252745 100644
--- a/cmd-swap-window.c
+++ b/cmd-swap-window.c
@@ -52,11 +52,11 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
wl_src = item->state.sflag.wl;
src = item->state.sflag.s;
- sg_src = session_group_find(src);
+ sg_src = session_group_contains(src);
wl_dst = item->state.tflag.wl;
dst = item->state.tflag.s;
- sg_dst = session_group_find(dst);
+ sg_dst = session_group_contains(dst);
if (src != dst && sg_src != NULL && sg_dst != NULL &&
sg_src == sg_dst) {
diff --git a/format.c b/format.c
index 145c31f5..4df17025 100644
--- a/format.c
+++ b/format.c
@@ -1097,10 +1097,10 @@ format_defaults_session(struct format_tree *ft, struct session *s)
format_add(ft, "session_height", "%u", s->sy);
format_add(ft, "session_id", "$%u", s->id);
- sg = session_group_find(s);
+ sg = session_group_contains(s);
format_add(ft, "session_grouped", "%d", sg != NULL);
if (sg != NULL)
- format_add(ft, "session_group", "%u", session_group_index(sg));
+ format_add(ft, "session_group", "%s", sg->name);
format_add_tv(ft, "session_created", &s->creation_time);
format_add_tv(ft, "session_last_attached", &s->last_attached_time);
diff --git a/server-fn.c b/server-fn.c
index d43461f3..c14b4cab 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -78,7 +78,7 @@ server_redraw_session_group(struct session *s)
{
struct session_group *sg;
- if ((sg = session_group_find(s)) == NULL)
+ if ((sg = session_group_contains(s)) == NULL)
server_redraw_session(s);
else {
TAILQ_FOREACH(s, &sg->sessions, gentry)
@@ -102,7 +102,7 @@ server_status_session_group(struct session *s)
{
struct session_group *sg;
- if ((sg = session_group_find(s)) == NULL)
+ if ((sg = session_group_contains(s)) == NULL)
server_status_session(s);
else {
TAILQ_FOREACH(s, &sg->sessions, gentry)
@@ -220,7 +220,7 @@ server_kill_window(struct window *w)
}
if (options_get_number(s->options, "renumber-windows")) {
- if ((sg = session_group_find(s)) != NULL) {
+ if ((sg = session_group_contains(s)) != NULL) {
TAILQ_FOREACH(target_s, &sg->sessions, gentry)
session_renumber_windows(target_s);
} else
@@ -238,8 +238,8 @@ server_link_window(struct session *src, struct winlink *srcwl,
struct winlink *dstwl;
struct session_group *srcsg, *dstsg;
- srcsg = session_group_find(src);
- dstsg = session_group_find(dst);
+ srcsg = session_group_contains(src);
+ dstsg = session_group_contains(dst);
if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) {
xasprintf(cause, "sessions are grouped");
return (-1);
@@ -348,7 +348,7 @@ server_destroy_session_group(struct session *s)
struct session_group *sg;
struct session *s1;
- if ((sg = session_group_find(s)) == NULL)
+ if ((sg = session_group_contains(s)) == NULL)
server_destroy_session(s);
else {
TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) {
diff --git a/server.c b/server.c
index 176cafcb..0ce90db6 100644
--- a/server.c
+++ b/server.c
@@ -156,8 +156,7 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
RB_INIT(&all_window_panes);
TAILQ_INIT(&clients);
RB_INIT(&sessions);
- TAILQ_INIT(&session_groups);
- mode_key_init_trees();
+ RB_INIT(&session_groups);
key_bindings_init();
gettimeofday(&start_time, NULL);
diff --git a/session.c b/session.c
index 09c2dc26..5ffa2b87 100644
--- a/session.c
+++ b/session.c
@@ -42,6 +42,9 @@ static void session_group_remove(struct session *);
static u_int session_group_count(struct session_group *);
static void session_group_synchronize1(struct session *, struct session *);
+static u_int session_group_count(struct session_group *);
+static void session_group_synchronize1(struct session *, struct session *);
+
RB_GENERATE(sessions, session, entry, session_cmp);
int
@@ -50,6 +53,14 @@ session_cmp(struct session *s1, struct session *s2)
return (strcmp(s1->name, s2->name));
}
+RB_GENERATE(session_groups, session_group, entry, session_group_cmp);
+
+int
+session_group_cmp(struct session_group *s1, struct session_group *s2)
+{
+ return (strcmp(s1->name, s2->name));
+}
+
/*
* Find if session is still alive. This is true if it is still on the global
* sessions list.
@@ -107,9 +118,9 @@ session_find_by_id(u_int id)
/* Create a new session. */
struct session *
-session_create(const char *name, int argc, char **argv, const char *path,
- const char *cwd, struct environ *env, struct termios *tio, int idx,
- u_int sx, u_int sy, char **cause)
+session_create(const char *prefix, const char *name, int argc, char **argv,
+ const char *path, const char *cwd, struct environ *env, struct termios *tio,
+ int idx, u_int sx, u_int sy, char **cause)
{
struct session *s;
struct winlink *wl;
@@ -150,7 +161,10 @@ session_create(const char *name, int argc, char **argv, const char *path,
do {
s->id = next_session_id++;
free(s->name);
- xasprintf(&s->name, "%u", s->id);
+ if (prefix != NULL)
+ xasprintf(&s->name, "%s-%u", prefix, s->id);
+ else
+ xasprintf(&s->name, "%u", s->id);
} while (RB_FIND(sessions, &sessions, s) != NULL);
}
RB_INSERT(sessions, &sessions, s);
@@ -429,7 +443,7 @@ session_is_linked(struct session *s, struct window *w)
{
struct session_group *sg;
- if ((sg = session_group_find(s)) != NULL)
+ if ((sg = session_group_contains(s)) != NULL)
return (w->references != session_group_count(sg));
return (w->references != 1);
}
@@ -540,12 +554,12 @@ session_set_current(struct session *s, struct winlink *wl)
/* Find the session group containing a session. */
struct session_group *
-session_group_find(struct session *target)
+session_group_contains(struct session *target)
{
struct session_group *sg;
struct session *s;
- TAILQ_FOREACH(sg, &session_groups, entry) {
+ RB_FOREACH(sg, session_groups, &session_groups) {
TAILQ_FOREACH(s, &sg->sessions, gentry) {
if (s == target)
return (sg);
@@ -554,39 +568,39 @@ session_group_find(struct session *target)
return (NULL);
}
-/* Find session group index. */
-u_int
-session_group_index(struct session_group *sg)
+/* Find session group by name. */
+struct session_group *
+session_group_find(const char *name)
{
- struct session_group *sg2;
- u_int i;
-
- i = 0;
- TAILQ_FOREACH(sg2, &session_groups, entry) {
- if (sg == sg2)
- return (i);
- i++;
- }
+ struct session_group sg;
- fatalx("session group not found");
+ sg.name = name;
+ return (RB_FIND(session_groups, &session_groups, &sg));
}
-/*
- * Add a session to the session group containing target, creating it if
- * necessary.
- */
-void
-session_group_add(struct session *target, struct session *s)
+/* Create a new session group. */
+struct session_group *
+session_group_new(const char *name)
{
struct session_group *sg;
- if ((sg = session_group_find(target)) == NULL) {
- sg = xmalloc(sizeof *sg);
- TAILQ_INSERT_TAIL(&session_groups, sg, entry);
- TAILQ_INIT(&sg->sessions);
- TAILQ_INSERT_TAIL(&sg->sessions, target, gentry);
- }
- TAILQ_INSERT_TAIL(&sg->sessions, s, gentry);
+ if ((sg = session_group_find(name)) != NULL)
+ return (sg);
+
+ sg = xcalloc(1, sizeof *sg);
+ sg->name = xstrdup(name);
+ TAILQ_INIT(&sg->sessions);
+
+ RB_INSERT(session_groups, &session_groups, sg);
+ return (sg);
+}
+
+/* Add a session to a session group. */
+void
+session_group_add(struct session_group *sg, struct session *s)
+{
+ if (session_group_contains(s) == NULL)
+ TAILQ_INSERT_TAIL(&sg->sessions, s, gentry);
}
/* Remove a session from its group and destroy the group if empty. */
@@ -595,13 +609,11 @@ session_group_remove(struct session *s)
{
struct session_group *sg;
- if ((sg = session_group_find(s)) == NULL)
+ if ((sg = session_group_contains(s)) == NULL)
return;
TAILQ_REMOVE(&sg->sessions, s, gentry);
- if (TAILQ_NEXT(TAILQ_FIRST(&sg->sessions), gentry) == NULL)
- TAILQ_REMOVE(&sg->sessions, TAILQ_FIRST(&sg->sessions), gentry);
if (TAILQ_EMPTY(&sg->sessions)) {
- TAILQ_REMOVE(&session_groups, sg, entry);
+ RB_REMOVE(session_groups, &session_groups, sg);
free(sg);
}
}
@@ -626,7 +638,7 @@ session_group_synchronize_to(struct session *s)
struct session_group *sg;
struct session *target;
- if ((sg = session_group_find(s)) == NULL)
+ if ((sg = session_group_contains(s)) == NULL)
return;
target = NULL;
@@ -634,7 +646,8 @@ session_group_synchronize_to(struct session *s)
if (target != s)
break;
}
- session_group_synchronize1(target, s);
+ if (target != NULL)
+ session_group_synchronize1(target, s);
}
/* Synchronize a session group to a session. */
@@ -644,7 +657,7 @@ session_group_synchronize_from(struct session *target)
struct session_group *sg;
struct session *s;
- if ((sg = session_group_find(target)) == NULL)
+ if ((sg = session_group_contains(target)) == NULL)
return;
TAILQ_FOREACH(s, &sg->sessions, gentry) {
diff --git a/tmux.1 b/tmux.1
index a712519d..d4f5a891 100644
--- a/tmux.1
+++ b/tmux.1
@@ -812,7 +812,7 @@ Lock all clients attached to
.Op Fl F Ar format
.Op Fl n Ar window-name
.Op Fl s Ar session-name
-.Op Fl t Ar target-session
+.Op Fl t Ar group-name
.Op Fl x Ar width
.Op Fl y Ar height
.Op Ar shell-command
@@ -857,16 +857,27 @@ to
.Pp
If
.Fl t
-is given, the new session is
-.Em grouped
-with
-.Ar target-session .
-This means they share the same set of windows - all windows from
-.Ar target-session
-are linked to the new session, any new windows are linked to both sessions and
-any windows closed removed from both sessions.
+is given, it specifies a
+.Ic session group .
+Sessions in the same group share the same set of windows - new windows are
+linked to all sessions in the grouo and any windows closed removed from all
+sessions.
The current and previous window and any session options remain independent and
-either session may be killed without affecting the other.
+any session in a group may be killed without affecting the others.
+The
+.Ar group-name
+argument may be:
+.Bl -enum -width Ds
+.It
+the name of an existing group, in which case the new session is added to that
+group;
+.It
+the name of an existing session - the new session is added to the same group
+as that session, creating a new group if necessary;
+.It
+the name for a new group containing only the new session.
+.El
+.Pp
.Fl n
and
.Ar shell-command
@@ -3562,7 +3573,7 @@ The following variables are available, where appropriate:
.It Li "session_activity" Ta "" Ta "Integer time of session last activity"
.It Li "session_created" Ta "" Ta "Integer time session created"
.It Li "session_last_attached" Ta "" Ta "Integer time session last attached"
-.It Li "session_group" Ta "" Ta "Number of session group"
+.It Li "session_group" Ta "" Ta "Name of session group"
.It Li "session_grouped" Ta "" Ta "1 if session in a group"
.It Li "session_height" Ta "" Ta "Height of session"
.It Li "session_id" Ta "" Ta "Unique session ID"
diff --git a/tmux.h b/tmux.h
index 09c980df..2a5dbe65 100644
--- a/tmux.h
+++ b/tmux.h
@@ -901,11 +901,12 @@ struct environ_entry {
/* Client session. */
struct session_group {
- TAILQ_HEAD(, session) sessions;
+ const char *name;
+ TAILQ_HEAD(, session) sessions;
- TAILQ_ENTRY(session_group) entry;
+ RB_ENTRY(session_group) entry;
};
-TAILQ_HEAD(session_groups, session_group);
+RB_HEAD(session_groups, session_group);
struct session {
u_int id;
@@ -2210,13 +2211,15 @@ extern struct sessions sessions;
extern struct session_groups session_groups;
int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp);
+int session_group_cmp(struct session_group *, struct session_group *);
+RB_PROTOTYPE(session_groups, session_group, entry, session_group_cmp);
int session_alive(struct session *);
struct session *session_find(const char *);
struct session *session_find_by_id_str(const char *);
struct session *session_find_by_id(u_int);
-struct session *session_create(const char *, int, char **, const char *,
- const char *, struct environ *, struct termios *, int,
- u_int, u_int, char **);
+struct session *session_create(const char *, const char *, int, char **,
+ const char *, const char *, struct environ *,
+ struct termios *, int, u_int, u_int, char **);
void session_destroy(struct session *);
void session_unref(struct session *);
int session_check_name(const char *);
@@ -2235,9 +2238,10 @@ int session_previous(struct session *, int);
int session_select(struct session *, int);
int session_last(struct session *);
int session_set_current(struct session *, struct winlink *);
-struct session_group *session_group_find(struct session *);
-u_int session_group_index(struct session_group *);
-void session_group_add(struct session *, struct session *);
+struct session_group *session_group_contains(struct session *);
+struct session_group *session_group_find(const char *);
+struct session_group *session_group_new(const char *);
+void session_group_add(struct session_group *, struct session *);
void session_group_synchronize_to(struct session *);
void session_group_synchronize_from(struct session *);
void session_renumber_windows(struct session *);