zsh-users
 help / color / mirror / code / Atom feed
* chpwd, precmd hooks have "zsh" in $0
@ 2021-08-09 20:15 Roman Neuhauser
  2021-08-09 21:26 ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Roman Neuhauser @ 2021-08-09 20:15 UTC (permalink / raw)
  To: zsh-users

as the subject says, at least the chpwd and precmd hooks
have the shell's argv[0] in $0.
seen in both zsh-5.8-0-g77d203f
and zsh-5.8-462-g765bc14. put the reproducer below in
argzero.zsh and source it into a fresh shell (zsh -f).
start the shell using its absolute path, that's what you'll
see.

% /usr/local/bin/zsh -f
% . ./argzero.zsh 
ZSH_PATCHLEVEL: zsh-5.8-462-g765bc14
top: nofunctionargzero     off
top: posixargzero          off

precmd output should be below this message.
'cd .' will utilize all three hooks.

precmd: nofunctionargzero     off                                                                        
precmd: posixargzero          off
precmd: /usr/local/bin/zsh <------
% cd .
preexec: nofunctionargzero     off
preexec: posixargzero          off
preexec: preexec <------
chpwd: nofunctionargzero     off
chpwd: posixargzero          off
chpwd: /usr/local/bin/zsh <------
precmd: nofunctionargzero     off                                                                        
precmd: posixargzero          off
precmd: /usr/local/bin/zsh <------

argzero.zsh:

print ZSH_PATCHLEVEL: $ZSH_PATCHLEVEL
set -o > >(sed -n "/argzero/s/^/top: /p")
function chpwd {
  set -o > >(sed -n "/argzero/s/^/chpwd: /p")
  print chpwd: "$0" '<------'
}
function precmd {
  set -o > >(sed -n "/argzero/s/^/precmd: /p")
  print precmd: "$0" '<------'
}
function preexec {
  set -o > >(sed -n "/argzero/s/^/preexec: /p")
  print preexec: "$0" '<------'
}
cat <<EOF

precmd output should be below this message.
'cd .' will utilize all three hooks.

EOF

-- 
roman


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

* Re: chpwd, precmd hooks have "zsh" in $0
  2021-08-09 20:15 chpwd, precmd hooks have "zsh" in $0 Roman Neuhauser
@ 2021-08-09 21:26 ` Bart Schaefer
  2021-08-10 11:33   ` Roman Neuhauser
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2021-08-09 21:26 UTC (permalink / raw)
  To: Roman Neuhauser; +Cc: Zsh Users

On Mon, Aug 9, 2021 at 1:16 PM Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
>
> as the subject says, at least the chpwd and precmd hooks
> have the shell's argv[0] in $0.

This is because (most) hook functions are called with an empty (NULL)
argument list, as opposed to e.g. all commands (external, builtin, or
function) run from a command line, which have a non-empty argument
list starting with the command name itself.

In the particular case of preexec, the argument list is empty any time
history is not active, which is the case when loading a script with
"source" or "." builtins.  If you actually try it from the interactive
command line, you'll see that $0 is "preexec" in the call to every
function in the preexec_functions list.

I'm not sure what the desired behavior is here.  callhookfunc() could
dummy up a LinkNode any time its lnklst argument is empty, and then
all the hooks would behave in the manner preexec behaves when history
is enabled; or doshfunc() could do the same, in which case every
hook-array function would have its own name in $0; or neither of the
above is appropriate and we should document the current behavior.


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

* Re: chpwd, precmd hooks have "zsh" in $0
  2021-08-09 21:26 ` Bart Schaefer
@ 2021-08-10 11:33   ` Roman Neuhauser
  2021-08-10 17:31     ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Roman Neuhauser @ 2021-08-10 11:33 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Users

# schaefer@brasslantern.com / 2021-08-09 14:26:58 -0700:
> On Mon, Aug 9, 2021 at 1:16 PM Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
> >
> > as the subject says, at least the chpwd and precmd hooks
> > have the shell's argv[0] in $0.
> 
> This is because (most) hook functions are called with an empty (NULL)
> argument list, as opposed to e.g. all commands (external, builtin, or
> function) run from a command line, which have a non-empty argument
> list starting with the command name itself.
> 
> In the particular case of preexec, the argument list is empty any time
> history is not active, which is the case when loading a script with
> "source" or "." builtins.  If you actually try it from the interactive
> command line, you'll see that $0 is "preexec" in the call to every
> function in the preexec_functions list.

how did this happen?  was it the shortest patch that wouldn't crash
the shell?  you give no hints of benefits this should have for users,
and i can't think of any either.

come to think of it, if so taxing to implement fully, why is it built
into the shell in the first place?  and is it too late to reverse the
course, gut the half-assed implementation with one written using shell
functions?  so much in zsh is done that way, why is the loop over
foo_functions written in C?

> I'm not sure what the desired behavior is here.  callhookfunc() could
> dummy up a LinkNode any time its lnklst argument is empty, and then
> all the hooks would behave in the manner preexec behaves when history
> is enabled; or doshfunc() could do the same, in which case every
> hook-array function would have its own name in $0; or neither of the
> above is appropriate and we should document the current behavior.
 
what are the downsides of (2) for users of the shell?  both (1) and (3)
result in loss of information and deviation from standard behavior,
and what is lost in behavior is gained in length of the manual.
(2) preserves information, gets rid of a special case, and nullifies
the need for more documentation.  that is, i'm assuming that functions
plugged into any hook behave as actual functions, IOW

    function a b { ... } > ab.log
    precmd_functions=(a)
    preexec_functions=(b)

calls the function with $0 == "a" in precmd, "b" in preexec,
and that their runtime output goes to ab.log.  hooks do neither
and TRAPNAL functions only the first. :(

-- 
roman


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

* Re: chpwd, precmd hooks have "zsh" in $0
  2021-08-10 11:33   ` Roman Neuhauser
@ 2021-08-10 17:31     ` Bart Schaefer
  2021-08-12  4:40       ` Roman Neuhauser
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2021-08-10 17:31 UTC (permalink / raw)
  To: Roman Neuhauser; +Cc: Zsh Users

On Tue, Aug 10, 2021 at 4:33 AM Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
>
> how did this happen?

I return to what I told Marlon the other day:

The answer to "why doesn't feature A take advantage of feature B" is
often "because A was developed long before B".

The code for calling the hook functions has been around since long
before the FUNCTION_ARGZERO option was added, and nobody thought to
update all the entry points.  When the code for the arrays of hooks
was further added, it just passed through what the base function was
already getting.

> come to think of it, if so taxing to implement fully, why is it built
> into the shell in the first place?

It's not "taxing", it's just forgotten.  It was built into the C code
so that people's existing hook functions (precmd, preexec, chpwd,
etc.) wouldn't have to be changed/overwritten to "know about" the new
special arrays, and so that e.g. module writers could plug into those
arrays without fear that a user could change the calling protocol.

> and is it too late to reverse the
> course, gut the half-assed implementation with one written using shell
> functions?

There's no need to be offensive about it, but yes, it's too late.  The
implementation actually has all the interfaces it needs to populate
FUNCTION_ARGZERO properly, it was just never noticed/found necessary
to do so.

> > I'm not sure what the desired behavior is here.  callhookfunc() could
> > dummy up a LinkNode any time its lnklst argument is empty, and then
> > all the hooks would behave in the manner preexec behaves when history
> > is enabled; or doshfunc() could do the same, in which case every
> > hook-array function would have its own name in $0; or neither of the
> > above is appropriate and we should document the current behavior.
>
> what are the downsides of (2) for users of the shell?

Theoretically, a function might prefer to know that it was being
called as a consequence of being found in a given hook list, vs. being
called directly.  That might argue for (1).  However, since the
current situation is (3), the only instance where that could exist in
practice is for the preexec hooks, so we're probably safe choosing
(2).

I will note, to avoid yet again having an "A forgot B" situation, that
Zftp module hooks also behave like (3) and would begin to have their
own name in $0 if we change doshfunc().

>     function a b { ... } > ab.log
>     precmd_functions=(a)
>     preexec_functions=(b)
>
> calls the function with $0 == "a" in precmd, "b" in preexec,
> and that their runtime output goes to ab.log.  hooks do neither
> and TRAPNAL functions only the first. :(

I'm not sure what "the first" is here?

Anyway, having output redirections on function definitions is another
thing that was added quite late in the long history of the shell --
originally, the redirect would have been connected to the "function"
command itself -- so there may be circumstances where you have to
write

  function a b { { ... } > ab.log }

to be sure of getting what you meant there.  PWS may have more to say about it.


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

* Re: chpwd, precmd hooks have "zsh" in $0
  2021-08-10 17:31     ` Bart Schaefer
@ 2021-08-12  4:40       ` Roman Neuhauser
  2021-08-15 21:10         ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Roman Neuhauser @ 2021-08-12  4:40 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Users

# schaefer@brasslantern.com / 2021-08-10 10:31:00 -0700:
> On Tue, Aug 10, 2021 at 4:33 AM Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
> > and is it too late to reverse the course, gut the half-assed implementation
> > with one written using shell functions?
> 
> There's no need to be offensive about it, but yes, it's too late.  The
> implementation actually has all the interfaces it needs to populate
> FUNCTION_ARGZERO properly, it was just never noticed/found necessary
> to do so.

sorry, i didn't think much about the wording, and didn't mean to be offencisve.
if you (someone) can finish it i'll be grateful.
 
> > > I'm not sure what the desired behavior is here.  callhookfunc() could
> > > dummy up a LinkNode any time its lnklst argument is empty, and then
> > > all the hooks would behave in the manner preexec behaves when history
> > > is enabled; or doshfunc() could do the same, in which case every
> > > hook-array function would have its own name in $0; or neither of the
> > > above is appropriate and we should document the current behavior.
> >
> > what are the downsides of (2) for users of the shell?
> 
> Theoretically, a function might prefer to know that it was being
> called as a consequence of being found in a given hook list, vs. being
> called directly.  That might argue for (1).

yes, but there's other ways to let a function know it's being called as
part of a particular hook array.  there's only one reasonable way
of letting a function know the name it was called with.

> >     function a b { ... } > ab.log
> >     precmd_functions=(a)
> >     preexec_functions=(b)
> >
> > calls the function with $0 == "a" in precmd, "b" in preexec,
> > and that their runtime output goes to ab.log.  hooks do neither
> > and TRAPNAL functions only the first. :(
> 
> I'm not sure what "the first" is here?

use the correct name for a function defined with multiple names.
 
> Anyway, having output redirections on function definitions is another
> thing that was added quite late in the long history of the shell --

i know, it was me who asked for it back then.

  Date: Thu, 24 Jul 2014 14:23:31 +0200
  From: Roman Neuhauser <neuhauser@sigpipe.cz>
  To: zsh-users@zsh.org
  Subject: io-redirect in function definitions

> originally, the redirect would have been connected to the "function"
> command itself -- so there may be circumstances where you have to
> write
> 
>   function a b { { ... } > ab.log }
> 
> to be sure of getting what you meant there.  PWS may have more to say about it.

sure, a workaround exists and it's just a pair of braces and
an indentation level away.  my bitching here isn't motivated by
difficulty to achieve the effect with existing means.  i want the
shell to be simpler, conceptually smaller by having one kind of
functions: those that have their name in $0 and which don't forget
redirections defined after their body.

requests for changes "just" for the sake of some principles may be
annoying so i'll add that this conversation exists because i wanted
to use a single function in several hooks and modify its behavior
based on the hook name:

function generic-hook
{
  local hooks=${1}_functions
  work with ${(P)hooks}
}

-- 
roman


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

* Re: chpwd, precmd hooks have "zsh" in $0
  2021-08-12  4:40       ` Roman Neuhauser
@ 2021-08-15 21:10         ` Bart Schaefer
  0 siblings, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2021-08-15 21:10 UTC (permalink / raw)
  To: Roman Neuhauser; +Cc: Zsh Users

On Wed, Aug 11, 2021 at 9:40 PM Roman Neuhauser <neuhauser@sigpipe.cz> wrote:
>
> [...]  i want the
> shell to be simpler, conceptually smaller by having one kind of
> functions: those that have their name in $0 and which don't forget
> redirections defined after their body.

Just a couple of thoughts about the latter.

First, it doesn't work with autoload.  You end up having to do some
equivalent of adding the extra set of braces, inside the source file.

Second, just worth noting:

% func() { print $SECONDS } > /tmp/funcout
% setopt noclobber
% func
% func
zsh: file exists: /tmp/funcout
%

Third, I'm not convinced that the semantics of memoized redirections
in this way is actually simpler or easier for a user to understand.
It's the only case where you can write a redirection in (what appears
to be) a "simple command" (doc term) and NOT have it immediately take
effect.

Fourth, related, why is redirection different from pipelining in this
particular case?  Why not parse the entire pipeline as part of the
function definition?  (Which would have to be done by treating it as
part of the function Eprog, see $0 patch discussion on zsh-workers.)
The "workaround" for this one is to redirect to a command
substitution.

% function f2 { print $SECONDS } | cat -n
% f2
zsh: command not found: f2
% function f2 { print $SECONDS } >>(cat -n)
% f2
     1    186
%

I'll conclude by wondering if there are well-known semantics for
execution of what appears inside the command substitution in that last
example.  DO NOT TRY THIS:

% f3() { print $SECONDS } >>(f3)


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

end of thread, other threads:[~2021-08-15 21:11 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-09 20:15 chpwd, precmd hooks have "zsh" in $0 Roman Neuhauser
2021-08-09 21:26 ` Bart Schaefer
2021-08-10 11:33   ` Roman Neuhauser
2021-08-10 17:31     ` Bart Schaefer
2021-08-12  4:40       ` Roman Neuhauser
2021-08-15 21:10         ` 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).