|
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 $ */ |
2 | 2 |
|
3 | 3 | /*
|
4 | 4 | * Copyright (c) 2011 Nicholas Marriott <[email protected]>
|
@@ -132,6 +132,18 @@ enum format_type {
|
132 | 132 | FORMAT_TYPE_PANE
|
133 | 133 | };
|
134 | 134 |
|
| 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 | + |
135 | 147 | struct format_tree {
|
136 | 148 | enum format_type type;
|
137 | 149 |
|
@@ -4028,7 +4040,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
4028 | 4040 | }
|
4029 | 4041 |
|
4030 | 4042 | /* Now try single character with arguments. */
|
4031 |
| - if (strchr("mCNst=pReq", cp[0]) == NULL) |
| 4043 | + if (strchr("mCNSst=pReq", cp[0]) == NULL) |
4032 | 4044 | break;
|
4033 | 4045 | c = cp[0];
|
4034 | 4046 |
|
@@ -4224,29 +4236,86 @@ format_session_name(struct format_expand_state *es, const char *fmt)
|
4224 | 4236 | return (xstrdup("0"));
|
4225 | 4237 | }
|
4226 | 4238 |
|
| 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 | + |
4227 | 4272 | /* Loop over sessions. */
|
4228 | 4273 | static char *
|
4229 | 4274 | format_loop_sessions(struct format_expand_state *es, const char *fmt)
|
4230 | 4275 | {
|
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); |
4239 | 4303 |
|
4240 | 4304 | value = xcalloc(1, 1);
|
4241 | 4305 | valuelen = 1;
|
4242 | 4306 |
|
4243 |
| - RB_FOREACH(s, sessions, &sessions) { |
| 4307 | + for (i = 0; i < n; i++) { |
| 4308 | + s = l[i]; |
4244 | 4309 | 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; |
4245 | 4314 | nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
4246 | 4315 | format_defaults(nft, ft->c, s, NULL, NULL);
|
4247 | 4316 | format_copy_state(&next, es, 0);
|
4248 | 4317 | next.ft = nft;
|
4249 |
| - expanded = format_expand1(&next, fmt); |
| 4318 | + expanded = format_expand1(&next, use); |
4250 | 4319 | format_free(next.ft);
|
4251 | 4320 |
|
4252 | 4321 | valuelen += strlen(expanded);
|
@@ -4585,6 +4654,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
4585 | 4654 | struct format_modifier *bool_op_n = NULL;
|
4586 | 4655 | u_int i, count, nsub = 0, nrep;
|
4587 | 4656 | struct format_expand_state next;
|
| 4657 | + struct format_loop_sort_criteria *sc = &format_loop_sort_criteria; |
4588 | 4658 |
|
4589 | 4659 | /* Make a copy of the key. */
|
4590 | 4660 | copy = copy0 = xstrndup(key, keylen);
|
@@ -4695,6 +4765,19 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
4695 | 4765 | break;
|
4696 | 4766 | case 'S':
|
4697 | 4767 | 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; |
4698 | 4781 | break;
|
4699 | 4782 | case 'W':
|
4700 | 4783 | modifiers |= FORMAT_WINDOWS;
|
|
0 commit comments