Skip to content

Commit 6880dff

Browse files
committed
Add S: to list sessions with modifiers for sorting, from Michael Grant.
1 parent 2052841 commit 6880dff

File tree

2 files changed

+109
-16
lines changed

2 files changed

+109
-16
lines changed

usr.bin/tmux/format.c

Lines changed: 95 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: format.c,v 1.332 2025/05/12 10:26:19 nicm Exp $ */
1+
/* $OpenBSD: format.c,v 1.333 2025/06/20 13:31:59 nicm Exp $ */
22

33
/*
44
* Copyright (c) 2011 Nicholas Marriott <[email protected]>
@@ -132,6 +132,18 @@ enum format_type {
132132
FORMAT_TYPE_PANE
133133
};
134134

135+
/* Format loop sort type. */
136+
enum format_loop_sort_type {
137+
FORMAT_LOOP_BY_INDEX,
138+
FORMAT_LOOP_BY_NAME,
139+
FORMAT_LOOP_BY_TIME,
140+
};
141+
142+
static struct format_loop_sort_criteria {
143+
u_int field;
144+
int reversed;
145+
} format_loop_sort_criteria;
146+
135147
struct format_tree {
136148
enum format_type type;
137149

@@ -4028,7 +4040,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
40284040
}
40294041

40304042
/* Now try single character with arguments. */
4031-
if (strchr("mCNst=pReq", cp[0]) == NULL)
4043+
if (strchr("mCNSst=pReq", cp[0]) == NULL)
40324044
break;
40334045
c = cp[0];
40344046

@@ -4224,29 +4236,86 @@ format_session_name(struct format_expand_state *es, const char *fmt)
42244236
return (xstrdup("0"));
42254237
}
42264238

4239+
static int
4240+
format_cmp_session(const void *a0, const void *b0)
4241+
{
4242+
const struct session *const *a = a0;
4243+
const struct session *const *b = b0;
4244+
const struct session *sa = *a;
4245+
const struct session *sb = *b;
4246+
int result = 0;
4247+
4248+
switch (format_loop_sort_criteria.field) {
4249+
case FORMAT_LOOP_BY_INDEX:
4250+
result = sa->id - sb->id;
4251+
break;
4252+
case FORMAT_LOOP_BY_TIME:
4253+
if (timercmp(&sa->activity_time, &sb->activity_time, >)) {
4254+
result = -1;
4255+
break;
4256+
}
4257+
if (timercmp(&sa->activity_time, &sb->activity_time, <)) {
4258+
result = 1;
4259+
break;
4260+
}
4261+
/* FALLTHROUGH */
4262+
case FORMAT_LOOP_BY_NAME:
4263+
result = strcmp(sa->name, sb->name);
4264+
break;
4265+
}
4266+
4267+
if (format_loop_sort_criteria.reversed)
4268+
result = -result;
4269+
return (result);
4270+
}
4271+
42274272
/* Loop over sessions. */
42284273
static char *
42294274
format_loop_sessions(struct format_expand_state *es, const char *fmt)
42304275
{
4231-
struct format_tree *ft = es->ft;
4232-
struct client *c = ft->client;
4233-
struct cmdq_item *item = ft->item;
4234-
struct format_tree *nft;
4235-
struct format_expand_state next;
4236-
char *expanded, *value;
4237-
size_t valuelen;
4238-
struct session *s;
4276+
struct format_tree *ft = es->ft;
4277+
struct client *c = ft->client;
4278+
struct cmdq_item *item = ft->item;
4279+
struct format_tree *nft;
4280+
struct format_expand_state next;
4281+
char *all, *active, *use, *expanded, *value;
4282+
size_t valuelen;
4283+
struct session *s;
4284+
int i, n;
4285+
static struct session **l = NULL;
4286+
static int lsz = 0;
4287+
4288+
if (format_choose(es, fmt, &all, &active, 0) != 0) {
4289+
all = xstrdup(fmt);
4290+
active = NULL;
4291+
}
4292+
4293+
n = 0;
4294+
RB_FOREACH(s, sessions, &sessions) {
4295+
if (lsz <= n) {
4296+
lsz += 100;
4297+
l = xreallocarray(l, lsz, sizeof *l);
4298+
}
4299+
l[n++] = s;
4300+
}
4301+
4302+
qsort(l, n, sizeof *l, format_cmp_session);
42394303

42404304
value = xcalloc(1, 1);
42414305
valuelen = 1;
42424306

4243-
RB_FOREACH(s, sessions, &sessions) {
4307+
for (i = 0; i < n; i++) {
4308+
s = l[i];
42444309
format_log(es, "session loop: $%u", s->id);
4310+
if (active != NULL && s->id == ft->c->session->id)
4311+
use = active;
4312+
else
4313+
use = all;
42454314
nft = format_create(c, item, FORMAT_NONE, ft->flags);
42464315
format_defaults(nft, ft->c, s, NULL, NULL);
42474316
format_copy_state(&next, es, 0);
42484317
next.ft = nft;
4249-
expanded = format_expand1(&next, fmt);
4318+
expanded = format_expand1(&next, use);
42504319
format_free(next.ft);
42514320

42524321
valuelen += strlen(expanded);
@@ -4585,6 +4654,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
45854654
struct format_modifier *bool_op_n = NULL;
45864655
u_int i, count, nsub = 0, nrep;
45874656
struct format_expand_state next;
4657+
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
45884658

45894659
/* Make a copy of the key. */
45904660
copy = copy0 = xstrndup(key, keylen);
@@ -4695,6 +4765,19 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
46954765
break;
46964766
case 'S':
46974767
modifiers |= FORMAT_SESSIONS;
4768+
if (fm->argc < 1)
4769+
break;
4770+
if (strchr(fm->argv[0], 'i') != NULL)
4771+
sc->field = FORMAT_LOOP_BY_INDEX;
4772+
else if (strchr(fm->argv[0], 'n') != NULL)
4773+
sc->field = FORMAT_LOOP_BY_NAME;
4774+
else if (strchr(fm->argv[0], 't') != NULL)
4775+
sc->field = FORMAT_LOOP_BY_TIME;
4776+
else sc->field = FORMAT_LOOP_BY_INDEX;
4777+
if (strchr(fm->argv[0], 'r') != NULL)
4778+
sc->reversed = 1;
4779+
else
4780+
sc->reversed = 0;
46984781
break;
46994782
case 'W':
47004783
modifiers |= FORMAT_WINDOWS;

usr.bin/tmux/tmux.1

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.\" $OpenBSD: tmux.1,v 1.1001 2025/05/28 09:53:57 nicm Exp $
1+
.\" $OpenBSD: tmux.1,v 1.1002 2025/06/20 13:31:59 nicm Exp $
22
.\"
33
.\" Copyright (c) 2007 Nicholas Marriott <[email protected]>
44
.\"
@@ -14,7 +14,7 @@
1414
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
1515
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616
.\"
17-
.Dd $Mdocdate: May 28 2025 $
17+
.Dd $Mdocdate: June 20 2025 $
1818
.Dt TMUX 1
1919
.Os
2020
.Sh NAME
@@ -5909,8 +5909,18 @@ or
59095909
.Ql L:\&
59105910
will loop over each session, window, pane or client and insert the format once
59115911
for each.
5912-
For windows and panes, two comma-separated formats may be given:
5913-
the second is used for the current window or active pane.
5912+
.Ql S:\& ,
5913+
can take an optional sort argument
5914+
.Ql /i\& ,
5915+
.Ql /n\& ,
5916+
.Ql /t\&
5917+
to sort by index, name, or time; or
5918+
.Ql /r\&
5919+
to sort in reverse order. For example,
5920+
.Ql S/nr:\&
5921+
to sort sessions by name in reverse order.
5922+
For each, two comma-separated formats may be given:
5923+
the second is used for the current window, active pane, or active session.
59145924
For example, to get a list of windows formatted like the status line:
59155925
.Bd -literal -offset indent
59165926
#{W:#{E:window-status-format} ,#{E:window-status-current-format} }

0 commit comments

Comments
 (0)