Instead of numbering session groups, give them a name which may be given

to -t instead of a target session. Also allow them to contain only one
session.
pull/777/merge
nicm 2017-02-09 15:04:53 +00:00
parent 8de4c15dfa
commit c6a3446398
8 changed files with 135 additions and 85 deletions

View File

@ -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);
}

View File

@ -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) {

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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;
struct session_group sg;
i = 0;
TAILQ_FOREACH(sg2, &session_groups, entry) {
if (sg == sg2)
return (i);
i++;
}
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) {

33
tmux.1
View File

@ -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"

22
tmux.h
View File

@ -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 *);