unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Matthew White <mehw.is.me@inventati.org>
To: emacs-devel@gnu.org
Subject: eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression
Date: Fri, 30 Jul 2021 00:55:51 +0200	[thread overview]
Message-ID: <20210730005551.5c77f879@pineapple> (raw)


[-- 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 --]

             reply	other threads:[~2021-07-29 22:55 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-29 22:55 Matthew White [this message]
2021-07-30  5:58 ` eval-print-last-sexp: "Selecting deleted buffer" error when the current buffer is killed evaluating the expression 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

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=20210730005551.5c77f879@pineapple \
    --to=mehw.is.me@inventati.org \
    --cc=emacs-devel@gnu.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).