unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: "Basil L. Contovounesios" <contovob@tcd.ie>
To: Eli Zaretskii <eliz@gnu.org>
Cc: Reuben Thomas <rrt@sc3d.org>,
	30280@debbugs.gnu.org, Juri Linkov <juri@linkov.net>
Subject: bug#30280: async-shell-command-display-buffer doesn't work anymore
Date: Tue, 30 Jan 2018 18:53:09 +0000	[thread overview]
Message-ID: <877erz41re.fsf@tcd.ie> (raw)
In-Reply-To: <83607kinmx.fsf@gnu.org> (Eli Zaretskii's message of "Mon, 29 Jan 2018 19:24:38 +0200")

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: 0001-Fix-deferred-display-of-async-shell-command-buffers.patch --]
[-- Type: text/x-diff, Size: 2474 bytes --]

From e55856682b1ff85e8743da04965e12a82e763689 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Tue, 30 Jan 2018 16:18:14 +0000
Subject: [PATCH] Fix deferred display of async shell-command buffers

* lisp/simple.el (shell-command): Display async shell buffer on
process output for every, not just first, command invocation.  Check
buffer liveness, not name, before displaying. (bug#30213, bug#30280)
---
 lisp/simple.el | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/lisp/simple.el b/lisp/simple.el
index 3ac6b86381..e2deceb4c2 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -3547,14 +3547,20 @@ shell-command
 		  ;; carriage motion (see comint-inhibit-carriage-motion).
 		  (set-process-filter proc 'comint-output-filter)
                   (if async-shell-command-display-buffer
+                      ;; Display buffer immediately.
                       (display-buffer buffer '(nil (allow-no-window . t)))
-                    (add-function :before (process-filter proc)
-                                  (lambda (process _string)
-                                    (let ((buf (process-buffer process)))
-                                      (when (and (zerop (buffer-size buf))
-                                                 (string= (buffer-name buf)
-                                                          bname))
-                                        (display-buffer buf))))))))
+                    ;; Defer displaying buffer until first process output.
+                    ;; Use disposable named advice so that the buffer is
+                    ;; displayed at most once per process lifetime.
+                    (let ((nonce (make-symbol "nonce")))
+                      (add-function :before (process-filter proc)
+                                    (lambda (proc _string)
+                                      (let ((buf (process-buffer proc)))
+                                        (when (buffer-live-p buf)
+                                          (remove-function (process-filter proc)
+                                                           nonce)
+                                          (display-buffer buf))))
+                                    `((name . ,nonce)))))))
 	    ;; Otherwise, command is executed synchronously.
 	    (shell-command-on-region (point) (point) command
 				     output-buffer nil error-buffer)))))))
-- 
2.15.1


[-- Attachment #2: Type: text/plain, Size: 2683 bytes --]


Eli Zaretskii <eliz@gnu.org> writes:

>> From: Juri Linkov <juri@linkov.net>
>> Date: Mon, 29 Jan 2018 00:20:30 +0200
>> 
>> 0. emacs -Q
>> 1. Eval: (setq async-shell-command-buffer 'new-buffer
>>                async-shell-command-display-buffer nil)
>> 2. M-& sleep 3600
>> 3. M-& sleep 3; echo "xyzzy"
>> 
>> At the step 2 “*Async Shell Command*” is not shown because of no output,
>> this is ok.
>> 
>> But at the step 3 “*Async Shell Command*<2>” is not shown after 3 seconds
>> when the output arrives, this is a regression.
>> 
>> It seems it is caused by commit#9f4f130 from bug#28997

Commit 9f4f130 indeed touches the relevant code, but the bug was
introduced along with the async-shell-command-display-buffer feature.

>> PS: Also it doesn't work with less official configuration:
>> 0. emacs -Q
>> 1. Eval: (setq async-shell-command-display-buffer nil)
>>          (add-hook 'shell-mode-hook 'rename-uniquely)
>> 2. M-& sleep 3600
>> 3. M-& sleep 3; echo "xyzzy"
>
> Thanks for reporting this.  Basil, can you take a look, please?

I am taking the liberty of CCing Reuben because I believe this report
can be merged with bug#30213.  As justification, a recap and correction
of my diagnosis and solution from that report follows.

The async-shell-command-display-buffer toggle determines whether the
output buffer is displayed immediately or in the process filter, as the
latter should only be executed on process output.  The guard in the
process filter, however, has always required that the buffer (a) be
empty; and (b) have the same name as the original output buffer.

I assume the reasoning behind (a) is that we only want the output buffer
to be displayed when the process first outputs something, and not every
time the process filter is called.  As mentioned in bug#30213, though,
the empty buffer check is The Wrong Thing when
shell-command-dont-erase-buffer is non-nil, i.e. when we want to reuse a
non-empty output buffer left behind by an old shell-command invocation.
AIUI, the process filter advice needs a way to distinguish between the
first time it receives process output and all its subsequent triggers,
irrespective of buffer contents.

I'm not entirely sure what the case for (b) is.  Usually process filters
need only check that their process buffer is live before acting on it;
surely that is also The Right Thing in this case?  The main issue with
(b) is that it does not take into account the various flavours of
async-shell-command-buffer under which the output buffer is renamed, as
demonstrated in this bug report.  I think the simplest fix for (b) would
be something like


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: foo.diff --]
[-- Type: text/x-diff, Size: 761 bytes --]

diff --git a/lisp/simple.el b/lisp/simple.el
index 3ac6b86381..4f6708dbc1 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -3552,8 +3552,7 @@ shell-command
                                   (lambda (process _string)
                                     (let ((buf (process-buffer process)))
                                       (when (and (zerop (buffer-size buf))
-                                                 (string= (buffer-name buf)
-                                                          bname))
+                                                 (eq buf buffer))
                                         (display-buffer buf))))))))
 	    ;; Otherwise, command is executed synchronously.
 	    (shell-command-on-region (point) (point) command

[-- Attachment #4: Type: text/plain, Size: 825 bytes --]


but I still don't see why we are forgoing a liveness check in favour of
this.

I attach a patch which addresses both bugs.  Its solution for (a) is to
make the advice disposable, i.e. it removes itself from the process
filter after it has fulfilled its purpose of displaying the output
buffer.  A syntactically simpler implementation of this could use a
plain boolean switch instead of removing the advice, but IMO the latter
is semantically more sound (and possibly more performant in subsequent
invocations of the process filter, though this should be irrelevant).

WDYT?

P.S. Would patch(es) for aesthetic changes to the rest of shell-command
(such as removing redundant variables, inverting the condition of the
massive if-then-else to reduce indentation, etc.) be welcome?  If so,
where should I send them?

-- 
Basil

  parent reply	other threads:[~2018-01-30 18:53 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-28 22:20 bug#30280: async-shell-command-display-buffer doesn't work anymore Juri Linkov
2018-01-29 17:24 ` Eli Zaretskii
2018-01-29 21:40   ` Juri Linkov
2018-01-30  3:24     ` Eli Zaretskii
2018-01-30 18:53   ` Basil L. Contovounesios [this message]
2018-01-30 19:06     ` Reuben Thomas
2018-01-31 21:44     ` Juri Linkov
2018-02-02 10:42       ` Eli Zaretskii
2018-02-03 14:13         ` Basil L. Contovounesios
2018-02-03 21:27           ` Juri Linkov
2018-05-06 16:18             ` Basil L. Contovounesios
2018-05-07  7:35               ` Tino Calancha
2018-05-09 11:54                 ` Basil L. Contovounesios
2018-05-09 13:57                   ` Tino Calancha
2018-05-09 14:10                     ` Noam Postavsky
2018-05-09 14:24                       ` Tino Calancha
2018-05-09 18:29                     ` Basil L. Contovounesios
2018-05-10  2:13                       ` Tino Calancha

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=877erz41re.fsf@tcd.ie \
    --to=contovob@tcd.ie \
    --cc=30280@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=juri@linkov.net \
    --cc=rrt@sc3d.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).