zsh-workers
 help / color / mirror / code / Atom feed
* The curious incident of the feep in the night-time
@ 2021-04-27 21:35 Bart Schaefer
  2021-04-28  7:26 ` Stephane Chazelas
  2021-04-29  1:04 ` Bart Schaefer
  0 siblings, 2 replies; 6+ messages in thread
From: Bart Schaefer @ 2021-04-27 21:35 UTC (permalink / raw)
  To: Zsh hackers list

Starting from a fresh zsh -f:

% yy() { zle .send-break }
% zle -N yy
% 12345
(type ESC x yy RET, note that prompt silently returns)
%

On every subsequent invocation of yy, you'll get a beep ... until a
command at the prompt exits zero, and then just one following
invocation of yy will be silent again.

The problem is that lastval is never updated when execzlefunc()
returns nonzero from the nested call (first call is to yy, nested call
is to .send-break), so eventually execpline() returns the old lastval
to the outer execzlefunc(), which behaves as if yy succeeded and
therefore skips handlefeep().

The inner execzlefunc() is called from bin_zle_call() and the outer
one from zlecore().  I think it's correct that the inner one does not
handlefeep() [if it did, you'd feep twice] but something needs to set
lastval.

Further complicating this is that execcmd_exec() skips setting lastval
when ERRFLAG_INT is set, which is one of the bits used by sendbreak().
That's why the old value is still present when the outer execzlefunc()
returns.

4139                /*
4140                 * In case of interruption assume builtin status
4141                 * is less useful than what interrupt set.
4142                 */
4143                if (!(errflag & ERRFLAG_INT))
4144                lastval = ret;

(indentation munged by copy-pasting tabs).  The reference to "what
interrupt set" seems to imply that it is sendbreak() that should be
assigning lastval, because it is simulating a SIGINT and the handler
for SIGINT assigns lastval directly.

What eventually does set lastval = 1 is the parser noticing that the
lexer failed on the interrupt.  Once that happens, further widget
calls don't reset it, so the feeps occur.

The other question is, to what should lastval be set?  Is there
reliance on it being 1 here?  (The parser only changes it [to 1] when
it is already 0.)

(For those confused about the Subject, see
https://en.wikipedia.org/wiki/The_Adventure_of_Silver_Blaze)


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

* Re: The curious incident of the feep in the night-time
  2021-04-27 21:35 The curious incident of the feep in the night-time Bart Schaefer
@ 2021-04-28  7:26 ` Stephane Chazelas
  2021-04-28 18:15   ` Bart Schaefer
  2021-04-29  1:04 ` Bart Schaefer
  1 sibling, 1 reply; 6+ messages in thread
From: Stephane Chazelas @ 2021-04-28  7:26 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2021-04-27 14:35:14 -0700, Bart Schaefer:
[...]
> % yy() { zle .send-break }
> % zle -N yy
> % 12345
> (type ESC x yy RET, note that prompt silently returns)
> %
[...]

That reminds me of
https://www.zsh.org/mla/workers/2020/msg00229.html
(X-seq: zsh-workers 45404)

-- 
Stephane


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

* Re: The curious incident of the feep in the night-time
  2021-04-28  7:26 ` Stephane Chazelas
@ 2021-04-28 18:15   ` Bart Schaefer
  0 siblings, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2021-04-28 18:15 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

On Wed, Apr 28, 2021 at 12:26 AM Stephane Chazelas
<stephane@chazelas.org> wrote:
>
> That reminds me of
> https://www.zsh.org/mla/workers/2020/msg00229.html
> (X-seq: zsh-workers 45404)

Following that back to
https://www.zsh.org/mla/workers/2015/msg00843.html
(workers/34919)
> ... using a different [errflag] bit ... we could abort back to
> the top of ZLE rather than out of ZLE and back in again

That idea is actually impossible because of the aforementioned
handshake with the parser.  Unwinding the recursive-descent parse
requires leaving and re-entering ZLE.

> which would
> mean you finally had the ability to embed push-line in other widgets

(This means "push-input", push-line actually already can be embedded
because it doesn't reset the prebuffer.)

I think the best we can do without completely restructuring the
interactive shell input** is to avoid treating push-input /
push-line-or-edit as an error condition, which might make it possible
to fix the "vared kills the shell" problem from workers/45404.

** Roughly, we'd have to invert the entry chain so that ZLE drives the
parser instead of the other way around, and change accept-line so that
it doesn't leave ZLE at all until the parser says it has a complete
expression, with attendant changes to managing PREBUFFER and BUFFER
and the printing (or not) of PS2, etc.  That in turn means that
interactive input is handled a lot differently from script input,
whereas right now those differences are all restricted to the I/O
layer.


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

* Re: The curious incident of the feep in the night-time
  2021-04-27 21:35 The curious incident of the feep in the night-time Bart Schaefer
  2021-04-28  7:26 ` Stephane Chazelas
@ 2021-04-29  1:04 ` Bart Schaefer
  2021-04-29 18:27   ` Bart Schaefer
  1 sibling, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2021-04-29  1:04 UTC (permalink / raw)
  To: Zsh hackers list

On Tue, Apr 27, 2021 at 2:35 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> [...]  The reference to "what
> interrupt set" seems to imply that it is sendbreak() that should be
> assigning lastval, because it is simulating a SIGINT and the handler
> for SIGINT assigns lastval directly.
>
> The other question is, to what should lastval be set?

With a quick grep for integer assignments to lastval, the shell
appears to use only 1, 127, or 128+SIGxx.  Unless someone knows of a
different circumstance, it appears sendbreak() should probably just
continue to use lastval = 1.


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

* Re: The curious incident of the feep in the night-time
  2021-04-29  1:04 ` Bart Schaefer
@ 2021-04-29 18:27   ` Bart Schaefer
  2021-05-02 22:20     ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2021-04-29 18:27 UTC (permalink / raw)
  To: Zsh hackers list

The plot thickens.

An actual interrupt signal causes getbyte() to behave as if no
keystroke were entered, at which point it discovers that errno ==
EINTR and the top level is restored without passing through the code
that calls handlefeep().  Conversely, sendbreak() eventually returns
whatever keystroke(s) initiated the widget, so the simulated interrupt
is treated as a failed widget and (when lastval is nonzero) causes the
feep.  This is probably why we didn't notice the missing feep before,
because ^G and ^C accidentally behaved the same most of the time.

Still pondering what to do about this.


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

* Re: The curious incident of the feep in the night-time
  2021-04-29 18:27   ` Bart Schaefer
@ 2021-05-02 22:20     ` Bart Schaefer
  0 siblings, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2021-05-02 22:20 UTC (permalink / raw)
  To: Zsh hackers list

On Thu, Apr 29, 2021 at 11:27 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> An actual interrupt signal causes getbyte() to behave as if no
> keystroke were entered [...], sendbreak() eventually returns
> whatever keystroke(s) initiated the widget

More accurately, on sendbreak() the keystrokes have already been
returned, and used to select the widget.

This brings us to the final (I hope) complication, which is that when
a built-in widget is run by execzlefunc() any result stored in lastval
is retained, whereas invoking a user-defined widget passes noreturnval
= 1 to doshfunc() which causes lastval to be overwritten by the saved
value from before the function was invoked.  This spoils a scheme I
briefly considered wherein running
  zle send-break 75
(for example) would cause $? to be set to 75.  I suppose it's best to
drop that idea and leave noreturnval as it is, because as it happens
there are no builtin widgets that change lastval.

A question for anyone still following this:  Is it acceptable/desirable that
  { zle send-break } always {
    TRY_BLOCK_ERROR=0
    TRY_BLOCK_INTERRUPT=0
  }
causes the send-break to be disregarded?  Or should send-break in fact
have its own not-clearable state?


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

end of thread, other threads:[~2021-05-02 22:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-27 21:35 The curious incident of the feep in the night-time Bart Schaefer
2021-04-28  7:26 ` Stephane Chazelas
2021-04-28 18:15   ` Bart Schaefer
2021-04-29  1:04 ` Bart Schaefer
2021-04-29 18:27   ` Bart Schaefer
2021-05-02 22:20     ` 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).