mirror of
https://github.com/tmux/tmux.git
synced 2026-07-08 18:39:30 +00:00
Merge branch 'obsd-master'
This commit is contained in:
327
format.c
327
format.c
@@ -125,6 +125,8 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
||||
#define FORMAT_COLOUR_ESC_FG 0x8000000
|
||||
#define FORMAT_COLOUR_ESC_BG 0x10000000
|
||||
#define FORMAT_QUOTE_SHELL_SQ 0x20000000
|
||||
#define FORMAT_OPTIONS 0x40000000
|
||||
#define FORMAT_ENVIRON 0x80000000ULL
|
||||
|
||||
/* Limit on recursion. */
|
||||
#define FORMAT_LOOP_LIMIT 100
|
||||
@@ -4221,7 +4223,7 @@ format_relative_time(time_t t)
|
||||
|
||||
/* Find a format entry. */
|
||||
static char *
|
||||
format_find(struct format_tree *ft, const char *key, int modifiers,
|
||||
format_find(struct format_tree *ft, const char *key, uint64_t modifiers,
|
||||
const char *time_format)
|
||||
{
|
||||
const struct format_table_entry *fte;
|
||||
@@ -4551,7 +4553,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
|
||||
/*
|
||||
* Modifiers are a ; separated list of the forms:
|
||||
* l,m,C,a,b,c,d,I,n,t,w,q,E,T,S,W,P,R,<,>
|
||||
* l,m,C,a,b,c,d,I,n,t,w,q,E,T,S,W,P,O,V,R,<,>
|
||||
* =a
|
||||
* =/a
|
||||
* =/a/
|
||||
@@ -4570,7 +4572,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
break;
|
||||
|
||||
/* Check single character modifiers with no arguments. */
|
||||
if (strchr("labdnwETSWPL!<>", cp[0]) != NULL &&
|
||||
if (strchr("labdnwETSWPOVL!<>", cp[0]) != NULL &&
|
||||
format_is_end(cp[1])) {
|
||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||
cp++;
|
||||
@@ -4592,7 +4594,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
}
|
||||
|
||||
/* Now try single character with arguments. */
|
||||
if (strchr("ImCLNPSst=pReqWc", cp[0]) == NULL)
|
||||
if (strchr("ImCLNPSOVst=pReqWc", cp[0]) == NULL)
|
||||
break;
|
||||
c = cp[0];
|
||||
|
||||
@@ -4869,11 +4871,14 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "loop_index", "%d", i);
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
|
||||
format_defaults(nft, ft->c, s, NULL, NULL);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, use);
|
||||
format_free(next.ft);
|
||||
|
||||
@@ -4988,24 +4993,29 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
use = active;
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_WINDOW|w->id,
|
||||
ft->flags);
|
||||
nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
|
||||
|
||||
format_add(nft, "loop_index", "%d", i);
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
format_defaults(nft, ft->c, s, wl, NULL);
|
||||
|
||||
/* Add neighbour window data to the format tree. */
|
||||
format_add(nft, "window_after_active", "%d",
|
||||
i > 0 && l[i - 1] == s->curw);
|
||||
format_add(nft, "window_before_active", "%d",
|
||||
i + 1 < n && l[i + 1] == s->curw);
|
||||
if (i > 0 && l[i - 1] == s->curw)
|
||||
format_add(nft, "window_after_active", "1");
|
||||
else
|
||||
format_add(nft, "window_after_active", "0");
|
||||
if (i + 1 < n && l[i + 1] == s->curw)
|
||||
format_add(nft, "window_before_active", "1");
|
||||
else
|
||||
format_add(nft, "window_before_active", "0");
|
||||
if (i + 1 < n)
|
||||
format_add_window_neighbour(nft, l[i + 1], s, "next");
|
||||
if (i > 0)
|
||||
format_add_window_neighbour(nft, l[i - 1], s, "prev");
|
||||
|
||||
format_defaults(nft, ft->c, s, wl, NULL);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, use);
|
||||
format_free(nft);
|
||||
|
||||
@@ -5062,13 +5072,15 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
|
||||
use = active;
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_PANE|wp->id,
|
||||
ft->flags);
|
||||
nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);
|
||||
|
||||
format_add(nft, "loop_index", "%d", i);
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, use);
|
||||
format_free(nft);
|
||||
|
||||
@@ -5087,6 +5099,269 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Add an option to an options loop. */
|
||||
static void
|
||||
format_loop_add_option(struct format_expand_state *es, const char *fmt,
|
||||
struct evbuffer *buffer, struct options_entry *o, u_int n, u_int i)
|
||||
{
|
||||
struct format_tree *ft = es->ft, *nft;
|
||||
struct format_expand_state next;
|
||||
const struct options_table_entry *oe = options_table_entry(o);
|
||||
const char *name = options_name(o);
|
||||
char *expanded, *s;
|
||||
int is_array = options_is_array(o);
|
||||
|
||||
format_log(es, "option loop: %s", name);
|
||||
nft = format_create(ft->client, ft->item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "option_name", "%s", name);
|
||||
s = options_to_string(o, -1, 0);
|
||||
format_add(nft, "option_value", "%s", s);
|
||||
free(s);
|
||||
|
||||
format_add(nft, "option_is_array", "%d", is_array);
|
||||
format_add(nft, "option_array_index", "%s", "");
|
||||
format_add(nft, "option_array_first", "%d", is_array);
|
||||
format_add(nft, "option_array_last", "%d", is_array);
|
||||
format_add(nft, "option_array_count", "%u", n);
|
||||
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
|
||||
format_add(nft, "option_is_hook", "1");
|
||||
else
|
||||
format_add(nft, "option_is_hook", "0");
|
||||
format_add(nft, "option_is_user", "%d", oe == NULL);
|
||||
|
||||
if (options_next(o) == NULL)
|
||||
format_add(nft, "loop_last_flag", "1");
|
||||
else
|
||||
format_add(nft, "loop_last_flag", "0");
|
||||
format_add(nft, "loop_index", "%u", i);
|
||||
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(nft);
|
||||
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||
free(expanded);
|
||||
}
|
||||
|
||||
/* Add an array option item to an options loop. */
|
||||
static void
|
||||
format_loop_add_array_item(struct format_expand_state *es, const char *fmt,
|
||||
struct evbuffer *buffer, struct options_entry *o,
|
||||
struct options_array_item *a, int n, u_int i)
|
||||
{
|
||||
struct format_tree *ft = es->ft, *nft;
|
||||
struct format_expand_state next;
|
||||
const struct options_table_entry *oe = options_table_entry(o);
|
||||
const char *name = options_name(o);
|
||||
char *expanded, *s;
|
||||
u_int idx;
|
||||
|
||||
idx = options_array_item_index(a);
|
||||
format_log(es, "option loop: %s[%u]", name, idx);
|
||||
nft = format_create(ft->client, ft->item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "option_name", "%s", name);
|
||||
s = options_to_string(o, idx, 0);
|
||||
format_add(nft, "option_value", "%s", s);
|
||||
free(s);
|
||||
|
||||
format_add(nft, "option_is_array", "1");
|
||||
format_add(nft, "option_array_index", "%u", idx);
|
||||
if (a == options_array_first(o))
|
||||
format_add(nft, "option_array_first", "1");
|
||||
else
|
||||
format_add(nft, "option_array_first", "0");
|
||||
if (options_array_next(a) == NULL)
|
||||
format_add(nft, "option_array_last", "1");
|
||||
else
|
||||
format_add(nft, "option_array_last", "0");
|
||||
format_add(nft, "option_array_count", "%u", n);
|
||||
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
|
||||
format_add(nft, "option_is_hook", "1");
|
||||
else
|
||||
format_add(nft, "option_is_hook", "0");
|
||||
format_add(nft, "option_is_user", "%d", oe == NULL);
|
||||
|
||||
if (options_array_next(a) == NULL && options_next(o) == NULL)
|
||||
format_add(nft, "loop_last_flag", "1");
|
||||
else
|
||||
format_add(nft, "loop_last_flag", "0");
|
||||
format_add(nft, "loop_index", "%u", i);
|
||||
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(nft);
|
||||
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||
free(expanded);
|
||||
}
|
||||
|
||||
/* Loop over options. */
|
||||
static char *
|
||||
format_loop_options(struct format_expand_state *es, const char *fmt,
|
||||
const char *flags)
|
||||
{
|
||||
struct format_tree *ft = es->ft;
|
||||
struct options *oo = NULL;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
char *value;
|
||||
struct evbuffer *buffer;
|
||||
size_t size;
|
||||
u_int i = 0, n;
|
||||
int global = 0;
|
||||
|
||||
if (flags == NULL || *flags == '\0')
|
||||
flags = "s";
|
||||
if (strchr(flags, 'v') != NULL)
|
||||
oo = global_options;
|
||||
else {
|
||||
if (strchr(flags, 'g') != NULL)
|
||||
global = 1;
|
||||
if (strchr(flags, 'w') != NULL) {
|
||||
if (global)
|
||||
oo = global_w_options;
|
||||
else if (ft->w != NULL)
|
||||
oo = ft->w->options;
|
||||
} else if (strchr(flags, 's') != NULL) {
|
||||
if (global)
|
||||
oo = global_s_options;
|
||||
else if (ft->s != NULL)
|
||||
oo = ft->s->options;
|
||||
} else if (strchr(flags, 'p') != NULL) {
|
||||
if (global)
|
||||
/* invalid */;
|
||||
else if (ft->wp != NULL)
|
||||
oo = ft->wp->options;
|
||||
} else if (global)
|
||||
oo = global_s_options;
|
||||
}
|
||||
if (oo == NULL)
|
||||
return (xstrdup(""));
|
||||
|
||||
buffer = evbuffer_new();
|
||||
if (buffer == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
|
||||
n = 0;
|
||||
if (options_is_array(o)) {
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
n++;
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (!options_is_array(o) || n == 0) {
|
||||
format_loop_add_option(es, fmt, buffer, o, n, i);
|
||||
i++;
|
||||
o = options_next(o);
|
||||
continue;
|
||||
}
|
||||
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
format_loop_add_array_item(es, fmt, buffer, o, a, n, i);
|
||||
i++;
|
||||
a = options_array_next(a);
|
||||
}
|
||||
o = options_next(o);
|
||||
}
|
||||
|
||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||
else
|
||||
value = xstrdup("");
|
||||
evbuffer_free(buffer);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Loop over an environment. */
|
||||
static char *
|
||||
format_loop_environ(struct format_expand_state *es, const char *fmt,
|
||||
const char *flags)
|
||||
{
|
||||
struct format_tree *ft = es->ft, *nft;
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_expand_state next;
|
||||
struct environ *env = NULL;
|
||||
struct environ_entry *envent;
|
||||
char *expanded, *value;
|
||||
struct evbuffer *buffer;
|
||||
size_t size;
|
||||
u_int i = 0;
|
||||
|
||||
if (flags == NULL || *flags == '\0' || strcmp(flags, "s") == 0) {
|
||||
if (ft->s != NULL)
|
||||
env = ft->s->environ;
|
||||
} else if (strcmp(flags, "g") == 0)
|
||||
env = global_environ;
|
||||
else if (strcmp(flags, "c") == 0) {
|
||||
if (ft->client != NULL)
|
||||
env = ft->client->environ;
|
||||
}
|
||||
if (env == NULL)
|
||||
return (xstrdup(""));
|
||||
|
||||
buffer = evbuffer_new();
|
||||
if (buffer == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
envent = environ_first(env);
|
||||
while (envent != NULL) {
|
||||
format_log(es, "environment loop: %s", envent->name);
|
||||
nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "environ_name", "%s", envent->name);
|
||||
if (envent->value == NULL)
|
||||
format_add(nft, "environ_value", "%s", "");
|
||||
else
|
||||
format_add(nft, "environ_value", "%s", envent->value);
|
||||
|
||||
if (envent->flags & ENVIRON_HIDDEN)
|
||||
format_add(nft, "environ_hidden", "1");
|
||||
else
|
||||
format_add(nft, "environ_hidden", "0");
|
||||
format_add(nft, "environ_removed", "%d", envent->value == NULL);
|
||||
|
||||
if (environ_next(envent) == NULL)
|
||||
format_add(nft, "loop_last_flag", "1");
|
||||
else
|
||||
format_add(nft, "loop_last_flag", "0");
|
||||
format_add(nft, "loop_index", "%u", i);
|
||||
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, ft->wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(nft);
|
||||
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||
free(expanded);
|
||||
|
||||
i++;
|
||||
envent = environ_next(envent);
|
||||
}
|
||||
|
||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||
else
|
||||
value = xstrdup("");
|
||||
evbuffer_free(buffer);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Loop over clients. */
|
||||
static char *
|
||||
format_loop_clients(struct format_expand_state *es, const char *fmt)
|
||||
@@ -5111,14 +5386,16 @@ format_loop_clients(struct format_expand_state *es, const char *fmt)
|
||||
c = l[i];
|
||||
format_log(es, "client loop: %s", c->name);
|
||||
nft = format_create(c, item, 0, ft->flags);
|
||||
|
||||
format_add(nft, "loop_index", "%d", i);
|
||||
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||
|
||||
format_defaults(nft, c, ft->s, ft->wl, ft->wp);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(nft);
|
||||
|
||||
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||
free(expanded);
|
||||
}
|
||||
@@ -5288,12 +5565,14 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
char *copy0, *condition, *found, *new;
|
||||
char *value, *left, *right;
|
||||
size_t valuelen;
|
||||
int modifiers = 0, limit = 0, width = 0;
|
||||
uint64_t modifiers = 0;
|
||||
int limit = 0, width = 0;
|
||||
int j, c;
|
||||
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
||||
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
||||
struct format_modifier *bool_op_n = NULL;
|
||||
u_int i, count, nsub = 0, nrep, check = 0;
|
||||
const char *loop_flags = "";
|
||||
struct format_expand_state next;
|
||||
struct environ_entry *envent;
|
||||
|
||||
@@ -5491,6 +5770,16 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
else
|
||||
sc->reversed = 0;
|
||||
break;
|
||||
case 'O':
|
||||
modifiers |= FORMAT_OPTIONS;
|
||||
if (fm->argc == 1)
|
||||
loop_flags = fm->argv[0];
|
||||
break;
|
||||
case 'V':
|
||||
modifiers |= FORMAT_ENVIRON;
|
||||
if (fm->argc == 1)
|
||||
loop_flags = fm->argv[0];
|
||||
break;
|
||||
case 'L':
|
||||
modifiers |= FORMAT_CLIENTS;
|
||||
if (fm->argc < 1) {
|
||||
@@ -5626,6 +5915,14 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
value = format_loop_clients(es, copy);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (modifiers & FORMAT_OPTIONS) {
|
||||
value = format_loop_options(es, copy, loop_flags);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (modifiers & FORMAT_ENVIRON) {
|
||||
value = format_loop_environ(es, copy, loop_flags);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (modifiers & FORMAT_WINDOW_NAME) {
|
||||
value = format_window_name(es, copy);
|
||||
if (value == NULL)
|
||||
|
||||
35
tmux.1
35
tmux.1
@@ -3255,7 +3255,7 @@ If
|
||||
is floating and
|
||||
.Ar dst\-pane
|
||||
is either unspecified or equal to
|
||||
.Ar src\-pane,
|
||||
.Ar src\-pane ,
|
||||
.Ar src\-pane
|
||||
is returned to its previous position in the layout.
|
||||
.Tg killp
|
||||
@@ -3851,7 +3851,7 @@ This command will automatically set
|
||||
to manual in the window options.
|
||||
.Tg respawnp
|
||||
.It Xo Ic respawn\-pane
|
||||
.Op Fl Ek
|
||||
.Op Fl \&Ek
|
||||
.Op Fl c Ar start\-directory
|
||||
.Op Fl e Ar environment
|
||||
.Op Fl t Ar target\-pane
|
||||
@@ -3880,7 +3880,7 @@ option has the same meaning as for the
|
||||
command.
|
||||
.Tg respawnw
|
||||
.It Xo Ic respawn\-window
|
||||
.Op Fl Ek
|
||||
.Op Fl \&Ek
|
||||
.Op Fl c Ar start\-directory
|
||||
.Op Fl e Ar environment
|
||||
.Op Fl t Ar target\-window
|
||||
@@ -6773,7 +6773,7 @@ will use shorter but less accurate time format for times in the past.
|
||||
.Ql r
|
||||
.Pq Ql t/r
|
||||
will show the time relative to the current time, for example
|
||||
.Ql \1m
|
||||
.Ql \&1m
|
||||
or
|
||||
.Ql 2m23s .
|
||||
A custom format may be given using an
|
||||
@@ -6899,6 +6899,33 @@ prefix, for example a user option
|
||||
on the next window is available as
|
||||
.Ql next_@color .
|
||||
.Pp
|
||||
.Ql O:\&
|
||||
will loop over each option;
|
||||
array options are looped once for each array item.
|
||||
.Ql O:\&
|
||||
may be given a flag to choose the options table:
|
||||
.Bl -column "Flag" "Table" -offset indent
|
||||
.It Sy "Flag" Ta Sy "Table"
|
||||
.It Li "s" Ta "session"
|
||||
.It Li "w" Ta "window"
|
||||
.It Li "p" Ta "pane"
|
||||
.It Li "v" Ta "server"
|
||||
.El
|
||||
.Pp
|
||||
.Ql g
|
||||
chooses global options.
|
||||
The default is
|
||||
.Ql s .
|
||||
.Ql V:\&
|
||||
will loop over each environment variable.
|
||||
Its flags are:
|
||||
.Bl -column "Flag" "Environment" -offset indent
|
||||
.It Sy "Flag" Ta Sy "Environment"
|
||||
.It Li "s" Ta "session environment"
|
||||
.It Li "g" Ta "global environment"
|
||||
.It Li "c" Ta "client environment"
|
||||
.El
|
||||
.Pp
|
||||
.Ql N:\&
|
||||
checks if a window (without any suffix or with the
|
||||
.Ql w
|
||||
|
||||
Reference in New Issue
Block a user