zsh-workers
 help / color / mirror / code / Atom feed
* Re: xterm title/screen title+hardstatus
@ 2000-11-27 12:42 Sven Wischnowsky
  2000-11-27 16:26 ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Sven Wischnowsky @ 2000-11-27 12:42 UTC (permalink / raw)
  To: zsh-workers


Bart Schaefer wrote:

> ...
> 
> When you do this:
> 
> 	spl=${(z)cmd}
> 
> 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.

It is intentional -- directly modelled after (s...).  But it's easy to 
change (removing lines 1800/01 in subst.c), should I?

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


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

* Re: xterm title/screen title+hardstatus
  2000-11-27 12:42 xterm title/screen title+hardstatus Sven Wischnowsky
@ 2000-11-27 16:26 ` Bart Schaefer
  0 siblings, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2000-11-27 16:26 UTC (permalink / raw)
  To: zsh-workers

On Nov 27,  1:42pm, Sven Wischnowsky wrote:
} 
} Bart Schaefer wrote:
} 
} > [...] 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.
} 
} It is intentional -- directly modelled after (s...).

In that case I think it should stay as is.

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


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

* Re: xterm title/screen title+hardstatus
  2000-11-22  8:11 ` Bart Schaefer
@ 2000-11-23  5:35   ` Glenn F. Maynard
  0 siblings, 0 replies; 6+ messages in thread
From: Glenn F. Maynard @ 2000-11-23  5:35 UTC (permalink / raw)
  To: zsh-workers

On Wed, Nov 22, 2000 at 08:11:41AM +0000, Bart Schaefer 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

I'm not terribly concerned with options I don't use.  I'm not looking for
a generic solution; I'm looking for an acceptable one for what features
I use.  (Where is auto_fg, anyway?  It doesn't seem to be mentioned in
the CVS tree.)

> zsh% ( print look, I am a subshell ; sleep 60 ; echo goodbye ) &
> 
> (Your function, and mine below, will put "(" in the title bar for that.)

I never do that outside of sh scripts.

> How meaningful is your hardstatus line when you run several commands in
> a pipeline?  What about redirections?

Meaningful enough to clearly identify it, which is what I'm looking for.

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

Again, I never do either of these things.  (I've never found a reason to
use the former syntax; I only find it slightly confusing.  I've no use for the
latter.)

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

The problems I listed are the only ones that affect me ... and doing this
would make its operation worse (overall), for my use.  (If I run "~/bin/irc
irc.foo.com", I don't want to see the parameters as part of the title, just
"irc".) 

Doing this selectively could be useful, however: if the text in the title
wouldn't be somewhat meaningful.  (Perhaps if there isn't at least one
alphanumeric in it?  Not foolproof, but enough to catch most useless
titles.) 

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

Thanks, I was hoping for that. 

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

Yep; I didn't like cluttering up expansions, but wasn't sure of a better
place.

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

Yuck. 

> } preexec() {
> } 	local cmd spl pnum lhs rhs
> } 	cmd=$@
> 
> This is unneccesary; preexec always gets exactly one argument (the whole
> command line, unparsed).

Yep, but since I was changing the functions around a lot, I shoved it
directly into a local so I didn't have to keep changing the parameters to
the first command.

> } 	spl=${(z)cmd}
> } 	if [[ ${#spl} == ${#cmd} ]] then
> } 		# it was split into an array of chars
> Oh, really?  Try `echo 1 2 3'.

That worked fine.

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

I had to reparse the string from jobtexts in the same way I parsed $@,
so it was the best way.  (If any other modifications are done to the
title, such as selectively setting titles and HS, it'll be needed, too.)
Removing literal newlines in $@ is 

To the first reply:

> It is worse than just quoting. You have to deal with pipelines and complex
> commands. Consider:

> bor@itsrm2% preexec() { print $1 > /tmp/foo }
> bor@itsrm2% while false
> while> do
> while> print x
> while> done

This works fine with both functions.  Something is changing this
to "while false ; do ; print x ; done"; I'm not sure what.

-- 
Glenn Maynard


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

* Re: xterm title/screen title+hardstatus
  2000-11-21 19:58 Glenn F. Maynard
  2000-11-22  6:52 ` Andrej Borsenkow
@ 2000-11-22  8:11 ` Bart Schaefer
  2000-11-23  5:35   ` Glenn F. Maynard
  1 sibling, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2000-11-22  8:11 UTC (permalink / raw)
  To: Glenn F. Maynard, zsh-workers

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 %+)
		else
		    # Replace the command name, ignore extra args.
		    cmd=(builtin jobs -l $cmd[2])
		fi;;
	    %*) 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
        esac

	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
		cmd=(${(z)${(e):-\$jt$num}})
		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:

	spl=${(z)cmd}

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   


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

* RE: xterm title/screen title+hardstatus
  2000-11-21 19:58 Glenn F. Maynard
@ 2000-11-22  6:52 ` Andrej Borsenkow
  2000-11-22  8:11 ` Bart Schaefer
  1 sibling, 0 replies; 6+ messages in thread
From: Andrej Borsenkow @ 2000-11-22  6:52 UTC (permalink / raw)
  To: Glenn F. Maynard, zsh-workers

>
> I've been trying to solve the problems with getting reliable titles and
> hardstatus lines (for screen).
>

Every now and then I thought about it and always failed to find reliable
solution.

> Two major problems: dealing with all input lines, and following processes
> around when job switching.
>
> The first is the more difficult one.  I couldn't get tcsh or bash to do
> this; zsh has come the closest.  In particular, there're issues with
> dealing with commands containing single quotes, double quotes, both nested,
> and escaping.

It is worse than just quoting. You have to deal with pipelines and complex
commands. Consider:

bor@itsrm2% preexec() { print $1 > /tmp/foo }
bor@itsrm2% while false
while> do
while> print x
while> done
bor@itsrm2% cat /tmp/foo
while false
do
print x
done

That was the main reason I never came up with any solution.

[...]

-andrej


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

* xterm title/screen title+hardstatus
@ 2000-11-21 19:58 Glenn F. Maynard
  2000-11-22  6:52 ` Andrej Borsenkow
  2000-11-22  8:11 ` Bart Schaefer
  0 siblings, 2 replies; 6+ messages in thread
From: Glenn F. Maynard @ 2000-11-21 19:58 UTC (permalink / raw)
  To: zsh-workers

I've been trying to solve the problems with getting reliable titles and
hardstatus lines (for screen).

Two major problems: dealing with all input lines, and following processes
around when job switching.

The first is the more difficult one.  I couldn't get tcsh or bash to do
this; zsh has come the closest.  In particular, there're issues with
dealing with commands containing single quotes, double quotes, both nested,
and escaping.  Zsh handles the quoting issue fine (tcsh can't seem to do
it at all; simple things like perl -e 'print "Hello";' become a major
task.)  Dealing with escapes is much more difficult (from preexec):
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".  I don't know if this is intentional: the rest of the
preexec parameters seem completely unparsed (no parameter parsing, no
variable substitution, no whitespace stripping), so my guess is that it
is.  Passing the string through the "escape everything" command is no good,
since it escapes quotes and everything else that hasn't been touched.  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.)

The second is a bit easier, especially since zsh provides $jobtexts[].  It
needs a bit of help from the shell; it'd be silly to reimplement getjob()
in shell code (since it'd need to be updated if new job codes are introduced.)
I wasn't sure where this should be added, however.  Currently, I've added a
variable expansion parameter: if FOO=%vi, then ${(J)FOO} expands to the job
number.  The patch has at least two problems: first, I couldn't find anything
to pass as a command name to the second argument of getjob(), so any errors
in it come from "foo".  Second, errors are bad in this case: if I run an fg
with bad arguments (fg %12345), getjob() says as much, so two errors are
printed (one from preexec calling getjob, and another from fg.)  I'm not sure
how to fix these, or if there's a better way to do this.

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.
Is this intentional or a bug? It's very difficult to use; the hack I used
to get around it should be fairly obvious.

The function currently only works in screen; it doesn't handle the case of
being run under xterm (which uses a different escape and only handles
a single title setting; screen has two, a 20ish-character title and an
arbitrary length hard status line.)  If someone wants to use the script
as is in screen, use 

hardstatus string "%t%?: %h%?"

in .screenrc to display both.

Patch (with above listed flaws); written for 3.1.9-dev-7, applies against CVS:

diff -ur zsh-3.1.9-dev-7/Src/jobs.c zsh-3.1.9.dev7-job/Src/jobs.c
--- zsh-3.1.9-dev-7/Src/jobs.c	Tue Oct 17 08:57:38 2000
+++ zsh-3.1.9.dev7-job/Src/jobs.c	Wed Nov 15 02:07:26 2000
@@ -1089,7 +1089,7 @@
  * to a job number.                                             */
 
 /**/
-static int
+int
 getjob(char *s, char *prog)
 {
     int jobnum, returnval;
diff -ur zsh-3.1.9-dev-7/Src/subst.c zsh-3.1.9.dev7-job/Src/subst.c
--- zsh-3.1.9-dev-7/Src/subst.c	Mon Jun 19 05:14:34 2000
+++ zsh-3.1.9.dev7-job/Src/subst.c	Wed Nov 15 02:54:25 2000
@@ -767,6 +767,7 @@
     char hkeys = 0;
     char hvals = 0;
     int subexp;
+    int joblookup = 0;
 
     *s++ = '\0';
     if (!ialnum(c = *s) && c != '#' && c != Pound && c != '-' &&
@@ -912,6 +913,10 @@
 			goto flagerr;
 		    break;
 
+		case 'J':
+		    joblookup++;
+		    break;
+
 		case 'l':
 		    tt = 1;
 		/* fall through */
@@ -1687,6 +1692,26 @@
 	opts[PROMPTSUBST] = ops;
 	opts[PROMPTBANG] = opb;
 	opts[PROMPTPERCENT] = opp;
+    }
+    if (joblookup) {
+	if (isarr) {
+	    char **ap;
+
+	    if (!copied)
+		aval = arrdup(aval), copied = 1;
+	    ap = aval;
+
+	    for (; *ap; ap++) {
+		int i = getjob(*ap, "foo");
+		*ap = hcalloc(16);
+		sprintf(*ap, "%i", i);
+            }
+	} else {
+	    int i = getjob(val, "foo");
+	    val = hcalloc(16);
+	    sprintf(val, "%i", i);
+	    copied = 1;
+	}
     }
     if (quotemod) {
 	if (--quotetype > 3)

(That allocation could probably be handled better, too, but it wouldn't matter
unless some masochistic person uses a system with 64-bit randomized PIDs.)

Zsh functions:

preexec() {
	local cmd spl pnum lhs rhs
	cmd=$@
	
	while [[ $cmd == *\  ]] do cmd=${cmd% } ; done
	while [[ $cmd == \ * ]] do cmd=${cmd# } ; done
# bug? ${(z)xxx} should split a string into an array of words; but if there
# is only 1 word, we get an array of chars. work around this.

	spl=${(z)cmd}
	if [[ ${#spl} == ${#cmd} ]] then
		# it was split into an array of chars
		lhs=${cmd}
		rhs=
	else
		lhs=${spl[1]}
		shift spl
		rhs=${spl[*]}
	fi

	# 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]}
		return
	fi

	# lhs %*?
	if [[ $lhs == %* ]] then
		pnum=${(J)lhs}
		preexec ${jobtexts[$pnum]}
		return
	fi

	echo -n '\033k'$lhs'\033'\\
	echo -n '\033_'$rhs'\033'\\
}

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

-- 
Glenn Maynard


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

end of thread, other threads:[~2000-11-27 16:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-11-27 12:42 xterm title/screen title+hardstatus Sven Wischnowsky
2000-11-27 16:26 ` Bart Schaefer
  -- strict thread matches above, loose matches on Subject: below --
2000-11-21 19:58 Glenn F. Maynard
2000-11-22  6:52 ` Andrej Borsenkow
2000-11-22  8:11 ` Bart Schaefer
2000-11-23  5:35   ` Glenn F. Maynard

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