Change 'M-:' to not error out on incomplete expressions

* lisp/simple.el (read--expression-try-read): New function to read
a Lisp expression from the minibuffer (bug#30697).  This will not
(as before) signal an error on incomplete expressions, but allow
users to continue editing it.
(read--expression): Use it (and add a doc string).
This commit is contained in:
Charles A. Roelli 2020-08-10 15:16:11 +02:00 committed by Lars Ingebrigtsen
parent 70825a4d31
commit 4a6dd13fa4
2 changed files with 52 additions and 0 deletions

View file

@ -101,6 +101,13 @@ deprecated. Errors in the Inscript method were corrected.
* Editing Changes in Emacs 28.1
---
** 'eval-expression' now no longer signals an error on incomplete expressions.
Previously, typing 'M-: ( RET' would result in Emacs saying "End of
file during parsing" and dropping out of the minibuffer. The user
would have to type 'M-: M-p' to edit and redo the expression. Now
Emacs will echo the message and allow the user to continue editing.
+++
** New command 'undo-redo'.
It undoes previous undo commands, but doesn't record itself as an

View file

@ -1619,6 +1619,10 @@ display the result of expression evaluation."
"Hook run by `eval-expression' when entering the minibuffer.")
(defun read--expression (prompt &optional initial-contents)
"Read an Emacs Lisp expression from the minibuffer.
PROMPT and optional argument INITIAL-CONTENTS do the same as in
function `read-from-minibuffer'."
(let ((minibuffer-completing-symbol t))
(minibuffer-with-setup-hook
(lambda ()
@ -1629,11 +1633,52 @@ display the result of expression evaluation."
(set-syntax-table emacs-lisp-mode-syntax-table)
(add-hook 'completion-at-point-functions
#'elisp-completion-at-point nil t)
(local-set-key "\r" 'read--expression-try-read)
(local-set-key "\n" 'read--expression-try-read)
(run-hooks 'eval-expression-minibuffer-setup-hook))
(read-from-minibuffer prompt initial-contents
read-expression-map t
'read-expression-history))))
(defun read--expression-try-read ()
"Try to read an Emacs Lisp expression in the minibuffer.
Exit the minibuffer if successful, else report the error to the
user and move point to the location of the error. If point is
not already at the location of the error, push a mark before
moving point."
(interactive)
(unless (> (minibuffer-depth) 0)
(error "Minibuffer must be active"))
(if (let* ((contents (minibuffer-contents))
(error-point nil))
(with-temp-buffer
(condition-case err
(progn
(insert contents)
(goto-char (point-min))
;; `read' will signal errors like "End of file during
;; parsing" and "Invalid read syntax".
(read (current-buffer))
;; Since `read' does not signal the "Trailing garbage
;; following expression" error, we check for trailing
;; garbage ourselves.
(or (progn
;; This check is similar to what `string_to_object'
;; does in minibuf.c.
(skip-chars-forward " \t\n")
(= (point) (point-max)))
(error "Trailing garbage following expression")))
(error
(setq error-point (+ (length (minibuffer-prompt)) (point)))
(with-current-buffer (window-buffer (minibuffer-window))
(unless (= (point) error-point)
(push-mark))
(goto-char error-point)
(minibuffer-message (error-message-string err)))
nil))))
(exit-minibuffer)))
(defun eval-expression-get-print-arguments (prefix-argument)
"Get arguments for commands that print an expression result.
Returns a list (INSERT-VALUE NO-TRUNCATE CHAR-PRINT-LIMIT)