diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Completion/Base/Core/_description | 2 | ||||
-rw-r--r-- | Completion/Base/Core/_message | 2 | ||||
-rw-r--r-- | Doc/Zsh/mod_zutil.yo | 11 | ||||
-rw-r--r-- | Src/Modules/zutil.c | 48 | ||||
-rw-r--r-- | Test/V13zformat.ztst | 24 |
6 files changed, 75 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog index 5865cb727..65c0dfa8f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/Completion/Base/Core/_description b/Completion/Base/Core/_description index bdb4007a6..5b54484c7 100644 --- a/Completion/Base/Core/_description +++ b/Completion/Base/Core/_description @@ -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 diff --git a/Completion/Base/Core/_message b/Completion/Base/Core/_message index 4d5645eaf..dbeed4a88 100644 --- a/Completion/Base/Core/_message +++ b/Completion/Base/Core/_message @@ -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 diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index 41d3dfdb0..3cf9e5028 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -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 diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 691ba6c2f..2f17c03f1 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -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)); diff --git a/Test/V13zformat.ztst b/Test/V13zformat.ztst index 982866e13..035a0a495 100644 --- a/Test/V13zformat.ztst +++ b/Test/V13zformat.ztst @@ -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 |