Subject: bug#36145: 26.2; Unable to "trigger another backtrace"

From: Noam Postavsky <[email-masked]>
Date: Fri, 21 Jun 2019 08:21:10 -0400

severity 36145 minor
tags 36145 + patch
quit

> Although it is possible to trigger another backtrace if the first one
> was from calling `debug' directly, e.g., M-: (debug) RET.

And it's also possible to trigger another backtrace with 'e', if using
it from a frame above the debugger's.  I bump into this every so often
by accident, and it's quite annoying.  Of course, I'm always in the
middle of debugging something else so I forget about it, but I'd like to
change it.  Patch attached.

>From c6d52846598eeaf200c553ff0ac9f16db612b64e Mon Sep 17 00:00:00 2001
From: Noam Postavsky <[email-masked]>
Date: Fri, 21 Jun 2019 08:14:20 -0400
Subject: [PATCH] Suppress recursive debugger for 'e' command (Bug#36145)

* lisp/emacs-lisp/debug.el (debugger-eval-expression):
* lisp/emacs-lisp/edebug.el (edebug-eval-expression)
(edebug-eval-last-sexp, edebug-eval-print-last-sexp): Suppress
debugger with inhibit-debugger, unless given a prefix argument.
* doc/lispref/edebug.texi (Edebug Eval):
* doc/lispref/debugging.texi (Debugger Commands, Backtraces): Document
new behavior.
(Using Debugger): Remove incorrect paragraph about debug-on-error.
* etc/NEWS: Announce new behavior.
---
 doc/lispref/debugging.texi | 15 ++++-----------
 doc/lispref/edebug.texi    | 10 +++++++---
 etc/NEWS                   | 11 +++++++++++
 lisp/emacs-lisp/debug.el   | 12 ++++++++----
 lisp/emacs-lisp/edebug.el  | 33 +++++++++++++++++++++------------
 5 files changed, 51 insertions(+), 30 deletions(-)

diff --git a/doc/lispref/debugging.texi b/doc/lispref/debugging.texi
index 9e43343310..7538e70ab5 100644
--- a/doc/lispref/debugging.texi
+++ b/doc/lispref/debugging.texi
@@ -383,16 +383,6 @@ Using Debugger
 rather than bury it.  Consult the variable's documentation for more
 possibilities.)
 
-  When the debugger has been entered, the @code{debug-on-error}
-variable is temporarily set according to
-@code{eval-expression-debug-on-error}.  If the latter variable is
-non-@code{nil}, @code{debug-on-error} will temporarily be set to
-@code{t}.  This means that any further errors that occur while doing a
-debugging session will (by default) trigger another backtrace.  If
-this is not what you want, you can either set
-@code{eval-expression-debug-on-error} to @code{nil}, or set
-@code{debug-on-error} to @code{nil} in @code{debugger-mode-hook}.
-
   The debugger itself must be run byte-compiled, since it makes
 assumptions about the state of the Lisp interpreter.  These
 assumptions are false if the debugger is running interpreted.
@@ -527,7 +517,10 @@ Debugger Commands
 temporarily restores their values from outside the debugger, so you can
 examine and change them.  This makes the debugger more transparent.  By
 contrast, @kbd{M-:} does nothing special in the debugger; it shows you
-the variable values within the debugger.
+the variable values within the debugger.  By default, this command
+suppresses the debugger during evaluation, so that an error in the
+evaluated expression won't add a new error on top of the existing one.
+Use the prefix argument to override this.
 
 @item R
 Like @kbd{e}, but also save the result of evaluation in the
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index 2c0ee3969b..823a5009e8 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -681,8 +681,11 @@ Edebug Eval
 @table @kbd
 @item e @var{exp} @key{RET}
 Evaluate expression @var{exp} in the context outside of Edebug
-(@code{edebug-eval-expression}).  That is, Edebug tries to minimize its
-interference with the evaluation.
+(@code{edebug-eval-expression}).  That is, Edebug tries to minimize
+its interference with the evaluation.  By default, this command
+suppresses the debugger during evaluation, so that an error in the
+evaluated expression won't add a new error on top of the existing one.
+Use a prefix argument to override this.
 
 @item M-: @var{exp} @key{RET}
 Evaluate expression @var{exp} in the context of Edebug itself
@@ -690,7 +693,8 @@ Edebug Eval
 
 @item C-x C-e
 Evaluate the expression before point, in the context outside of Edebug
-(@code{edebug-eval-last-sexp}).
+(@code{edebug-eval-last-sexp}).  Similar to @key{e}, this command
+suppresses the debugger unless a prefix argument is used.
 @end table
 
 @cindex lexical binding (Edebug)
diff --git a/etc/NEWS b/etc/NEWS
index 4a168d5678..43dc6ea969 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1074,6 +1074,11 @@ Backtrace mode adds fontification and commands for changing the
 appearance of backtrace frames.  See the node "(elisp) Backtraces" in
 the Elisp manual for documentation of the new mode and its commands.
 
++++
+*** Recursive debugging is suppressed by default for 'e'.
+That is bound to the command 'debug-eval-expression'.  Use a prefix
+argument to override this.
+
 ** Edebug
 
 +++
@@ -1098,6 +1103,12 @@ The new 'backtrace-goto-source' command, bound to 's', works in
 Edebug's backtraces on backtrace frames whose source code has
 been instrumented by Edebug.
 
++++
+*** Backtrace debugging is suppressed by default for 'e' and 'C-x C-e'.
+Those are bound to the commands 'edebug-eval-expression' and
+'edebug-eval-last-sexp', respectively.  Use a prefix argument to
+override this.
+
 ** Enhanced xterm support
 
 *** New variable 'xterm-set-window-title' controls whether Emacs sets
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 8989aa0719..20aceccb68 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -516,17 +516,21 @@ (defun debugger--backtrace-base ()
 	 'debug--implement-debug-on-entry)
 	(t 'debug)))
 
-(defun debugger-eval-expression (exp &optional nframe)
+(defun debugger-eval-expression (exp &optional nframe allow-recursive-debug)
   "Eval an expression, in an environment like that outside the debugger.
-The environment used is the one when entering the activation frame at point."
+The environment used is the one when entering the activation frame at point.
+With a prefix argument, errors signaled while evaluating may
+trigger the debugger again."
   (interactive
-   (list (read--expression "Eval in stack frame: ")))
+   (list (read--expression "Eval in stack frame: ")
+         nil current-prefix-arg))
   (let ((nframe (or nframe
                     (condition-case nil (1+ (debugger-frame-number 'skip-base))
                       (error 0)))) ;; If on first line.
 	(base (debugger--backtrace-base)))
     (debugger-env-macro
-      (let ((val (backtrace-eval exp nframe base)))
+      (let ((val (let ((inhibit-debugger (not allow-recursive-debug)))
+                   (backtrace-eval exp nframe base))))
         (prog1
             (debugger--print val t)
           (let ((str (eval-expression-print-format val)))
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index ab5553b4e8..1f9d994fed 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -3580,28 +3580,37 @@ (defalias 'edebug-prin1-to-string #'cl-prin1-to-string)
 (defalias 'edebug-format #'format-message)
 (defalias 'edebug-message #'message)
 
-(defun edebug-eval-expression (expr)
+(defun edebug-eval-expression (expr &optional allow-debugger)
   "Evaluate an expression in the outside environment.
 If interactive, prompt for the expression.
-Print result in minibuffer."
-  (interactive (list (read--expression "Eval: ")))
+Print result in minibuffer.
+With a prefix argument, errors signaled while evaluating may
+trigger the debugger."
+  (interactive (list (read--expression "Eval: ")
+                     current-prefix-arg))
   (princ
    (edebug-outside-excursion
-    (setq values (cons (edebug-eval expr) values))
+    (push (let ((inhibit-debugger (not allow-debugger)))
+            (edebug-eval expr))
+          values)
     (concat (edebug-safe-prin1-to-string (car values))
             (eval-expression-print-format (car values))))))
 
-(defun edebug-eval-last-sexp ()
+(defun edebug-eval-last-sexp (&optional allow-debugger)
   "Evaluate sexp before point in the outside environment.
-Print value in minibuffer."
-  (interactive)
-  (edebug-eval-expression (edebug-last-sexp)))
+Print value in minibuffer.
+With a prefix argument, errors signaled while evaluating may
+trigger the debugger."
+  (interactive "P")
+  (edebug-eval-expression (edebug-last-sexp allow-debugger)))
 
-(defun edebug-eval-print-last-sexp ()
+(defun edebug-eval-print-last-sexp (&optional allow-debugger)
   "Evaluate sexp before point in outside environment; insert value.
-This prints the value into current buffer."
-  (interactive)
-  (let* ((form (edebug-last-sexp))
+This prints the value into current buffer.
+With a prefix argument, errors signaled while evaluating may
+trigger the debugger."
+  (interactive "P")
+  (let* ((form (edebug-last-sexp allow-debugger))
 	 (result-string
 	  (edebug-outside-excursion
 	   (edebug-safe-prin1-to-string (edebug-safe-eval form))))
-- 
2.11.0