zsh-users
 help / color / mirror / code / Atom feed
* Count only visible characters?
@ 2010-04-08 22:38 Seth House
  2010-04-09  9:02 ` Joke de Buhr
  2010-04-09 19:50 ` Peter Stephenson
  0 siblings, 2 replies; 11+ messages in thread
From: Seth House @ 2010-04-08 22:38 UTC (permalink / raw)
  To: zsh-users

Is there any way to count only visible characters?

    testing="%F{green}hello"
    echo ${(%)#testing}

The number I'm interested in is 5 not 14.

After an awful lot of Googling, I'm under the impression this isn't a trivial 
problem. If that is true, I would certainly enjoy a little exposition if someone 
has time.

Thanks.
- Seth


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-08 22:38 Count only visible characters? Seth House
@ 2010-04-09  9:02 ` Joke de Buhr
  2010-04-09  9:13   ` Frank Terbeck
  2010-04-09 19:50 ` Peter Stephenson
  1 sibling, 1 reply; 11+ messages in thread
From: Joke de Buhr @ 2010-04-09  9:02 UTC (permalink / raw)
  To: zsh-users

Since you are using prompt expansion you should always escape the color codes 
with "%{...%}". That's the only way zsh can calculate the length of the prompt 
line correctly. Otherwise the cursor will not be positioned at the end of the 
visual end.

testing="%{%F{green}%}hello"


If you need to do manual counting you can use this 

${(S%%)#testing//\%\{*\%\}}

The command replaces every escape %{...%} sequence prior to calculating the 
length.


$ testing="%{%F{green}%}hello"
$ echo ${(S%%)#testing//\%\{*\%\}}
5


On Friday, 9. April 2010 00:38:05 Seth House wrote:
> Is there any way to count only visible characters?
> 
>     testing="%F{green}hello"
>     echo ${(%)#testing}
> 
> The number I'm interested in is 5 not 14.
> 
> After an awful lot of Googling, I'm under the impression this isn't a
>  trivial problem. If that is true, I would certainly enjoy a little
>  exposition if someone has time.
> 
> Thanks.
> - Seth
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-09  9:02 ` Joke de Buhr
@ 2010-04-09  9:13   ` Frank Terbeck
  2010-04-09  9:49     ` Joke de Buhr
  2010-04-09 10:44     ` Sebastian Stark
  0 siblings, 2 replies; 11+ messages in thread
From: Frank Terbeck @ 2010-04-09  9:13 UTC (permalink / raw)
  To: zsh-users

Joke de Buhr wrote:
> Since you are using prompt expansion you should always escape the color codes 
> with "%{...%}". That's the only way zsh can calculate the length of the prompt 
> line correctly. Otherwise the cursor will not be positioned at the end of the 
> visual end.
>
> testing="%{%F{green}%}hello"

No, with %F{...}...%f he does *not* need to wrap things in %{...%}.

Regards, Frank


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-09  9:13   ` Frank Terbeck
@ 2010-04-09  9:49     ` Joke de Buhr
  2010-04-09 19:22       ` Seth House
  2010-04-09 10:44     ` Sebastian Stark
  1 sibling, 1 reply; 11+ messages in thread
From: Joke de Buhr @ 2010-04-09  9:49 UTC (permalink / raw)
  To: zsh-users

Sorry. I used the color array ${fg_*[green]} for my prompt. They need to be 
escaped. 


If you want to do character counting as suggested earlier you need to escape 
the %F{...} sequences or it won't work unless you change the replacing pattern 
to recognize %F, %f, %K, %k sequences.

On Friday, 9. April 2010 11:13:44 Frank Terbeck wrote:
> Joke de Buhr wrote:
> > Since you are using prompt expansion you should always escape the color
> > codes with "%{...%}". That's the only way zsh can calculate the length of
> > the prompt line correctly. Otherwise the cursor will not be positioned at
> > the end of the visual end.
> >
> > testing="%{%F{green}%}hello"
> 
> No, with %F{...}...%f he does *not* need to wrap things in %{...%}.
> 
> Regards, Frank
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-09  9:13   ` Frank Terbeck
  2010-04-09  9:49     ` Joke de Buhr
@ 2010-04-09 10:44     ` Sebastian Stark
  2010-04-09 10:56       ` Sebastian Stark
  1 sibling, 1 reply; 11+ messages in thread
From: Sebastian Stark @ 2010-04-09 10:44 UTC (permalink / raw)
  To: zsh-users


Hi,

I was playing around with colors because of this post and noticed something strange along the way:

% echo $ZSH_VERSION
4.3.10
% print "${(%)a::=3D%F{green}hello}"
hello}
% print "${(%)a::=3D%F{green}hello"
hello

Why does the first print statement print the closing brace? How can the second print statement not produce an error?


Sebastian


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-09 10:44     ` Sebastian Stark
@ 2010-04-09 10:56       ` Sebastian Stark
  2010-04-09 12:08         ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Sebastian Stark @ 2010-04-09 10:56 UTC (permalink / raw)
  To: zsh-users


Am 09.04.2010 um 12:44 schrieb Sebastian Stark:

> 
> Hi,
> 
> I was playing around with colors because of this post and noticed something strange along the way:
> 
> % echo $ZSH_VERSION
> 4.3.10
> % print "${(%)a::=3D%F{green}hello}"
> hello}
> % print "${(%)a::=3D%F{green}hello"
> hello

Sorry, I made a pasto. The two commands should be:

  print "${(%)a::=%F{green}hello}"

and

   print "${(%)a::=%F{green}hello"

respectively.


Sebastian

> 
> Why does the first print statement print the closing brace? How can the second print statement not produce an error?
> 
> 
> Sebastian
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-09 10:56       ` Sebastian Stark
@ 2010-04-09 12:08         ` Peter Stephenson
  2010-04-09 12:27           ` Sebastian Stark
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2010-04-09 12:08 UTC (permalink / raw)
  To: zsh-users

On Fri, 9 Apr 2010 12:56:02 +0200
Sebastian Stark <seb-zsh@biskalar.de> wrote:
> print "${(%)a::=%F{green}hello}"
> hello}
> % print "${(%)a::=%F{green}hello"
> hello
>
> Why does the first print statement print the closing brace? How can the
> second print statement not produce an error?

${...} doesn't attempt to balance braces internally, so the first } brings
it to an end.  The final quoted "}" is then just an ordinary character.

You're being a bit too clever for your own good here by trying to too much
at once.  If you separate out the assignment from the use it'll work.
If you absolutely have to do it this way, however, quoting the text you
want to be treated as a string by the parameter expansion works.

print "${(%)a::="%F{green}hello"}"

The outer double quotes are now overloaded too many times to be able to
tell this is what you mean: see a recent post by Bart for a reference to a
discussion on the standards mailing list about trouble with double quotes.
I'm not sure you actually want the outer double quotes at all, but I'm not
sure what you're trying to do (and it probably doesn't matter for this
particular issue).

-- 
Peter Stephenson <pws@csr.com>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-09 12:08         ` Peter Stephenson
@ 2010-04-09 12:27           ` Sebastian Stark
  0 siblings, 0 replies; 11+ messages in thread
From: Sebastian Stark @ 2010-04-09 12:27 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-users


Am 09.04.2010 um 14:08 schrieb Peter Stephenson:

> On Fri, 9 Apr 2010 12:56:02 +0200
> Sebastian Stark <seb-zsh@biskalar.de> wrote:
>> print "${(%)a::=%F{green}hello}"
>> hello}
>> % print "${(%)a::=%F{green}hello"
>> hello
>> 
>> Why does the first print statement print the closing brace? How can the
>> second print statement not produce an error?
> 
> ${...} doesn't attempt to balance braces internally, so the first } brings
> it to an end.  The final quoted "}" is then just an ordinary character.

ok, good to know.

> You're being a bit too clever for your own good here by trying to too much
> at once.  If you separate out the assignment from the use it'll work.
> If you absolutely have to do it this way, however, quoting the text you
> want to be treated as a string by the parameter expansion works.
> 
> print "${(%)a::="%F{green}hello"}"
> 
> The outer double quotes are now overloaded too many times to be able to
> tell this is what you mean: see a recent post by Bart for a reference to a
> discussion on the standards mailing list about trouble with double quotes.

The expression works as I expect when I leave out all the double quotes. I didn't think those were the problem.

> I'm not sure you actually want the outer double quotes at all, but I'm not
> sure what you're trying to do (and it probably doesn't matter for this
> particular issue).

Sometimes I want to use expansions that are only available as prompt expansions. It's a bit cumbersome having to assign them to a variable first and then evaluate it with the %-modifier. One example would be a condition that checks wether a background job is running:

  if ((${(%):-%j}))
  then
    print "no reexec because background job is running"
    return $E_JOB
  fi

In this example the above is not an issue. But it could appear in other contexts, when using "inline prompt expansion" in print statements. I admit this is a bit esoteric, but still worth mentioning.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-09  9:49     ` Joke de Buhr
@ 2010-04-09 19:22       ` Seth House
  0 siblings, 0 replies; 11+ messages in thread
From: Seth House @ 2010-04-09 19:22 UTC (permalink / raw)
  To: zsh-users

Joke de Buhr <joke <at> seiken.de> writes:
> If you want to do character counting as suggested earlier you need to escape 
> the %F{...} sequences

I used to use %{%} before I found the %F short-form and now I've switched back. 
:) Doing a search-and-replace for those delimiters seems so obvious in 
retrospect. Works like a charm, thanks a lot! That made my day (and made my 
prompt code about half as long).


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-08 22:38 Count only visible characters? Seth House
  2010-04-09  9:02 ` Joke de Buhr
@ 2010-04-09 19:50 ` Peter Stephenson
  2010-04-10  4:02   ` Bart Schaefer
  1 sibling, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2010-04-09 19:50 UTC (permalink / raw)
  To: zsh-users

On Thu, 8 Apr 2010 22:38:05 +0000 (UTC)
Seth House <seth@eseth.com> wrote:
> Is there any way to count only visible characters?
> 
>     testing="%F{green}hello"
>     echo ${(%)#testing}
> 
> The number I'm interested in is 5 not 14.
> 
> After an awful lot of Googling, I'm under the impression this isn't a trivial 
> problem.

That's correct, it isn't trivial using shell code.  (It's not *so* hard
to strip the various highlighting codes and %{ ... %} sections if you
want an exercise in shell programming.)  However, the code to do this
is already built into the shell itself, so making this available is a
straightforward change.  Note you need the `#' inside the
parentheses---the normal `#' is too long established for me to be keen
on changing its meaning even in combination with `(%)'.

print ${(%#):-%F{red}hello%f there}
11

I'm guessing there's no call for what this syntax previously meant,
doing prompt expansion on a string and then treating the result as a
numeric expression to give you a character.  I've spent too much of my
life finding new codes for substitution flags.  However, I'm open to
more imaginative suggestions.

Index: Doc/Zsh/expn.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/expn.yo,v
retrieving revision 1.112
diff -p -u -r1.112 expn.yo
--- Doc/Zsh/expn.yo	27 Mar 2010 19:04:35 -0000	1.112
+++ Doc/Zsh/expn.yo	9 Apr 2010 19:38:28 -0000
@@ -729,6 +729,14 @@ entirely distinct from use of the tt(#) 
 
 If the tt(MULTIBYTE) option is set and the number is greater than 127
 (i.e. not an ASCII character) it is treated as a Unicode character.
+
+In combination with the tt(%) flag, described immediately below,
+this has a different meaning: the expanded prompt is replaced by
+the width of the string as it would appear on the screen in the same
+way as it would be calculated by the prompt code.  In other words,
+this takes account of tt(%{), tt(%}) and highlighting sequences in
+the string, but is not otherwise sensitive to embedded control
+sequences.
 )
 item(tt(%))(
 Expand all tt(%) escapes in the resulting words in the same way as in
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.103
diff -p -u -r1.103 subst.c
--- Src/subst.c	9 Apr 2010 15:40:14 -0000	1.103
+++ Src/subst.c	9 Apr 2010 19:38:28 -0000
@@ -2660,7 +2660,7 @@ paramsubst(LinkList l, LinkNode n, char 
     }
     if (errflag)
 	return NULL;
-    if (evalchar) {
+    if (evalchar && !presc) {
 	int one = noerrs, oef = errflag, haserr = 0;
 
 	if (!quoteerr)
@@ -2801,6 +2801,7 @@ paramsubst(LinkList l, LinkNode n, char 
     if (presc) {
 	int ops = opts[PROMPTSUBST], opb = opts[PROMPTBANG];
 	int opp = opts[PROMPTPERCENT];
+	int width;
 
 	if (presc < 2) {
 	    opts[PROMPTPERCENT] = 1;
@@ -2823,17 +2824,33 @@ paramsubst(LinkList l, LinkNode n, char 
 	    for (; *ap; ap++) {
 		char *tmps;
 		untokenize(*ap);
-		tmps = promptexpand(*ap, 0, NULL, NULL, NULL);
-		*ap = dupstring(tmps);
+		tmps = promptexpand(*ap, evalchar, NULL, NULL, NULL);
+		if (evalchar) {
+		    char digbuf[DIGBUFSIZE];
+		    countprompt(tmps, &width, NULL, -1);
+		    sprintf(digbuf, "%d", width);
+		    *ap = dupstring(digbuf);
+		} else {
+		    *ap = dupstring(tmps);
+		}
 		free(tmps);
 	    }
 	} else {
 	    char *tmps;
-	    if (!copied)
-		val = dupstring(val), copied = 1;
+	    if (!copied) {
+		val = dupstring(val);
+		copied = 1;
+	    }
 	    untokenize(val);
-	    tmps = promptexpand(val, 0, NULL, NULL, NULL);
-	    val = dupstring(tmps);
+	    tmps = promptexpand(val, evalchar, NULL, NULL, NULL);
+	    if (evalchar) {
+		char digbuf[DIGBUFSIZE];
+		countprompt(tmps, &width, NULL, -1);
+		sprintf(digbuf, "%d", width);
+		val = dupstring(digbuf);
+	    } else {
+		val = dupstring(tmps);
+	    }
 	    free(tmps);
 	}
 	opts[PROMPTSUBST] = ops;


-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Count only visible characters?
  2010-04-09 19:50 ` Peter Stephenson
@ 2010-04-10  4:02   ` Bart Schaefer
  0 siblings, 0 replies; 11+ messages in thread
From: Bart Schaefer @ 2010-04-10  4:02 UTC (permalink / raw)
  To: zsh-users

On Apr 9,  8:50pm, Peter Stephenson wrote:
} On Thu, 8 Apr 2010 22:38:05 +0000 (UTC)
} Seth House <seth@eseth.com> wrote:
} > Is there any way to count only visible characters?
} > 
} >     testing="%F{green}hello"
} >     echo ${(%)#testing}
} > 
} > The number I'm interested in is 5 not 14.

Incidentally, ${(%)#testing} doesn't do what you think it does.  # is
applied BEFORE (%), making (%) rather useless.

What you meant was ${#${(%)testing}}.

} That's correct, it isn't trivial using shell code.  (It's not *so* hard
} to strip the various highlighting codes and %{ ... %} sections if you
} want an exercise in shell programming.)

There's code to do part of this in Functions/Prompts/prompt_bart_setup,
in the prompt_bart_precmd function.  Search for "zero".  It doesn't
handle %{ %} pairs, though, just the other zero-width strings.

} However, the code to do this is already built into the shell itself,
} so making this available is a straightforward change.  Note you need
} the `#' inside the parentheses---the normal `#' is too long
} established for me to be keen on changing its meaning even in
} combination with `(%)'.

Hmm.  Might I suggest that this is of somewhat limited utility?  A
better approach might be to add an option that produces the string
with the zero-width characters removed, and then simply apply the old
normal '#' operator to that result.  Perhaps tripling the (%) flag
means this, e.g.

  print ${(%%%):-%F{red}hello%f there}
  hello there
  print ${#${(%%%):-%F{red}hello%f there}}
  11

My one qualm about (%%%) is that (%%) does more expansion than (%)
and one might want e.g. to count the result of (%) without doing the
PROMPT_SUBST etc. expansion ...

I realize this isn't as straightforward as what you just patched.

A related suggestion that doesn't actually solve the problem of
terminal escapes:  Doubling the (V) flag could remove all special
characters from the result, rather than making them visible.  (That
should also have the effect of removing any fragmentary multibyte
characters, I think.)


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-04-10  4:02 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-08 22:38 Count only visible characters? Seth House
2010-04-09  9:02 ` Joke de Buhr
2010-04-09  9:13   ` Frank Terbeck
2010-04-09  9:49     ` Joke de Buhr
2010-04-09 19:22       ` Seth House
2010-04-09 10:44     ` Sebastian Stark
2010-04-09 10:56       ` Sebastian Stark
2010-04-09 12:08         ` Peter Stephenson
2010-04-09 12:27           ` Sebastian Stark
2010-04-09 19:50 ` Peter Stephenson
2010-04-10  4:02   ` Bart Schaefer

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).