49561: add zformat -F option, similar to -f but ternary expressions check for existence instead of doing math evaluation

This commit is contained in:
Oliver Kiddle 2021-11-12 20:33:52 +01:00
parent 631576de0f
commit dfb7ac94bb
6 changed files with 75 additions and 20 deletions

View File

@ -1,3 +1,11 @@
2021-11-12 Oliver Kiddle <opk@zsh.org>
* 49561: Src/Modules/zutil.c, Doc/Zsh/mod_zutil.yo,
Completion/Base/Core/_description, Completion/Base/Core/_message,
Test/V13zformat.ztst: Add zformat -F option, similar to -f but
ternary expressions check for existence instead of doing math
evaluation. Make use it with the format style.
2021-11-07 Oliver Kiddle <opk@zsh.org>
* 49544: Src/Modules/watch.c: only tie watch/WATCH if both come

View File

@ -78,7 +78,7 @@ shift 2
if [[ -z "$1" && $# -eq 1 ]]; then
format=
elif [[ -n "$format" ]]; then
zformat -f format "$format" "d:$1" "${(@)argv[2,-1]}"
zformat -F format "$format" "d:$1" "${(@)argv[2,-1]}"
fi
if [[ -n "$gname" ]]; then

View File

@ -39,7 +39,7 @@ else
fi
if [[ -n "$format$raw" ]]; then
[[ -z "$raw" ]] && zformat -f format "$format" "d:$1" "${(@)argv[2,-1]}"
[[ -z "$raw" ]] && zformat -F format "$format" "d:$1" "${(@)argv[2,-1]}"
builtin compadd "$gopt[@]" -x "$format"
_comp_mesg=yes
fi

View File

@ -150,8 +150,9 @@ enditem()
)
findex(zformat)
xitem(tt(zformat -f) var(param) var(format) var(spec) ...)
xitem(tt(zformat -F) var(param) var(format) var(spec) ...)
item(tt(zformat -a) var(array) var(sep) var(spec) ...)(
This builtin provides two different forms of formatting. The first form
This builtin provides different forms of formatting. The first form
is selected with the tt(-f) option. In this case the var(format)
string will be modified by replacing sequences starting with a percent
sign in it with strings from the var(spec)s. Each var(spec) should be
@ -195,7 +196,13 @@ outputs "The answer is 'yes'." to tt(REPLY) since the value for the format
specifier tt(c) is 3, agreeing with the digit argument to the ternary
expression.
The second form, using the tt(-a) option, can be used for aligning
With tt(-F) instead of tt(-f), ternary expressions choose between the
`true' or `false' text on the basis of whether the format specifier is
present and non-empty. A test number indicates a minimum width for the
value given in the format specifier. Negative numbers reverse this,
so the test is for whether the value exceeds a maximum width.
The form, using the tt(-a) option, can be used for aligning
strings. Here, the var(spec)s are of the form
`var(left)tt(:)var(right)' where `var(left)' and `var(right)' are
arbitrary strings. These strings are modified by replacing the colons

View File

@ -776,10 +776,12 @@ bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
* ousedp (*outp)[*ousedp] is where to write next
* olenp *olenp is the size allocated for *outp
* endchar Terminator character in addition to `\0' (may be '\0')
* presence -F: Ternary expressions test emptyness instead
* skip If 1, don't output, just parse.
*/
static char *zformat_substring(char* instr, char **specs, char **outp,
int *ousedp, int *olenp, int endchar, int skip)
int *ousedp, int *olenp, int endchar,
int presence, int skip)
{
char *s;
@ -813,20 +815,29 @@ static char *zformat_substring(char* instr, char **specs, char **outp,
if (testit && STOUC(*s)) {
int actval, testval, endcharl;
/*
* One one number is useful for ternary expressions.
* Remember to put the sign back.
*/
/* Only one number is useful for ternary expressions. */
testval = (min >= 0) ? min : (max >= 0) ? max : 0;
if (right)
testval *= -1;
if (specs[STOUC(*s)])
actval = (int)mathevali(specs[STOUC(*s)]);
else
actval = 0;
/* zero means values are equal, i.e. true */
actval -= testval;
if (specs[STOUC(*s)] && *specs[STOUC(*s)]) {
if (presence) {
if (testval)
#ifdef MULTIBYTE_SUPPORT
if (isset(MULTIBYTE))
actval = MB_METASTRWIDTH(specs[STOUC(*s)]);
else
#endif
actval = strlen(specs[STOUC(*s)]);
else
actval = 1;
actval = right ? (testval < actval) : (testval >= actval);
} else {
if (right) /* put the sign back */
testval *= -1;
/* zero means values are equal, i.e. true */
actval = (int)mathevali(specs[STOUC(*s)]) - testval;
}
} else
actval = presence ? !right : testval;
/* careful about premature end of string */
if (!(endcharl = *++s))
@ -837,10 +848,10 @@ static char *zformat_substring(char* instr, char **specs, char **outp,
* vice versa... unless we are already skipping.
*/
if (!(s = zformat_substring(s+1, specs, outp, ousedp,
olenp, endcharl, skip || actval)))
olenp, endcharl, presence, skip || actval)))
return NULL;
if (!(s = zformat_substring(s+1, specs, outp, ousedp,
olenp, ')', skip || !actval)))
olenp, ')', presence, skip || !actval)))
return NULL;
} else if (skip) {
continue;
@ -912,6 +923,7 @@ static int
bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
char opt;
int presence = 0;
if (args[0][0] != '-' || !(opt = args[0][1]) || args[0][2]) {
zwarnnam(nam, "invalid argument: %s", args[0]);
@ -920,6 +932,9 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
args++;
switch (opt) {
case 'F':
presence = 1;
/* fall-through */
case 'f':
{
char **ap, *specs[256] = {0}, *out;
@ -939,7 +954,8 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
}
out = (char *) zhalloc(olen = 128);
zformat_substring(args[1], specs, &out, &oused, &olen, '\0', 0);
zformat_substring(args[1], specs, &out, &oused, &olen, '\0',
presence, 0);
out[oused] = '\0';
setsparam(args[0], ztrdup(out));

View File

@ -58,6 +58,30 @@
0:nested conditionals test
>yes
() {
zformat -f 1 '%(w.zero.fail) %(x.fail.present) %(y.empty.fail) %(z.missing.fail)' w:0 x:1 y:
zformat -F 2 '%(w.zero.fail) %(x.present.fail) %(y.fail.empty) %(z.fail.missing)' w:0 x:1 y:
echo $1
echo $2
}
0:conditionals with empty and missing values
>zero present empty missing
>zero present empty missing
() {
local l
for l in 0 1 2 3; do
zformat -F 1 "%$l(a.a.A)%$l(b.b.B)%$l(c.c.C)%$l(d.d.D)" a: b:1 c:12 d:123
zformat -F 2 "%-$l(a.a.A)%-$l(b.b.B)%-$l(c.c.C)%-$l(d.d.D)" a: b:1 c:12 d:123
print - $1 $2
done
}
0:minimum and maximum widths
>Abcd aBCD
>ABcd abCD
>ABCd abcD
>ABCD abcd
zformat -a argv . foo:lorem ipsum:bar bazbaz '\\esc\:ape'
print -rl -- "$@"
0:basic -a test