Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam
2025-06-20 16:01:08 +01:00
2 changed files with 106 additions and 13 deletions

105
format.c
View File

@ -132,6 +132,18 @@ enum format_type {
FORMAT_TYPE_PANE FORMAT_TYPE_PANE
}; };
/* Format loop sort type. */
enum format_loop_sort_type {
FORMAT_LOOP_BY_INDEX,
FORMAT_LOOP_BY_NAME,
FORMAT_LOOP_BY_TIME,
};
static struct format_loop_sort_criteria {
u_int field;
int reversed;
} format_loop_sort_criteria;
struct format_tree { struct format_tree {
enum format_type type; enum format_type type;
@ -4032,7 +4044,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
} }
/* Now try single character with arguments. */ /* Now try single character with arguments. */
if (strchr("mCNst=pReq", cp[0]) == NULL) if (strchr("mCNSst=pReq", cp[0]) == NULL)
break; break;
c = cp[0]; c = cp[0];
@ -4228,29 +4240,86 @@ format_session_name(struct format_expand_state *es, const char *fmt)
return (xstrdup("0")); return (xstrdup("0"));
} }
static int
format_cmp_session(const void *a0, const void *b0)
{
const struct session *const *a = a0;
const struct session *const *b = b0;
const struct session *sa = *a;
const struct session *sb = *b;
int result = 0;
switch (format_loop_sort_criteria.field) {
case FORMAT_LOOP_BY_INDEX:
result = sa->id - sb->id;
break;
case FORMAT_LOOP_BY_TIME:
if (timercmp(&sa->activity_time, &sb->activity_time, >)) {
result = -1;
break;
}
if (timercmp(&sa->activity_time, &sb->activity_time, <)) {
result = 1;
break;
}
/* FALLTHROUGH */
case FORMAT_LOOP_BY_NAME:
result = strcmp(sa->name, sb->name);
break;
}
if (format_loop_sort_criteria.reversed)
result = -result;
return (result);
}
/* Loop over sessions. */ /* Loop over sessions. */
static char * static char *
format_loop_sessions(struct format_expand_state *es, const char *fmt) format_loop_sessions(struct format_expand_state *es, const char *fmt)
{ {
struct format_tree *ft = es->ft; struct format_tree *ft = es->ft;
struct client *c = ft->client; struct client *c = ft->client;
struct cmdq_item *item = ft->item; struct cmdq_item *item = ft->item;
struct format_tree *nft; struct format_tree *nft;
struct format_expand_state next; struct format_expand_state next;
char *expanded, *value; char *all, *active, *use, *expanded, *value;
size_t valuelen; size_t valuelen;
struct session *s; struct session *s;
int i, n;
static struct session **l = NULL;
static int lsz = 0;
if (format_choose(es, fmt, &all, &active, 0) != 0) {
all = xstrdup(fmt);
active = NULL;
}
n = 0;
RB_FOREACH(s, sessions, &sessions) {
if (lsz <= n) {
lsz += 100;
l = xreallocarray(l, lsz, sizeof *l);
}
l[n++] = s;
}
qsort(l, n, sizeof *l, format_cmp_session);
value = xcalloc(1, 1); value = xcalloc(1, 1);
valuelen = 1; valuelen = 1;
RB_FOREACH(s, sessions, &sessions) { for (i = 0; i < n; i++) {
s = l[i];
format_log(es, "session loop: $%u", s->id); format_log(es, "session loop: $%u", s->id);
if (active != NULL && s->id == ft->c->session->id)
use = active;
else
use = all;
nft = format_create(c, item, FORMAT_NONE, ft->flags); nft = format_create(c, item, FORMAT_NONE, ft->flags);
format_defaults(nft, ft->c, s, NULL, NULL); format_defaults(nft, ft->c, s, NULL, NULL);
format_copy_state(&next, es, 0); format_copy_state(&next, es, 0);
next.ft = nft; next.ft = nft;
expanded = format_expand1(&next, fmt); expanded = format_expand1(&next, use);
format_free(next.ft); format_free(next.ft);
valuelen += strlen(expanded); valuelen += strlen(expanded);
@ -4589,6 +4658,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
struct format_modifier *bool_op_n = NULL; struct format_modifier *bool_op_n = NULL;
u_int i, count, nsub = 0, nrep; u_int i, count, nsub = 0, nrep;
struct format_expand_state next; struct format_expand_state next;
struct format_loop_sort_criteria *sc = &format_loop_sort_criteria;
/* Make a copy of the key. */ /* Make a copy of the key. */
copy = copy0 = xstrndup(key, keylen); copy = copy0 = xstrndup(key, keylen);
@ -4699,6 +4769,19 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
break; break;
case 'S': case 'S':
modifiers |= FORMAT_SESSIONS; modifiers |= FORMAT_SESSIONS;
if (fm->argc < 1)
break;
if (strchr(fm->argv[0], 'i') != NULL)
sc->field = FORMAT_LOOP_BY_INDEX;
else if (strchr(fm->argv[0], 'n') != NULL)
sc->field = FORMAT_LOOP_BY_NAME;
else if (strchr(fm->argv[0], 't') != NULL)
sc->field = FORMAT_LOOP_BY_TIME;
else sc->field = FORMAT_LOOP_BY_INDEX;
if (strchr(fm->argv[0], 'r') != NULL)
sc->reversed = 1;
else
sc->reversed = 0;
break; break;
case 'W': case 'W':
modifiers |= FORMAT_WINDOWS; modifiers |= FORMAT_WINDOWS;

14
tmux.1
View File

@ -5911,8 +5911,18 @@ or
.Ql L:\& .Ql L:\&
will loop over each session, window, pane or client and insert the format once will loop over each session, window, pane or client and insert the format once
for each. for each.
For windows and panes, two comma-separated formats may be given: .Ql S:\& ,
the second is used for the current window or active pane. can take an optional sort argument
.Ql /i\& ,
.Ql /n\& ,
.Ql /t\&
to sort by index, name, or time; or
.Ql /r\&
to sort in reverse order. For example,
.Ql S/nr:\&
to sort sessions by name in reverse order.
For each, two comma-separated formats may be given:
the second is used for the current window, active pane, or active session.
For example, to get a list of windows formatted like the status line: For example, to get a list of windows formatted like the status line:
.Bd -literal -offset indent .Bd -literal -offset indent
#{W:#{E:window-status-format} ,#{E:window-status-current-format} } #{W:#{E:window-status-format} ,#{E:window-status-current-format} }