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

Re: xterm title/screen title+hardstatus

On Nov 21,  2:58pm, Glenn F. Maynard wrote:
} My objective is to display exactly what was typed in the titlebar (parsed
} somewhat: the first word, the command, is placed in the title; the remainder,
} if anything, is placed in the hardstatus line.)

I hate to rain on your parade, but you haven't even begun to address all
the possible problems here.  What do you do about the AUTO_FG option?  What
is "the command" in something like:

zsh% ( print look, I am a subshell ; sleep 60 ; echo goodbye ) &

(Your function, and mine below, will put "(" in the title bar for that.)

How meaningful is your hardstatus line when you run several commands in
a pipeline?  What about redirections?  (Did you know that you can write
`2>/dev/null foo bar' in place of `foo bar 2>/dev/null'?)  What about
`fg %2 %3 %5'?  (Brings multiple jobs to the foreground in succession.)

(OK, maybe I did like raining, just a little.  One solution would be to
forget about putting one word in the title, and instead put a truncated
prefix of the entire command line there.)

Anyway, here's a preexec to do what your patches and precmd did, without
having to hack on the zsh source.

    # Helper function to output the title escapes
    title() {
	print -nR $'\033k'$1$'\033'\\
	print -nR $'\033_'$2$'\033'\\

    preexec() {
    	emulate -L zsh
        local -a cmd; cmd=(${(z)1})		# Re-parse the command line

	# Construct a command that will output the desired job number.
        case $cmd[1] in
	    fg) if (( $#cmd == 1 )); then
		    # No arguments, must find the current job
		    cmd=(builtin jobs -l %+)
		    # Replace the command name, ignore extra args.
		    cmd=(builtin jobs -l $cmd[2])
	    %*) cmd=(builtin jobs -l $cmd[1]);;	# Same as "else" above
	    *)  title $cmd[1]:t "$cmd[2,-1]"	# Not resuming a job,
	    	return;;			# so we're all done

	local -A jt; jt=(${(kv)jobtexts})	# Copy jobtexts for subshell

	# Run the command, read its output, and look up the jobtext.
	# Could parse $rest here, but $jobtexts (via $jt) is easier.
	$cmd >>(read num rest
		title $cmd[1]:t "$cmd[2,-1]") 2>/dev/null

Probably the oddest bit of that is ${(z)${(e):-\$jt$num}} ... $num will be
a string such as "[3]", so \$jt$num is $jt[3], which evaluated with (e) is
the desired job text, which is then parsed with (z).

Some other commentary:

} preexec appears to receive the original, unparsed input command (including
} whitespace)--except that escapes are parsed, so a command like
} echo "Hello\nThere\n"; contains two real newlines, not the character
} sequence "\n".

No, escapes of that sort are not parsed before calling preexec.  It's your
`echo -n' that's turning those "\n" into newlines.  That's why I used
`print -Rn' instead, in the `title' function above.

} Currently, I've added a variable expansion parameter: if FOO=%vi, then
} ${(J)FOO} expands to the job number.

That was a creative approach, but I don't think it's the best way.  An
option to the `jobs' command to have it stick its output in a parameter,
like the `stat' command from the zsh/stat module does, would probably be
much better.

} Other problems I've had: Whitespace stripping was rather tricky; I'm sure
} there's a better way to do it.  The (z) (split) expansion command has very
} strange behavior: it splits on spaces if there's more than one word; if
} there's only one word, it splits it into an array of single characters.

Nope, that's not what's happening.  Subscripts on zsh parameters always
behave that way:  If the parameter is a string, the subscript indexes it
by characters, and if it's an array, it indexes by array elements.

When you do this:


The type of `spl' is a string if ${(z)cmd} is a string, or an array if
${(z)cmd} is an array.  It just happens that when $cmd has only one word,
${(z)cmd} is a string, and otherwise it's an array.  That's probably not
intentional -- most likely (z) should always return a (maybe one-element)
array.  However, you can (and should) force `spl' to always be an array,
by using parens like this:

	spl=( ${(z)cmd} )

} preexec() {
} 	local cmd spl pnum lhs rhs
} 	cmd=$@

This is unneccesary; preexec always gets exactly one argument (the whole
command line, unparsed).

} 	spl=${(z)cmd}
} 	if [[ ${#spl} == ${#cmd} ]] then
} 		# it was split into an array of chars

Oh, really?  Try `echo 1 2 3'.

} 	# strip off any path from lhs
} 	lhs=${lhs:t}
} 	# is this a command which restarts an existing job?
} 	# lhs "fg"
} 	if [[ $lhs == "fg" ]] then
} 		pnum=${(J)rhs}
} 		preexec ${jobtexts[$pnum]}

This recursive call is a lot of work just to get those two `echo's.

} precmd() {
} 	echo -n '\033kzsh\033\\\033_'$PWD'\033'\\
} }

This, of course, is still necessary with my preexec above.

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