all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Making debugging possible on expressions executed from ielm
@ 2018-01-13  9:22 Jarosław Rzeszótko
  2018-01-15 17:23 ` Stefan Monnier
  2018-01-15 19:22 ` Jarosław Rzeszótko
  0 siblings, 2 replies; 8+ messages in thread
From: Jarosław Rzeszótko @ 2018-01-13  9:22 UTC (permalink / raw)
  To: emacs-devel@gnu.org


[-- Attachment #1.1: Type: text/plain, Size: 1682 bytes --]

I attach a patch for ielm.el that makes it possible to enter the debugger
when executing expressions in ielm, and that makes ielm respect the
debug-on-error and debug-on-exit flags.

I guess that possibly the reason that was not originally done is that it is
not obvious how to restore ielm to a usable state after the debugger has
been entered. My patch makes use of the fact that unwind-protect unwind
forms are still executed when user resumes execution from the debugger
after an error.

Without the patch, ielm wraps the evaluation of the expression given by the
user in a condition case, and in case of an error, or exit, displays an
appropriate message in its buffer, right under the evaluated expression,
regardless of debug-on-error and debug-on-exit.

With the patch, the message that ielm displays in its buffer will be a
generic error message  regardless if there was an error in the evaluated
form, or a quit. However:

- if debug-on-error is t, emacs will enter the debugger and show a stack
trace, just like with almost any other evaluation method. When the user
continues the execution from the debugger, ielm will correctly resume
execution

- if debug-on-error is nil, emacs will display the specific error in the
minibuffer anyway

Similar things are true for debug-on-quit.

I think this is an improvement over the current state of affairs. Of course
ideally I would like to preserve the "nice" message in ielm buffer and make
the improvements I made, but emacs does not seem to make it possible to do
some handling of an error and then to re-raise it while preserving the
original stack trace.

Cheers,
Jarosław Rzeszótko

[-- Attachment #1.2: Type: text/html, Size: 1936 bytes --]

[-- Attachment #2: ielm-debug-on-error.el.patch --]
[-- Type: text/x-patch, Size: 12410 bytes --]

diff --git a/lisp/ielm.el b/lisp/ielm.el
index fb285e80f6..13bb4693cd 100644
--- a/lisp/ielm.el
+++ b/lisp/ielm.el
@@ -353,113 +353,117 @@ nonempty, then flushes the buffer."
         (output "")                  ; result to display
         (wbuf ielm-working-buffer)   ; current buffer after evaluation
         (pmark (ielm-pm)))
-    (unless (ielm-is-whitespace-or-comment string)
-      (condition-case err
-          (let ((rout (read-from-string string)))
-            (setq form (car rout)
-                  pos (cdr rout)))
-        (error (setq result (error-message-string err))
-               (setq error-type "Read error")))
-      (unless error-type
-        ;; Make sure working buffer has not been killed
-        (if (not (buffer-name ielm-working-buffer))
-            (setq result "Working buffer has been killed"
-                  error-type "IELM Error"
-                  wbuf (current-buffer))
-          (if (ielm-is-whitespace-or-comment (substring string pos))
-              ;; To correctly handle the ielm-local variables *,
-              ;; ** and ***, we need a temporary buffer to be
-              ;; current at entry to the inner of the next two let
-              ;; forms.  We need another temporary buffer to exit
-              ;; that same let.  To avoid problems, neither of
-              ;; these buffers should be alive during the
-              ;; evaluation of form.
-              (let* ((*1 *)
-                     (*2 **)
-                     (*3 ***)
-                     (active-process (ielm-process))
-                     (old-standard-output standard-output)
-                     new-standard-output
-                     ielm-temp-buffer)
-                (set-match-data ielm-match-data)
-                (save-excursion
-                  (with-temp-buffer
-                    (condition-case err
-                        (unwind-protect
-                            ;; The next let form creates default
-                            ;; bindings for *, ** and ***.  But
-                            ;; these default bindings are
-                            ;; identical to the ielm-local
-                            ;; bindings.  Hence, during the
-                            ;; evaluation of form, the
-                            ;; ielm-local values are going to be
-                            ;; used in all buffers except for
-                            ;; other ielm buffers, which override
-                            ;; them.  Normally, the variables *1,
-                            ;; *2 and *3 also have default
-                            ;; bindings, which are not overridden.
-                            (let ((* *1)
-                                  (** *2)
-                                  (*** *3))
-                              (when (eq standard-output t)
-                                (setf new-standard-output
-                                      (ielm-standard-output-impl
-                                       active-process))
-                                (setf standard-output new-standard-output))
-                              (kill-buffer (current-buffer))
-                              (set-buffer wbuf)
-                              (setq result
-                                    (eval form lexical-binding))
-                              (setq wbuf (current-buffer))
-                              (setq
-                               ielm-temp-buffer
-                               (generate-new-buffer " *ielm-temp*"))
-                              (set-buffer ielm-temp-buffer))
-                          (when ielm-temp-buffer
-                            (kill-buffer ielm-temp-buffer))
-                          (when (eq new-standard-output standard-output)
-                            (ignore-errors
-                              (funcall standard-output t))
-                            (setf standard-output old-standard-output)))
-                      (error (setq result (error-message-string err))
-                             (setq error-type "Eval error"))
-                      (quit (setq result "Quit during evaluation")
-                            (setq error-type "Eval error")))))
-                (setq ielm-match-data (match-data)))
-            (setq error-type "IELM error")
-            (setq result "More than one sexp in input"))))
-
-      ;; If the eval changed the current buffer, mention it here
-      (unless (eq wbuf ielm-working-buffer)
-        (message "current buffer is now: %s" wbuf)
-        (setq ielm-working-buffer wbuf))
-
-      (goto-char pmark)
-      (unless error-type
-        (condition-case nil
-            ;; Self-referential objects cause loops in the printer, so
-            ;; trap quits here. May as well do errors, too
-            (unless for-effect
-              (setq output (concat output (pp-to-string result)
-				   (let ((str (eval-expression-print-format result)))
-				     (if str (propertize str 'font-lock-face 'shadow))))))
-          (error (setq error-type "IELM Error")
-                 (setq result "Error during pretty-printing (bug in pp)"))
-          (quit  (setq error-type "IELM Error")
-                 (setq result "Quit during pretty-printing"))))
-      (if error-type
+    (unwind-protect
+        (progn
+          (unless (ielm-is-whitespace-or-comment string)
+            (condition-case err
+                (let ((rout (read-from-string string)))
+                  (setq form (car rout)
+                        pos (cdr rout)))
+              (error (setq result (error-message-string err))
+                     (setq error-type "Read error")))
+            (unless error-type
+              ;; Make sure working buffer has not been killed
+              (if (not (buffer-name ielm-working-buffer))
+                  (setq result "Working buffer has been killed"
+                        error-type "IELM Error"
+                        wbuf (current-buffer))
+                (if (ielm-is-whitespace-or-comment (substring string pos))
+                    ;; To correctly handle the ielm-local variables *,
+                    ;; ** and ***, we need a temporary buffer to be
+                    ;; current at entry to the inner of the next two let
+                    ;; forms.  We need another temporary buffer to exit
+                    ;; that same let.  To avoid problems, neither of
+                    ;; these buffers should be alive during the
+                    ;; evaluation of form.
+                    (let* ((*1 *)
+                           (*2 **)
+                           (*3 ***)
+                           (active-process (ielm-process))
+                           (old-standard-output standard-output)
+                           new-standard-output
+                           ielm-temp-buffer)
+                      (set-match-data ielm-match-data)
+                      (save-excursion
+                        (with-temp-buffer
+                          (unwind-protect
+                              ;; The next let form creates default
+                              ;; bindings for *, ** and ***.  But
+                              ;; these default bindings are
+                              ;; identical to the ielm-local
+                              ;; bindings.  Hence, during the
+                              ;; evaluation of form, the
+                              ;; ielm-local values are going to be
+                              ;; used in all buffers except for
+                              ;; other ielm buffers, which override
+                              ;; them.  Normally, the variables *1,
+                              ;; *2 and *3 also have default
+                              ;; bindings, which are not overridden.
+                              (let ((* *1)
+                                    (** *2)
+                                    (*** *3))
+                                (setq result nil)
+                                (when (eq standard-output t)
+                                  (setf new-standard-output
+                                        (ielm-standard-output-impl
+                                         active-process))
+                                  (setf standard-output new-standard-output))
+                                (kill-buffer (current-buffer))
+                                (set-buffer wbuf)
+                                ;; Will immediately get
+                                ;; overwritten, but only if eval
+                                ;; does not throw an error
+                                (setq error-type "Eval error")
+                                (setq result
+                                      (eval form lexical-binding))
+                                (setq error-type nil)
+                                (setq wbuf (current-buffer))
+                                (setq
+                                 ielm-temp-buffer
+                                 (generate-new-buffer " *ielm-temp*"))
+                                (set-buffer ielm-temp-buffer))
+                            (when ielm-temp-buffer
+                              (kill-buffer ielm-temp-buffer))
+                            (when (eq new-standard-output standard-output)
+                              (ignore-errors
+                                (funcall standard-output t))
+                              (setf standard-output old-standard-output)))))
+                      (setq ielm-match-data (match-data)))
+                  (setq error-type "IELM error")
+                  (setq result "More than one sexp in input"))))
+
+            ;; If the eval changed the current buffer, mention it here
+            (unless (eq wbuf ielm-working-buffer)
+              (message "current buffer is now: %s" wbuf)
+              (setq ielm-working-buffer wbuf))
+
+            (goto-char pmark)
+            (unless error-type
+              (condition-case nil
+                  ;; Self-referential objects cause loops in the printer, so
+                  ;; trap quits here. May as well do errors, too
+                  (unless for-effect
+                    (setq output (concat output (pp-to-string result)
+                                         (let ((str (eval-expression-print-format result)))
+                                           (if str (propertize str 'font-lock-face 'shadow))))))
+                (error (setq error-type "IELM Error")
+                       (setq result "Error during pretty-printing (bug in pp)"))
+                (quit  (setq error-type "IELM Error")
+                       (setq result "Quit during pretty-printing"))))))
           (progn
-            (when ielm-noisy (ding))
-            (setq output (concat output "*** " error-type " ***  "))
-            (setq output (concat output result)))
-        ;; There was no error, so shift the *** values
-        (setq *** **)
-        (setq ** *)
-        (setq * result))
-      (when (or (not for-effect) (not (equal output "")))
-        (setq output (concat output "\n"))))
-    (setq output (concat output ielm-prompt-internal))
-    (comint-output-filter (ielm-process) output)))
+            (if error-type
+                (progn
+                  (when ielm-noisy (ding))
+                  (setq output (concat output "*** " error-type " ***  "))
+                  (setq output (concat output result)))
+              ;; There was no error, so shift the *** values
+              (setq *** **)
+              (setq ** *)
+              (setq * result))
+            (when (or (not for-effect) (not (equal output "")))
+              (setq output (concat output "\n"))))
+          (setq output (concat output ielm-prompt-internal))
+          (comint-output-filter (ielm-process) output))))
 
 ;;; Process and marker utilities
 
@@ -517,9 +521,6 @@ causes output to be directed to the ielm buffer.
 set to a different value during evaluation.  You can use (princ
 VALUE) or (pp VALUE) to write to the ielm buffer.
 
-Expressions evaluated by IELM are not subject to `debug-on-quit' or
-`debug-on-error'.
-
 The behavior of IELM may be customized with the following variables:
 * To stop beeping on error, set `ielm-noisy' to nil.
 * If you don't like the prompt, you can change it by setting `ielm-prompt'.

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2018-01-20 17:55 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-01-13  9:22 Making debugging possible on expressions executed from ielm Jarosław Rzeszótko
2018-01-15 17:23 ` Stefan Monnier
2018-01-15 19:22 ` Jarosław Rzeszótko
2018-01-15 21:59   ` Stefan Monnier
2018-01-16  6:42     ` Jarosław Rzeszótko
2018-01-19 19:14   ` Jarosław Rzeszótko
2018-01-19 19:58     ` Eli Zaretskii
2018-01-20 17:55   ` Stefan Monnier

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.