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 --]
next 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
* 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 external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.