unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression
@ 2021-07-29 22:55 Matthew White
  2021-07-30  5:58 ` Eli Zaretskii
  0 siblings, 1 reply; 6+ messages in thread
From: Matthew White @ 2021-07-29 22:55 UTC (permalink / raw)
  To: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 2273 bytes --]

Hello,

I tumbled on the error in the subject, "Selecting deleted buffer",
evaluating the following line in the "*scratch*" buffer with C-j:

(kill-buffer (current-buffer))

When the other buffer isn't read-only, suppose "*foo*" is selected
after killing the current buffer "*scratch*", the error "Selecting
deleted buffer" appears into the echo area and the return value of
the evaluation is printed into the other buffer "*foo*".

If the other buffer is "*Messages*", which is read-only, the error
"Buffer is read-only: #<buffer *Messages*>" will appear instead.

I'd like to discuss the possibility to enforce printing the output
either to the initial current buffer when eval-print-last-sexp has
been called, or to the echo area when the prefix '-' is given.  If
the initial current buffer (aka standard-output) is killed, during
the evaluation of the expression, we fall back to the echo area as
the output medium.

I attach a patch as proof of concept.

Below there's a version of the current eval-print-last-sexp, as of
commit 7e8d1b08e3e23bc783cad10e620c2ebe6536965c, well commented:

(defun eval-print-last-sexp (&optional eval-last-sexp-arg-internal)
  (interactive "P")
  (let ((standard-output (current-buffer)))

    ;; This prints to `standard-output', aka `current-buffer'.

    (terpri)

    ;; Since `eval-last-sexp-arg-internal' is always replaced with t
    ;; when nil, the expression's return value is printed to what is
    ;; the actual `current-buffer' after the evaluation is done.  If
    ;; the initial buffer is killed, the current buffer is something
    ;; else after the evaluation.  "Buffer is read-only" is given if
    ;; the `current-buffer' is read-only, otherwise the return value
    ;; is printed at whatever is the actual `current-buffer' cursor.

    (eval-last-sexp (or eval-last-sexp-arg-internal t))

    ;; This prints to `standard-output', aka `current-buffer' before
    ;; the expression is evaluated.  If the `standard-output' buffer
    ;; has been killed evaluating the expression, the PRINTPREPARE C
    ;; macro will trigger an error trying to `set-buffer' the killed
    ;; buffer: "Selecting deleted buffer".

    (terpri)))

Thank you.

Best regards,
-Matthew

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-eval-print-last-sexp-print-to-initial-buffer-or-to-e.patch --]
[-- Type: text/x-patch, Size: 4428 bytes --]

From d1a93240cd6150f67622b9f6f91b29b768ee5231 Mon Sep 17 00:00:00 2001
From: Matthew White <mehw.is.me@inventati.org>
Date: Thu, 29 Jul 2021 20:24:37 +0000
Subject: [PATCH] eval-print-last-sexp: print to initial buffer or to echo area

* lisp/progmodes/elisp-mode.el (eval-print-last-sexp): Update
  docstring about the possible use of the prefix argument.  A
  '-' prefix prints to the echo area, otherwise prints to the
  initial current buffer (aka 'standard-output'), unless it's
  killed evaluating the expression.  If 'standard-output' has
  been killed, print to the echo area.  Do not print newlines
  to the echo area.

This prevents an error triggered when calling 'terpri' with a
PRINTCHARFUN or 'standard-output' set to a killed buffer.  To
be specific, PRINTPREPARE C macro may try to 'set-buffer' the
initial current buffer (aka 'standard-output') which has been
killed while evaluating the expression.

Also, when the initial current buffer is killed, unless a '-'
prefix argument is used, the output shouldn't be printed into
a different buffer than the initial one, but to the echo area.

The errors described above can be hit evaluating with C-j the
following expression in the *scratch* buffer:

(kill-buffer (current-buffer))

If the other buffer is not read-only, the evaluation's return
value is printed to the other buffer and the error "Selecting
deleted buffer" appears into the echo area.

If the other buffer is read-only, like the *Messages* buffer,
"Buffer is read-only: ..." appears into the echo area.
---
 lisp/progmodes/elisp-mode.el | 36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 7ed2d3d08c..20fcec6f85 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -1030,7 +1030,10 @@ Semicolons start comments.
 ;;; Globally accessible functionality
 
 (defun eval-print-last-sexp (&optional eval-last-sexp-arg-internal)
-  "Evaluate sexp before point; print value into current buffer.
+  "Evaluate sexp before point.
+
+Interactively, with a non `-' prefix argument, print output into
+current buffer, otherwise print in the echo area.
 
 Normally, this function truncates long output according to the value
 of the variables `eval-expression-print-length' and
@@ -1042,10 +1045,33 @@ also causes integers to be printed in several additional formats
 If `eval-expression-debug-on-error' is non-nil, which is the default,
 this command arranges for all errors to enter the debugger."
   (interactive "P")
-  (let ((standard-output (current-buffer)))
-    (terpri)
-    (eval-last-sexp (or eval-last-sexp-arg-internal t))
-    (terpri)))
+  (let* ((standard-output (current-buffer))
+         ;; Unless the output is already redirected to the echo area,
+         ;; force it to the `standard-output' if it is a live buffer.
+         (force-standard-output `(lambda (args)
+                                   (let ((value (nth 0 args))
+                                         (output (nth 1 args))
+                                         (rest (nthcdr 2 args)))
+                                     (unless (eq output t)
+                                       (setq output (if (buffer-live-p ,standard-output)
+                                                        ,standard-output
+                                                      t)))
+                                     (append (list value output) rest)))))
+    (pcase-let*
+        ((`(,insert-value ,no-truncate ,char-print-limit)
+          (eval-expression-get-print-arguments (or eval-last-sexp-arg-internal t))))
+      ;; Don't print newlines to the echo area.
+      (when insert-value
+        (terpri))
+      ;; The expression may kill `standard-output'.
+      (unwind-protect
+          (progn
+            (advice-add #'elisp--eval-last-sexp-print-value :filter-args force-standard-output)
+            (eval-last-sexp (list insert-value no-truncate char-print-limit)))
+        (advice-remove #'elisp--eval-last-sexp-print-value force-standard-output))
+      ;; Don't print to a killed `standard-output' buffer.
+      (when (and insert-value (buffer-live-p standard-output))
+        (terpri)))))
 
 
 (defun last-sexp-setup-props (beg end value alt1 alt2)
-- 
2.31.1


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression
  2021-07-29 22:55 eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression Matthew White
@ 2021-07-30  5:58 ` Eli Zaretskii
  2021-07-30 14:07   ` Matthew White
  0 siblings, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2021-07-30  5:58 UTC (permalink / raw)
  To: Matthew White; +Cc: emacs-devel

> Date: Fri, 30 Jul 2021 00:55:51 +0200
> From: Matthew White <mehw.is.me@inventati.org>
> 
> I tumbled on the error in the subject, "Selecting deleted buffer",
> evaluating the following line in the "*scratch*" buffer with C-j:
> 
> (kill-buffer (current-buffer))
> 
> When the other buffer isn't read-only, suppose "*foo*" is selected
> after killing the current buffer "*scratch*", the error "Selecting
> deleted buffer" appears into the echo area and the return value of
> the evaluation is printed into the other buffer "*foo*".
> 
> If the other buffer is "*Messages*", which is read-only, the error
> "Buffer is read-only: #<buffer *Messages*>" will appear instead.
> 
> I'd like to discuss the possibility to enforce printing the output
> either to the initial current buffer when eval-print-last-sexp has
> been called, or to the echo area when the prefix '-' is given.  If
> the initial current buffer (aka standard-output) is killed, during
> the evaluation of the expression, we fall back to the echo area as
> the output medium.

Could you please tell what are the real-life situations where this
problem happens and causes trouble?  Killing the current buffer this
way is unusual, so why isn't what we have now sufficient?  You tried
to insert something into a killed buffer, Emacs told you it cannot do
that; why is that a problem?

IME, trying to "fix" such obscure problems causes problems of its own
that we then get to rectify for several releases in the future, so the
net gains are very small if there are any.



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

* Re: eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression
  2021-07-30  5:58 ` Eli Zaretskii
@ 2021-07-30 14:07   ` Matthew White
  2021-07-31 13:13     ` Eli Zaretskii
  0 siblings, 1 reply; 6+ messages in thread
From: Matthew White @ 2021-07-30 14:07 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3165 bytes --]

On Fri, 30 Jul 2021 08:58:34 +0300
Eli Zaretskii <eliz@gnu.org> wrote:

> > Date: Fri, 30 Jul 2021 00:55:51 +0200
> > From: Matthew White <mehw.is.me@inventati.org>
> > 
> > I tumbled on the error in the subject, "Selecting deleted buffer",
> > evaluating the following line in the "*scratch*" buffer with C-j:
> > 
> > (kill-buffer (current-buffer))
> > 
> > When the other buffer isn't read-only, suppose "*foo*" is selected
> > after killing the current buffer "*scratch*", the error "Selecting
> > deleted buffer" appears into the echo area and the return value of
> > the evaluation is printed into the other buffer "*foo*".
> > 
> > If the other buffer is "*Messages*", which is read-only, the error
> > "Buffer is read-only: #<buffer *Messages*>" will appear instead.
> > 
> > I'd like to discuss the possibility to enforce printing the output
> > either to the initial current buffer when eval-print-last-sexp has
> > been called, or to the echo area when the prefix '-' is given.  If
> > the initial current buffer (aka standard-output) is killed, during
> > the evaluation of the expression, we fall back to the echo area as
> > the output medium.  
> 
> Could you please tell what are the real-life situations where this
> problem happens and causes trouble?  Killing the current buffer this
> way is unusual, so why isn't what we have now sufficient?  You tried
> to insert something into a killed buffer, Emacs told you it cannot do
> that; why is that a problem?

I understand that such occasions are rare, I mean killing the current
buffer evaluating an expression also in the current buffer like:

(kill-buffer (current-buffer))

eval-print-last-sexp is trying to insert something into a dead buffer,
by calling terpri with standard-output set to the dead buffer.

This could be prevented by checking standard-output:

(when (buffer-live-p standard-output)
  (terpri))

Less uncommon than killing the current buffer evaluating an expression
with C-j, is redirecting the output to the echo area with a '-' prefix
C-u - C-j.  I'd expect no output into the current buffer, and the call
to eval-last-sexp respects this, while terpri does not and prints into
the standard-output (aka current buffer at the time C-j was pressed).

There's also the strange behavior of printing to a buffer which is not
the one where the expression was evaluated. This is also rare, happens
when the buffer is killed, like described previously:

;; Always prints to the actual current buffer.
(eval-last-sexp (or eval-last-sexp-arg-internal t))

> 
> IME, trying to "fix" such obscure problems causes problems of its own
> that we then get to rectify for several releases in the future, so the
> net gains are very small if there are any.

I agree, there is a little gain into that.  I just explored the source
of the problems to understand what they are.

IMHO, when C-u - C-j is used terpri shouldn't print to stadard-output,
since the evaluation's return value is destined to the echo area.  And
checking if standard-output is a live buffer is also trivial.

What do you think?

Thanks.
-Matthew

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression
  2021-07-30 14:07   ` Matthew White
@ 2021-07-31 13:13     ` Eli Zaretskii
  2021-07-31 23:50       ` Michael Heerdegen
  2021-08-01  2:09       ` Matthew White
  0 siblings, 2 replies; 6+ messages in thread
From: Eli Zaretskii @ 2021-07-31 13:13 UTC (permalink / raw)
  To: Matthew White; +Cc: emacs-devel

> Date: Fri, 30 Jul 2021 16:07:53 +0200
> From: Matthew White <mehw.is.me@inventati.org>
> 
> > Could you please tell what are the real-life situations where this
> > problem happens and causes trouble?  Killing the current buffer this
> > way is unusual, so why isn't what we have now sufficient?  You tried
> > to insert something into a killed buffer, Emacs told you it cannot do
> > that; why is that a problem?
> 
> I understand that such occasions are rare, I mean killing the current
> buffer evaluating an expression also in the current buffer like:
> 
> (kill-buffer (current-buffer))
> 
> eval-print-last-sexp is trying to insert something into a dead buffer,
> by calling terpri with standard-output set to the dead buffer.
> 
> This could be prevented by checking standard-output:
> 
> (when (buffer-live-p standard-output)
>   (terpri))
> 
> Less uncommon than killing the current buffer evaluating an expression
> with C-j, is redirecting the output to the echo area with a '-' prefix
> C-u - C-j.  I'd expect no output into the current buffer, and the call
> to eval-last-sexp respects this, while terpri does not and prints into
> the standard-output (aka current buffer at the time C-j was pressed).
> 
> There's also the strange behavior of printing to a buffer which is not
> the one where the expression was evaluated. This is also rare, happens
> when the buffer is killed, like described previously:
> 
> ;; Always prints to the actual current buffer.
> (eval-last-sexp (or eval-last-sexp-arg-internal t))
> 
> > 
> > IME, trying to "fix" such obscure problems causes problems of its own
> > that we then get to rectify for several releases in the future, so the
> > net gains are very small if there are any.
> 
> I agree, there is a little gain into that.  I just explored the source
> of the problems to understand what they are.
> 
> IMHO, when C-u - C-j is used terpri shouldn't print to stadard-output,
> since the evaluation's return value is destined to the echo area.  And
> checking if standard-output is a live buffer is also trivial.
> 
> What do you think?

I think we should leave this issue alone, but maybe someone else has a
different opinion and a rationale to go with that?



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

* Re: eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression
  2021-07-31 13:13     ` Eli Zaretskii
@ 2021-07-31 23:50       ` Michael Heerdegen
  2021-08-01  2:09       ` Matthew White
  1 sibling, 0 replies; 6+ messages in thread
From: Michael Heerdegen @ 2021-07-31 23:50 UTC (permalink / raw)
  To: emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> I think we should leave this issue alone, but maybe someone else has a
> different opinion and a rationale to go with that?

Maybe the OP is just not familiar with the alternative C-x C-e?

When you eval an expression that kills the current buffer and explicitly
choose the command to print the result into the current buffer that is a
pilot error.

Michael.




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

* Re: eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression
  2021-07-31 13:13     ` Eli Zaretskii
  2021-07-31 23:50       ` Michael Heerdegen
@ 2021-08-01  2:09       ` Matthew White
  1 sibling, 0 replies; 6+ messages in thread
From: Matthew White @ 2021-08-01  2:09 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 649 bytes --]

On Sat, 31 Jul 2021 16:13:02 +0300
Eli Zaretskii <eliz@gnu.org> wrote:

> I think we should leave this issue alone, but maybe someone else has a
> different opinion and a rationale to go with that?

I definitely agree.

I also read the answer of Michael Heerdegen... I was too much into
studying eval-print-last-sexp... it even calls eval-print-sexp...!

I understand now, thanks to you and Michael.  Using C-x C-e rather
than C-j to call eval-print-sexp directly, to print the evaluation
result into the echo area, dispels my doubts.

It was a good excuse for me to look also into Emacs' C source code...

Thanks again.
-Matthew

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

end of thread, other threads:[~2021-08-01  2:09 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-29 22:55 eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression Matthew White
2021-07-30  5:58 ` Eli Zaretskii
2021-07-30 14:07   ` Matthew White
2021-07-31 13:13     ` Eli Zaretskii
2021-07-31 23:50       ` Michael Heerdegen
2021-08-01  2:09       ` Matthew White

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