1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-03 10:21:46 +02:00

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> 2021-11-07 Oliver Kiddle <opk@zsh.org>
* 49544: Src/Modules/watch.c: only tie watch/WATCH if both come * 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 if [[ -z "$1" && $# -eq 1 ]]; then
format= format=
elif [[ -n "$format" ]]; then elif [[ -n "$format" ]]; then
zformat -f format "$format" "d:$1" "${(@)argv[2,-1]}" zformat -F format "$format" "d:$1" "${(@)argv[2,-1]}"
fi fi
if [[ -n "$gname" ]]; then if [[ -n "$gname" ]]; then

View file

@ -39,7 +39,7 @@ else
fi fi
if [[ -n "$format$raw" ]]; then 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" builtin compadd "$gopt[@]" -x "$format"
_comp_mesg=yes _comp_mesg=yes
fi fi

View file

@ -150,8 +150,9 @@ enditem()
) )
findex(zformat) findex(zformat)
xitem(tt(zformat -f) var(param) var(format) var(spec) ...) 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) ...)( 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) is selected with the tt(-f) option. In this case the var(format)
string will be modified by replacing sequences starting with a percent 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 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 specifier tt(c) is 3, agreeing with the digit argument to the ternary
expression. 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 strings. Here, the var(spec)s are of the form
`var(left)tt(:)var(right)' where `var(left)' and `var(right)' are `var(left)tt(:)var(right)' where `var(left)' and `var(right)' are
arbitrary strings. These strings are modified by replacing the colons 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 * ousedp (*outp)[*ousedp] is where to write next
* olenp *olenp is the size allocated for *outp * olenp *olenp is the size allocated for *outp
* endchar Terminator character in addition to `\0' (may be '\0') * 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. * skip If 1, don't output, just parse.
*/ */
static char *zformat_substring(char* instr, char **specs, char **outp, 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; char *s;
@ -813,20 +815,29 @@ static char *zformat_substring(char* instr, char **specs, char **outp,
if (testit && STOUC(*s)) { if (testit && STOUC(*s)) {
int actval, testval, endcharl; int actval, testval, endcharl;
/* /* Only one number is useful for ternary expressions. */
* One one number is useful for ternary expressions.
* Remember to put the sign back.
*/
testval = (min >= 0) ? min : (max >= 0) ? max : 0; testval = (min >= 0) ? min : (max >= 0) ? max : 0;
if (right)
testval *= -1;
if (specs[STOUC(*s)]) if (specs[STOUC(*s)] && *specs[STOUC(*s)]) {
actval = (int)mathevali(specs[STOUC(*s)]); if (presence) {
else if (testval)
actval = 0; #ifdef MULTIBYTE_SUPPORT
/* zero means values are equal, i.e. true */ if (isset(MULTIBYTE))
actval -= testval; 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 */ /* careful about premature end of string */
if (!(endcharl = *++s)) if (!(endcharl = *++s))
@ -837,10 +848,10 @@ static char *zformat_substring(char* instr, char **specs, char **outp,
* vice versa... unless we are already skipping. * vice versa... unless we are already skipping.
*/ */
if (!(s = zformat_substring(s+1, specs, outp, ousedp, if (!(s = zformat_substring(s+1, specs, outp, ousedp,
olenp, endcharl, skip || actval))) olenp, endcharl, presence, skip || actval)))
return NULL; return NULL;
if (!(s = zformat_substring(s+1, specs, outp, ousedp, if (!(s = zformat_substring(s+1, specs, outp, ousedp,
olenp, ')', skip || !actval))) olenp, ')', presence, skip || !actval)))
return NULL; return NULL;
} else if (skip) { } else if (skip) {
continue; continue;
@ -912,6 +923,7 @@ static int
bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{ {
char opt; char opt;
int presence = 0;
if (args[0][0] != '-' || !(opt = args[0][1]) || args[0][2]) { if (args[0][0] != '-' || !(opt = args[0][1]) || args[0][2]) {
zwarnnam(nam, "invalid argument: %s", args[0]); zwarnnam(nam, "invalid argument: %s", args[0]);
@ -920,6 +932,9 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
args++; args++;
switch (opt) { switch (opt) {
case 'F':
presence = 1;
/* fall-through */
case 'f': case 'f':
{ {
char **ap, *specs[256] = {0}, *out; 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); 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'; out[oused] = '\0';
setsparam(args[0], ztrdup(out)); setsparam(args[0], ztrdup(out));

View file

@ -58,6 +58,30 @@
0:nested conditionals test 0:nested conditionals test
>yes >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' zformat -a argv . foo:lorem ipsum:bar bazbaz '\\esc\:ape'
print -rl -- "$@" print -rl -- "$@"
0:basic -a test 0:basic -a test