emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: question about `sit-for' and `C-g'


From: Drew Adams
Subject: RE: question about `sit-for' and `C-g'
Date: Mon, 14 May 2012 13:05:32 -0700

Thanks for a carefully prepared reply, with useful info.

Just a couple of remarks, which you can think of as questions if you like.

> 4. The behavior you observed was this normal behavior; your command
> (that ran `sit-for') was destroyed, and Emacs resumed waiting (in the
> minibuffer) for further input.  `sit-for' was entirely 
> irrelevant -- you would have seen the same, normal behavior had
> your code been in a long computation loop at the time.  `sit-for'
> does not have "special behavior" with regards to C-g.

Yes, well put.  But it was not obvious to me, as I said, since I had nearly
forgotten that the command in question (which cycles to the next completion
candidate) called `sit-for'.

And the "destroying" of that command was not at all obvious, since it had
already done its real job of cycling to the next candidate and was just
temporarily displaying help about it in the mode line, with a `sit-for' wait.

So in terms of the most-observable behavior, no command appeared to be
aborted/quit.  The `C-g' seemed to quit only the `sit-for' because that was the
last thing that the command did.

I'm not at all disagreeing with you here - just pointing out my observations
while I was trying to figure things out.  Though I knew the points you make, it
was not clear to me what was happening, and rather than start from such an
understanding I tried to narrow down who was handling that particular `C-g'
event.

> There actually is special (relative to the rest of Emacs) 
> behavior here: if `quit-flag' is non-nil during `read-char', it
> returns `quit_char'.

Yes, that was a point that I made.  (But I think you mean `read_char', not
`read-char'.)

> If `inhibit-quit' is also non-nil, `quit-flag' is cleared (since the
> quit has been "consumed" as input); otherwise the quit remains
> outstanding and the signal will be raised soon thereafter.  (This is
> arguably a bug: (setq n (read-event)) actually sets n to 7 on C-g
> because the `setq' happens before the quit is signaled.)
>
> However, leaving aside the delayed quit, this is invisible to 
> the Elisp programmer except that "when `inhibit-quit' is set,
> `read-event' can read C-g", which is hardly counterintuitive.
>
> > What a user expects when s?he uses `C-g' in the minibuffer is
> > `abort-recursive-edit', IMO.  S?he does not know or care 
> > whether a `sit-for' might be in progress.
> 
> #0  (The user must care because they must know whether a command is
> running.  If they want to kill the minibuffer, they know that's two
> levels and so two `C-g's.)

See above.  No, when this particular `sit-for' is invoked it is not at all
obvious (to a user, and even to me when I was trying to debug what was
happening) that some command is still executing.  From all appearances, the last
command (to cycle to the next candidate) has finished, including its display of
help info in the mode line.  The last thing it does is call `sit-for', and that
`sit-for' wait is pretty invisible to a user.

> If you're writing a command that pretends to not exist so that keys that
> arrive during its execution are treated as they would be were it not
> executing,

See above.  That is not really the case here.  The cycle-to-next command just
makes the next candidate current, then displays some text about it in the mode
line, and then calls `sit-for' before restoring the mode line.

Keys arriving during a `sit-for' generally cancel the `sit-for' wait.  They are
typically processed normally.  That's all.  That's also the user expectation for
the `C-g' here (even if s?he  knew that it happened during a `sit-for'): just
apply the keybinding for `C-g'.

And that's the behavior obtained by binding `inhibit-quit' to t, because
`read-event' returns the `C-g' character in any case ("because the `setq'
happens before the quit is signaled").

> yes you will have to do strange things like bind
> `inhibit-quit', set `unread-command-events', etc.  This should not be
> surprising, as you are writing a command that needs to operate outside
> the standard rules.

Bof.  (But I know what you mean, and it's not incorrect.)

> > Maybe it's as simple as asking whether `C-g' during `sit-for'
> > should quit only the `sit-for' (?), i.e., whether that is 
> ever useful.
> 
> Then a loop (while ... (do-something-inexpensive) (sit-for 1))
> would be difficult to interrupt because nearly every C-g would hit a
> `sit-for'.

I don't think so.  If `sit-for' binds `inhibit-quit' (as in my case), what
happens is that a `C-g' char is returned and then handled normally, e.g., by its
keybinding.

That's exactly what happens in my (corrected) code, except that it is `when'
rather than `while', and the `sit-for' period is (by default) longer.  Because
it is longer, the same thing is true in the end: a `C-g' typically falls within
`sit-for'.

The binding of `inhibit-quit' to non-nil inside (my version of) `sit-for' just
makes the `C-g' char pass through (so that it is handled by its keybinding, in
this case).

However, your point is valid if the code does something after the `sit-for'.  In
that case, without binding `inhibit-quit' that post-sit-for code would be
skipped, whereas with its binding it would be run.

In my case and in your example, there is nothing after the `sit-for', so there
is no difference except the handling of `C-g'.  (Well, you could argue that
`do-something-inexpensive' occurs also after the `sit-for'...)

Anyway yes, with such a modification to your example it provides a good reason
why `sit-for' should not, itself, bind `inhibit-quit'.

> Glad to be of assistance!

Thanks again.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]