zsh-workers
 help / color / mirror / code / Atom feed
From: Oliver Kiddle <opk@zsh.org>
To: Jun T <takimoto-j@kba.biglobe.ne.jp>
Cc: zsh-workers@zsh.org
Subject: PATCH: zformat (was list units in brackets at the end of completion group descriptions)
Date: Thu, 11 Nov 2021 00:08:04 +0100	[thread overview]
Message-ID: <75714-1636585684.348103@RLBx.KaGK.RKdB> (raw)
In-Reply-To: <2C471545-3339-4B78-BADD-B98336D3833D@kba.biglobe.ne.jp>

On 8 Nov, Jun T wrote:
> I think %1(M is enough for the current purpose.
> (or set %M to 0 if unit is given, and nonzero otherwise; i.e., never leave
> it undefined).

We can't retrospectively set M to nonzero for users of older versions of
zsh. I'd like to be able to configure a format that'll work with new or
old versions.

> But, in zshcompsys(1), neither the section for the 'format' style nor the
> section for '_description' says that the ternary expression of zformat can
> be used (or is it mentioned somewhere?). So if adding a new option to
> zformat would have wider use, then I think adding the option and using it in
> _description would not break the compatibility.

As you say, it doesn't appear to be documented anywhere and I can't see
any cases where we pass values that are intended for use with it. Given
that math evaluation will treat words as variable names, it won't even
be useful with the specs that we do pass. Being able to check for the
presence of specs is more useful so how about the following patch?

This adds -F as an alternative to -f. That was largely chosen out of
lazyness because a second option to be combined with -f requires proper
option parsing rather than the existing string compare on the first
argument. But we can do that if someone is bothered enough to argue in
favour.

With this form, where d:word is passed, a %(d ternary will follow the
true path. Numeric arguments allow for a string width test. I'm not sure
how useful that is but it is consistent with the basic presence checking
(absence being a width of zero) and could have uses like for truncating
long suffix lists.

Or if there's objections to this then the %1(M approach does work.

Oliver

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..36038fa6e 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


  reply	other threads:[~2021-11-10 23:08 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-27 11:52 PATCH: list units in brackets at the end of completion group descriptions Oliver Kiddle
2021-08-27 12:10 ` Daniel Shahaf
2021-10-27 20:51   ` Oliver Kiddle
2021-11-02 12:08     ` Jun T
2021-11-07  1:16       ` Oliver Kiddle
2021-11-08 10:56         ` Jun T
2021-11-10 23:08           ` Oliver Kiddle [this message]
2021-11-22 21:24           ` Oliver Kiddle
2021-12-01  3:27             ` Daniel Shahaf
2021-08-27 14:44 ` Mikael Magnusson
2021-08-27 16:14   ` Oliver Kiddle

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=75714-1636585684.348103@RLBx.KaGK.RKdB \
    --to=opk@zsh.org \
    --cc=takimoto-j@kba.biglobe.ne.jp \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).