Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: coloring STDERR to terminal

On Wed, 30 Jun 2004, Vincent Lefevre wrote:

> On 2004-06-29 10:14:13 -0700, Bart Schaefer wrote:
> > If you want something fancier, have the coproc print a single byte to 
> > its stdout every time around the read loop

To clarify, by this I mean to its original standard output, not to the 
redirected stdout which is going to /dev/tty (otherwise the parent zsh 
can't see it).  E.g. instead of

 coproc while read line; print '\e[91m'${(q)line}'\e[0m' > /dev/tty

You need

 coproc while read line; do
          print '\e[91m'${(q)line}'\e[0m' > /dev/tty
          print -n $'\0'

> > However, if you produce more lines of output between commands than
> > there are bytes of space in the socket buffer you'll block the
> > coproc and potentially deadlock everything
> I don't understand how this can happen.

The situation is thus: The parent zsh (Z) holds the write-end (W) of the 
standard input of coprocess (C), and the read end (R) of the standard 
output of the coprocess.  Within the coprocess, the first print command 
has its standard output redirected to the terminal (T), but the second is 
still writing on R.

Z passes a copy of W to new job (J) as its stderr, then waits for J.

C is thus reading from W and writing to both T and to R, but Z is not 
reading from R (because Z is waiting), so C can only execute as many loops 
as there are bytes in the buffer for R before C blocks.  If C blocks, it 
stops reading from W, which means that eventually the buffer for W will 
fill up and also block J.  Deadlock.

This happens even faster when Z and J are the same process (a built-in
command or shell function).  The whole thing operates much better if C
is independent of Z, and you live with the race condition that means you
may sometimes get a prompt in the middle of your error output.

Which is, in part, why I said whether it "doesn't work very well" depends 
on your definition of "very well."  It works as well as it can, given the
original premise.

Using "read -t" in C's while loop test doesn't help with this, because the 
gating factor is Z waiting on J.  If you put J in the background (so Z is 
not waiting on it), the gating factor becomes Z waiting on input from the 
terminal at the prompt, but that you can solve with a "zle -F" handler (in 
4.2.1 or later).

> Wouldn't it be fine to have a read option (e.g. -T) that does this, i.e. 
> read what is requested (i.e. until \n or num characters if -k is used) 
> or return as soon as nothing else is available?

See "sysread" (and "syswrite") in the zsh/system module.

Messages sorted by: Reverse Date, Date, Thread, Author