From d1a93240cd6150f67622b9f6f91b29b768ee5231 Mon Sep 17 00:00:00 2001 From: Matthew White 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