summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Kiddle <opk@zsh.org>2021-11-12 20:33:52 +0100
committerOliver Kiddle <opk@zsh.org>2021-11-12 20:33:52 +0100
commitdfb7ac94bb4c28472d759a61ea3c2dab30cf9cd3 (patch)
tree1894d81725e4825c1b1948c0ccf1236b439e3710
parent631576de0f7b4e52487175e3e017e5136424b626 (diff)
downloadzsh-dfb7ac94bb4c28472d759a61ea3c2dab30cf9cd3.tar.gz
zsh-dfb7ac94bb4c28472d759a61ea3c2dab30cf9cd3.zip
49561: add zformat -F option, similar to -f but ternary expressions check for existence instead of doing math evaluation
-rw-r--r--ChangeLog8
-rw-r--r--Completion/Base/Core/_description2
-rw-r--r--Completion/Base/Core/_message2
-rw-r--r--Doc/Zsh/mod_zutil.yo11
-rw-r--r--Src/Modules/zutil.c48
-rw-r--r--Test/V13zformat.ztst24
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