]> git.eshelyaron.com Git - emacs.git/commitdiff
Change 'M-:' to not error out on incomplete expressions
authorCharles A. Roelli <charles@aurox.ch>
Mon, 10 Aug 2020 13:16:11 +0000 (15:16 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Mon, 10 Aug 2020 13:18:19 +0000 (15:18 +0200)
* 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).

etc/NEWS
lisp/simple.el

index e3d7ff0bef2d19b2698090ac7a89715ebdce97a8..7a38b4df1448e19f11b47c63b2cd5b55906223e3 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -101,6 +101,13 @@ deprecated.  Errors in the Inscript method were corrected.
 \f
 * 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
index 4a774bc9b4dd834966c78dc03b6aa3370c3dbc1d..4d59108a34fe0587e89700b049856cf85d34b773 100644 (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)