mirror of
https://github.com/tmux/tmux.git
synced 2025-09-04 15:16:57 +00:00
Add more features for boolean expressions in formats: 1) extend && and
|| to support arbitrarily many arguments and 2) add ! and !! for not and not-not.
This commit is contained in:
94
format.c
94
format.c
@ -104,6 +104,8 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
|||||||
#define FORMAT_CHARACTER 0x10000
|
#define FORMAT_CHARACTER 0x10000
|
||||||
#define FORMAT_COLOUR 0x20000
|
#define FORMAT_COLOUR 0x20000
|
||||||
#define FORMAT_CLIENTS 0x40000
|
#define FORMAT_CLIENTS 0x40000
|
||||||
|
#define FORMAT_NOT 0x80000
|
||||||
|
#define FORMAT_NOT_NOT 0x100000
|
||||||
|
|
||||||
/* Limit on recursion. */
|
/* Limit on recursion. */
|
||||||
#define FORMAT_LOOP_LIMIT 100
|
#define FORMAT_LOOP_LIMIT 100
|
||||||
@ -4003,7 +4005,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
cp++;
|
cp++;
|
||||||
|
|
||||||
/* Check single character modifiers with no arguments. */
|
/* Check single character modifiers with no arguments. */
|
||||||
if (strchr("labcdnwETSWPL<>", cp[0]) != NULL &&
|
if (strchr("labcdnwETSWPL!<>", cp[0]) != NULL &&
|
||||||
format_is_end(cp[1])) {
|
format_is_end(cp[1])) {
|
||||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||||
cp++;
|
cp++;
|
||||||
@ -4013,6 +4015,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
/* Then try double character with no arguments. */
|
/* Then try double character with no arguments. */
|
||||||
if ((memcmp("||", cp, 2) == 0 ||
|
if ((memcmp("||", cp, 2) == 0 ||
|
||||||
memcmp("&&", cp, 2) == 0 ||
|
memcmp("&&", cp, 2) == 0 ||
|
||||||
|
memcmp("!!", cp, 2) == 0 ||
|
||||||
memcmp("!=", cp, 2) == 0 ||
|
memcmp("!=", cp, 2) == 0 ||
|
||||||
memcmp("==", cp, 2) == 0 ||
|
memcmp("==", cp, 2) == 0 ||
|
||||||
memcmp("<=", cp, 2) == 0 ||
|
memcmp("<=", cp, 2) == 0 ||
|
||||||
@ -4148,6 +4151,60 @@ format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
|
|||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle unary boolean operators, "!" and "!!". */
|
||||||
|
static char *
|
||||||
|
format_bool_op_1(struct format_expand_state *es, const char *fmt, int not)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
char *expanded;
|
||||||
|
|
||||||
|
expanded = format_expand1(es, fmt);
|
||||||
|
result = format_true(expanded);
|
||||||
|
if (not)
|
||||||
|
result = !result;
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
return (xstrdup(result ? "1" : "0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle n-ary boolean operators, "&&" and "||". */
|
||||||
|
static char *
|
||||||
|
format_bool_op_n(struct format_expand_state *es, const char *fmt, int and)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
const char *cp1, *cp2;
|
||||||
|
char *raw, *expanded;
|
||||||
|
|
||||||
|
result = and ? 1 : 0;
|
||||||
|
cp1 = fmt;
|
||||||
|
|
||||||
|
while (and ? result : !result) {
|
||||||
|
cp2 = format_skip(cp1, ",");
|
||||||
|
|
||||||
|
if (cp2 == NULL)
|
||||||
|
raw = xstrdup(cp1);
|
||||||
|
else
|
||||||
|
raw = xstrndup(cp1, cp2 - cp1);
|
||||||
|
expanded = format_expand1(es, raw);
|
||||||
|
free(raw);
|
||||||
|
format_log(es, "operator %s has operand: %s",
|
||||||
|
and ? "&&" : "||", expanded);
|
||||||
|
|
||||||
|
if (and)
|
||||||
|
result = result && format_true(expanded);
|
||||||
|
else
|
||||||
|
result = result || format_true(expanded);
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
if (cp2 == NULL)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
cp1 = cp2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (xstrdup(result ? "1" : "0"));
|
||||||
|
}
|
||||||
|
|
||||||
/* Does session name exist? */
|
/* Does session name exist? */
|
||||||
static char *
|
static char *
|
||||||
format_session_name(struct format_expand_state *es, const char *fmt)
|
format_session_name(struct format_expand_state *es, const char *fmt)
|
||||||
@ -4524,6 +4581,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
int j, c;
|
int j, c;
|
||||||
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
||||||
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
||||||
|
struct format_modifier *bool_op_n = NULL;
|
||||||
u_int i, count, nsub = 0;
|
u_int i, count, nsub = 0;
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
|
|
||||||
@ -4548,6 +4606,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
case '>':
|
case '>':
|
||||||
cmp = fm;
|
cmp = fm;
|
||||||
break;
|
break;
|
||||||
|
case '!':
|
||||||
|
modifiers |= FORMAT_NOT;
|
||||||
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
search = fm;
|
search = fm;
|
||||||
break;
|
break;
|
||||||
@ -4646,8 +4707,11 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
}
|
}
|
||||||
} else if (fm->size == 2) {
|
} else if (fm->size == 2) {
|
||||||
if (strcmp(fm->modifier, "||") == 0 ||
|
if (strcmp(fm->modifier, "||") == 0 ||
|
||||||
strcmp(fm->modifier, "&&") == 0 ||
|
strcmp(fm->modifier, "&&") == 0)
|
||||||
strcmp(fm->modifier, "==") == 0 ||
|
bool_op_n = fm;
|
||||||
|
else if (strcmp(fm->modifier, "!!") == 0)
|
||||||
|
modifiers |= FORMAT_NOT_NOT;
|
||||||
|
else if (strcmp(fm->modifier, "==") == 0 ||
|
||||||
strcmp(fm->modifier, "!=") == 0 ||
|
strcmp(fm->modifier, "!=") == 0 ||
|
||||||
strcmp(fm->modifier, ">=") == 0 ||
|
strcmp(fm->modifier, ">=") == 0 ||
|
||||||
strcmp(fm->modifier, "<=") == 0)
|
strcmp(fm->modifier, "<=") == 0)
|
||||||
@ -4686,7 +4750,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this a loop, comparison or condition? */
|
/* Is this a loop, operator, comparison or condition? */
|
||||||
if (modifiers & FORMAT_SESSIONS) {
|
if (modifiers & FORMAT_SESSIONS) {
|
||||||
value = format_loop_sessions(es, copy);
|
value = format_loop_sessions(es, copy);
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
@ -4722,6 +4786,16 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
value = format_search(search, wp, new);
|
value = format_search(search, wp, new);
|
||||||
}
|
}
|
||||||
free(new);
|
free(new);
|
||||||
|
} else if (modifiers & FORMAT_NOT) {
|
||||||
|
value = format_bool_op_1(es, copy, 1);
|
||||||
|
} else if (modifiers & FORMAT_NOT_NOT) {
|
||||||
|
value = format_bool_op_1(es, copy, 0);
|
||||||
|
} else if (bool_op_n != NULL) {
|
||||||
|
/* n-ary boolean operator. */
|
||||||
|
if (strcmp(bool_op_n->modifier, "||") == 0)
|
||||||
|
value = format_bool_op_n(es, copy, 0);
|
||||||
|
else if (strcmp(bool_op_n->modifier, "&&") == 0)
|
||||||
|
value = format_bool_op_n(es, copy, 1);
|
||||||
} else if (cmp != NULL) {
|
} else if (cmp != NULL) {
|
||||||
/* Comparison of left and right. */
|
/* Comparison of left and right. */
|
||||||
if (format_choose(es, copy, &left, &right, 1) != 0) {
|
if (format_choose(es, copy, &left, &right, 1) != 0) {
|
||||||
@ -4732,17 +4806,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
format_log(es, "compare %s left is: %s", cmp->modifier, left);
|
format_log(es, "compare %s left is: %s", cmp->modifier, left);
|
||||||
format_log(es, "compare %s right is: %s", cmp->modifier, right);
|
format_log(es, "compare %s right is: %s", cmp->modifier, right);
|
||||||
|
|
||||||
if (strcmp(cmp->modifier, "||") == 0) {
|
if (strcmp(cmp->modifier, "==") == 0) {
|
||||||
if (format_true(left) || format_true(right))
|
|
||||||
value = xstrdup("1");
|
|
||||||
else
|
|
||||||
value = xstrdup("0");
|
|
||||||
} else if (strcmp(cmp->modifier, "&&") == 0) {
|
|
||||||
if (format_true(left) && format_true(right))
|
|
||||||
value = xstrdup("1");
|
|
||||||
else
|
|
||||||
value = xstrdup("0");
|
|
||||||
} else if (strcmp(cmp->modifier, "==") == 0) {
|
|
||||||
if (strcmp(left, right) == 0)
|
if (strcmp(left, right) == 0)
|
||||||
value = xstrdup("1");
|
value = xstrdup("1");
|
||||||
else
|
else
|
||||||
|
10
tmux.1
10
tmux.1
@ -5704,9 +5704,17 @@ otherwise by
|
|||||||
.Ql ||
|
.Ql ||
|
||||||
and
|
and
|
||||||
.Ql &&
|
.Ql &&
|
||||||
evaluate to true if either or both of two comma-separated alternatives are
|
evaluate to true if any or all of the comma-separated alternatives are
|
||||||
true, for example
|
true, for example
|
||||||
.Ql #{||:#{pane_in_mode},#{alternate_on}} .
|
.Ql #{||:#{pane_in_mode},#{alternate_on}} .
|
||||||
|
.Ql \&!
|
||||||
|
evaluates to true if the value is false and vice versa, for example
|
||||||
|
.Ql #{!:#{pane_in_mode}} .
|
||||||
|
.Ql !!
|
||||||
|
converts a value to a canonical boolean form, 1 for true and 0 for false, for
|
||||||
|
example
|
||||||
|
.Ql #{!!:non-empty string}
|
||||||
|
evaluates to 1.
|
||||||
.Pp
|
.Pp
|
||||||
An
|
An
|
||||||
.Ql m
|
.Ql m
|
||||||
|
Reference in New Issue
Block a user