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

Re: ZSpeak! Only Zsh can do this!

On Mar 22,  6:52am (that's GMT), I wrote:
} Subject: Re: ZSpeak! Only Zsh can do this!
} On Mar 21,  6:18pm, Mario Lang wrote:
} } Subject: Re: ZSpeak! Only Zsh can do this!
} }
} } Another really nice to have(tm) feature would be stdout buffering.
} } What I mean is that the shell should have an array (much like history)
} } which contains the outputs (stdout and stderr separated)
} } from the last commands.
} However ... it might be possible to construct something based on the
} zpty module, where stdout and stderr would (unless redirected) each go
} to a separate pty, and both ptys would be managed by a front-end that
} slurped up the output from each as it appeared.

This seemed like such an interesting idea that I tried it.

It should be pretty obvious how to modify this to do something else with
the captured output, e.g., write it to a speech synthesizer instead of
stuffing it into an array parameter ...

This may also need to be tweaked in the event that a command does not
begin producing output within one second; "zpty -r -t" is a rather blunt
instrument with which to be doing precision work.


# zplitty -- run a command with stdout and stderr directed to separate ttys,
# from which that output can be captured for later reference.
# Usage:
#    zplitty command args ...
# Output from the command is captured in the arrays $stdout and $stderr,
# one line per array element.  Beware of running commands that produce
# voluminous output; "zplitty yes" will consume all available memory
# unless interrupted. 
# zplitty can be used in a pipeline or with redirected I/O, but depending
# on its location in the pipeline it may be run in a subshell, in which
# case the parent shell is not able to make use of the captured output.
# zplitty requires the zsh/zpty module and uses the function zttyrun to
# set up two ptys, ztdout and ztderr, to which output can be redirected
# by referencing $ztdout and $ztderr.  Be careful not to redirect too
# much output to a pty unless something is reading it with "zpty -r".
# The command zttystop closes these two ptys and discards the captured
# output; zttyrun must be run again before a new zplitty can be started.
# The stdout or stderr arrays can be reset at any time without zttystop
# simply by assigning an empty array as usual.
# Note that some interactive commands (examples are zsh, vim, and less)
# insist that their standard input and output be the same device.  Zsh
# attempts to re-open its standard input for this, while vim and less do
# the same with their standard error.  This causes "zplitty zsh" to stop
# (SIGTTOU) and "zplitty vim" or "zplitty less" to hang (reading from
# $ztderr, whence they'll never get any input).  Some other interactive
# programs may (mis)behave in similar ways; use zplitty with caution.

zmodload -i zsh/zpty || return

zttywait () {
    stty onlret -ocrnl -onlcr	# May need to adjust this for your OS
    read -e

zttyget() {
    setopt localoptions extendedglob noshwordsplit
    zpty $1 zttywait
    zpty -r $1 $1
    : ${(P)1::=${(P)1%%[[:space:]]#}}

zttyrun() {
    setopt localoptions noshwordsplit
    typeset -g ztdout='' ztderr=''
    typeset -g -a stdout stderr
    zttyget ztdout
    zttyget ztderr

zttystop() {
    unset stdout stderr ztdout ztderr
    zpty -w ztdout exit &&
    zpty -rt ztdout &&
    zpty -d ztdout
    zpty -w ztderr exit &&
    zpty -rt ztderr &&
    zpty -d ztderr

zplitty() {
    setopt localoptions noshwordsplit nonotify noksharrays
    local out err
    ${@:?} > $ztdout 2> $ztderr &
    sleep 1	# Let the background command get started
    while zpty -r -t ztdout out || zpty -r -t ztderr err
	(( $+out )) && {
	    print -Rn $out
	(( $+err )) && {
	    print -u2 -Rn $err
	unset out err

[[ -o kshautoload ]] || zplitty "$@"

# end of zplitty

Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   

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