aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Schmidt2025-08-21 20:58:42 +0200
committerEli Zaretskii2025-08-30 12:30:21 +0300
commitfdc6bb2caf959ceafd1c516f4f7a0687eb292ea4 (patch)
tree5bdf9f3b52ffac118c3865bc2e16b07431e13583
parent34f3ac6c5b98d79e51bd9bbaf3c5bd89b2faaba3 (diff)
downloademacs-fdc6bb2caf959ceafd1c516f4f7a0687eb292ea4.tar.gz
emacs-fdc6bb2caf959ceafd1c516f4f7a0687eb292ea4.zip
Add edebug-bounce-to-previous-value
Command edebug-bounce-to-previous-value uses the previous value observed while single-stepping or evaluating an expression to bounce point in the outside current buffer to the buffer position corresponding to that value. * lisp/emacs-lisp/edebug.el (edebug-previous-value): Add variable. (edebug-compute-previous-result, edebug-eval-expression): Update it. (edebug-bounce-to-previous-value): Add command. (edebug-mode-map): Add keybinding for the new command, replacing the binding of "P" to edebug-view-outside. (edebug-mode-menus): Add menu entry for the new command. * doc/lispref/edebug.texi (Edebug Views): Add documentation. * test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el (edebug-test-code-bounce-point): Add test code. * test/lisp/emacs-lisp/edebug-tests.el (edebug-tests-bounce-outside-buffer) (edebug-tests-bounce-outside-point) (edebug-tests-bounce-outside-mark) (edebug-tests-bounce-record-outside-environment) (edebug-tests-should-have-bounced-to): Add infrastructure to test bounces. (edebug-tests-check-keymap): Update tests to new key bindings. (edebug-tests-bounce-point) (edebug-tests-bounce-to-previous-value) (edebug-tests-bounce-to-previous-non-position): Add tests. (edebug-tests-evaluation-of-current-buffer-bug-19611): Clean up side effects. (Bug#79288)
-rw-r--r--doc/lispref/edebug.texi28
-rw-r--r--etc/NEWS12
-rw-r--r--lisp/emacs-lisp/edebug.el47
-rw-r--r--test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el10
-rw-r--r--test/lisp/emacs-lisp/edebug-tests.el147
5 files changed, 222 insertions, 22 deletions
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index f16190b85c9..97909e2bb55 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -677,8 +677,7 @@ effect outside of Edebug.
677 677
678@table @kbd 678@table @kbd
679@findex edebug-view-outside 679@findex edebug-view-outside
680@item P 680@item v
681@itemx v
682Switch to viewing the outside window configuration 681Switch to viewing the outside window configuration
683(@code{edebug-view-outside}). Type @kbd{C-x X w} to return to Edebug. 682(@code{edebug-view-outside}). Type @kbd{C-x X w} to return to Edebug.
684 683
@@ -689,6 +688,17 @@ outside position (@code{edebug-bounce-point}), pausing for one second
689before returning to Edebug. With a prefix argument @var{n}, pause for 688before returning to Edebug. With a prefix argument @var{n}, pause for
690@var{n} seconds instead. 689@var{n} seconds instead.
691 690
691@findex edebug-bounce-to-previous-value
692@item P
693Temporarily display the outside current buffer with the outside point
694corresponding to the previous value
695(@code{edebug-bounce-to-previous-value}). The previous value is what
696Edebug has evaluated before its last stop point or what you have
697evaluated in the context outside of Edebug, for example, with
698@kbd{C-x C-e}. This command pauses for one second before returning to
699Edebug. With a prefix argument @var{n}, it pauses for @var{n} seconds
700instead.
701
692@findex edebug-where 702@findex edebug-where
693@item w 703@item w
694Move point back to the current stop point in the source code buffer 704Move point back to the current stop point in the source code buffer
@@ -713,6 +723,20 @@ source code buffer, you must use @kbd{C-x X W} from the global keymap.
713bounce to the point in the current buffer with @kbd{p}, even if 723bounce to the point in the current buffer with @kbd{p}, even if
714it is not normally displayed. 724it is not normally displayed.
715 725
726 You can also bounce to buffer positions other than the current point.
727Suppose you are debugging the form
728
729@example
730(make-overlay beg end)
731@end example
732
733@noindent
734and you would like to know where @code{beg} and @code{end} are located
735in the outside buffer. Then you could either evaluate these, for
736example, with @kbd{C-x C-e}, or step over them with @kbd{n}, and
737immediately after that press @kbd{P}, to bounce to the position you have
738previously evaluated.
739
716 After moving point, you may wish to jump back to the stop point. 740 After moving point, you may wish to jump back to the stop point.
717You can do that with @kbd{w} from a source code buffer. You can jump 741You can do that with @kbd{w} from a source code buffer. You can jump
718back to the stop point in the source code buffer from any buffer using 742back to the stop point in the source code buffer from any buffer using
diff --git a/etc/NEWS b/etc/NEWS
index 37d38d0d91d..c9f30dc7ef7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2521,6 +2521,18 @@ If non-nil, FFAP always finds remote files in buffers with remote
2521'default-directory'. If nil, FFAP finds local files first for absolute 2521'default-directory'. If nil, FFAP finds local files first for absolute
2522file names in above buffers. The default is nil. 2522file names in above buffers. The default is nil.
2523 2523
2524** Debugging
2525
2526+++
2527*** New command 'edebug-bounce-to-previous-value' (bound to 'P')
2528This command temporarily displays the outside current buffer with the
2529outside point corresponding to the previous value, where the previous
2530value is what Edebug has evaluated before its last stop point or what
2531the user has evaluated in the context outside of Edebug.
2532
2533This replaces the binding of command 'edebug-view-outside' to 'P', which
2534is still available on 'v'.
2535
2524--- 2536---
2525** Flymake 2537** Flymake
2526 2538
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 284e3acd959..fc349787c93 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -2617,7 +2617,11 @@ when edebug becomes active."
2617 2617
2618(defvar edebug-eval-list nil) ;; List of expressions to evaluate. 2618(defvar edebug-eval-list nil) ;; List of expressions to evaluate.
2619 2619
2620(defvar edebug-previous-result nil) ;; Last result returned. 2620;; Last value seen while single-stepping or evaluating in the outside
2621;; environment.
2622(defvar edebug-previous-value nil)
2623;; Last value seen while single-stepping, converted to a string.
2624(defvar edebug-previous-result nil)
2621 2625
2622(defun edebug--display (value offset-index arg-mode) 2626(defun edebug--display (value offset-index arg-mode)
2623 ;; edebug--display-1 is too big, we should split it. This function 2627 ;; edebug--display-1 is too big, we should split it. This function
@@ -3113,6 +3117,37 @@ before returning. The default is one second."
3113 (sit-for arg) 3117 (sit-for arg)
3114 (edebug-pop-to-buffer edebug-buffer (car edebug-window-data))))) 3118 (edebug-pop-to-buffer edebug-buffer (car edebug-window-data)))))
3115 3119
3120(defun edebug-bounce-to-previous-value (arg)
3121 "Bounce point to previous value in the outside current buffer.
3122The previous value is what Edebug has evaluated before its last stop
3123point or what you have evaluated in the context outside of Edebug, for
3124example, by calling function `edebug-eval-expression', whatever comes
3125later.
3126If prefix argument ARG is supplied, sit for that many seconds before
3127returning. The default is one second."
3128 (interactive "p")
3129 (if (not edebug-active)
3130 (error "Edebug is not active"))
3131 (if (not (integer-or-marker-p edebug-previous-value))
3132 (error "Previous value not a number or marker"))
3133 (save-excursion
3134 ;; If the buffer's currently displayed, avoid set-window-configuration.
3135 (save-window-excursion
3136 (let ((point-info ""))
3137 (edebug-pop-to-buffer edebug-outside-buffer)
3138 (cond
3139 ((< edebug-previous-value (point-min))
3140 (setq point-info (format " (< Point min: %s)" (point-min))))
3141 ((> edebug-previous-value (point-max))
3142 (setq point-info (format " (> Point max: %s)" (point-max))))
3143 ((invisible-p edebug-previous-value)
3144 (setq point-info (format " (invisible)"))))
3145 (goto-char edebug-previous-value)
3146 (message "Current buffer: %s Point: %s%s"
3147 (current-buffer) edebug-previous-value point-info)
3148 (sit-for arg)
3149 (edebug-pop-to-buffer edebug-buffer (car edebug-window-data))))))
3150
3116 3151
3117;; Joe Wells, here is a start at your idea of adding a buffer to the internal 3152;; Joe Wells, here is a start at your idea of adding a buffer to the internal
3118;; display list. Still need to use this list in edebug--display. 3153;; display list. Still need to use this list in edebug--display.
@@ -3743,7 +3778,8 @@ Return the result of the last expression."
3743 (if edebug-unwrap-results 3778 (if edebug-unwrap-results
3744 (setq previous-value 3779 (setq previous-value
3745 (edebug-unwrap* previous-value))) 3780 (edebug-unwrap* previous-value)))
3746 (setq edebug-previous-result 3781 (setq edebug-previous-value previous-value
3782 edebug-previous-result
3747 (concat "Result: " 3783 (concat "Result: "
3748 (edebug-safe-prin1-to-string previous-value) 3784 (edebug-safe-prin1-to-string previous-value)
3749 (eval-expression-print-format previous-value)))) 3785 (eval-expression-print-format previous-value))))
@@ -3785,6 +3821,8 @@ this is the prefix key.)"
3785 (values--store-value value) 3821 (values--store-value value)
3786 (concat (edebug-safe-prin1-to-string value) 3822 (concat (edebug-safe-prin1-to-string value)
3787 (eval-expression-print-format value))))) 3823 (eval-expression-print-format value)))))
3824 ;; Provide a defined previous value also in case of an error.
3825 (setq edebug-previous-value (if errored nil value))
3788 (cond 3826 (cond
3789 (errored 3827 (errored
3790 (message "Error: %s" errored)) 3828 (message "Error: %s" errored))
@@ -3901,9 +3939,9 @@ be installed in `emacs-lisp-mode-map'.")
3901 3939
3902 ;; views 3940 ;; views
3903 "w" #'edebug-where 3941 "w" #'edebug-where
3904 "v" #'edebug-view-outside ; maybe obsolete?? 3942 "v" #'edebug-view-outside
3905 "p" #'edebug-bounce-point 3943 "p" #'edebug-bounce-point
3906 "P" #'edebug-view-outside ; same as v 3944 "P" #'edebug-bounce-to-previous-value
3907 "W" #'edebug-toggle-save-windows 3945 "W" #'edebug-toggle-save-windows
3908 3946
3909 ;; misc 3947 ;; misc
@@ -4517,6 +4555,7 @@ It is removed when you hit any char."
4517 ("Views" 4555 ("Views"
4518 ["Where am I?" edebug-where t] 4556 ["Where am I?" edebug-where t]
4519 ["Bounce to Current Point" edebug-bounce-point t] 4557 ["Bounce to Current Point" edebug-bounce-point t]
4558 ["Bounce to Previous Value" edebug-bounce-to-previous-value t]
4520 ["View Outside Windows" edebug-view-outside t] 4559 ["View Outside Windows" edebug-view-outside t]
4521 ["Previous Result" edebug-previous-result t] 4560 ["Previous Result" edebug-previous-result t]
4522 ["Show Backtrace" edebug-pop-to-backtrace t] 4561 ["Show Backtrace" edebug-pop-to-backtrace t]
diff --git a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
index 24981bb63cf..4e63732554f 100644
--- a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
+++ b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
@@ -126,6 +126,16 @@
126 !start!(with-current-buffer (get-buffer-create "*edebug-test-code-buffer*") 126 !start!(with-current-buffer (get-buffer-create "*edebug-test-code-buffer*")
127 !body!(format "current-buffer: %s" (current-buffer)))) 127 !body!(format "current-buffer: %s" (current-buffer))))
128 128
129(defun edebug-test-code-bounce-point ()
130 !start!(with-current-buffer (get-buffer-create "*edebug-test-code-buffer*")
131 (erase-buffer)
132 (insert "123\n567\n9ab\n")
133 (narrow-to-region 5 9)
134 (goto-char 6)!goto-char!
135 (push-mark 1)!push-mark!
136 (set-mark nil)!clear-mark!
137 (+ 1)!1! (+ 6)!6! (+ 10)!10!))
138
129(defun edebug-test-code-use-destructuring-bind () 139(defun edebug-test-code-use-destructuring-bind ()
130 (let ((two 2) (three 3)) 140 (let ((two 2) (three 3))
131 (cl-destructuring-bind (x . y) (cons two three) (+ x!x! y!y!)))) 141 (cl-destructuring-bind (x . y) (cons two three) (+ x!x! y!y!))))
diff --git a/test/lisp/emacs-lisp/edebug-tests.el b/test/lisp/emacs-lisp/edebug-tests.el
index 7daacea7925..4550f25f798 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -302,6 +302,29 @@ Then clear edebug-tests' saved messages."
302 edebug-tests-messages)) 302 edebug-tests-messages))
303 (setq edebug-tests-messages "")) 303 (setq edebug-tests-messages ""))
304 304
305(defvar edebug-tests-bounce-outside-buffer nil
306 "Outside buffer observed while bouncing.")
307(defvar edebug-tests-bounce-outside-point nil
308 "Outside point observed while bouncing.")
309(defvar edebug-tests-bounce-outside-mark nil
310 "Outside mark observed while bouncing.")
311
312(defun edebug-tests-bounce-record-outside-environment (&rest _)
313 "Record outside buffer, point, and mark while bouncing."
314 (setq edebug-tests-bounce-outside-buffer (current-buffer)
315 edebug-tests-bounce-outside-point (point)
316 edebug-tests-bounce-outside-mark (mark)))
317
318(defun edebug-tests-should-have-bounced-to (buffer-or-name point mark message)
319 "Require that a previous bounce bounced to BUFFER-OR-NAME, POINT, and MARK.
320Ensure that the message generated by that bounce equals MESSAGE."
321 (should (equal edebug-tests-bounce-outside-buffer
322 (get-buffer buffer-or-name)))
323 (should (equal edebug-tests-bounce-outside-point point))
324 (should (equal edebug-tests-bounce-outside-mark mark))
325 (should (string-match-p (concat (regexp-quote message) "$")
326 edebug-tests-messages)))
327
305(defun edebug-tests-locate-def (def-name) 328(defun edebug-tests-locate-def (def-name)
306 "Search for a definition of DEF-NAME from the start of the current buffer. 329 "Search for a definition of DEF-NAME from the start of the current buffer.
307Place point at the end of DEF-NAME in the buffer." 330Place point at the end of DEF-NAME in the buffer."
@@ -419,9 +442,9 @@ test and possibly others should be updated."
419 (verify-keybinding "\C-x\C-e" 'edebug-eval-last-sexp) 442 (verify-keybinding "\C-x\C-e" 'edebug-eval-last-sexp)
420 (verify-keybinding "E" 'edebug-visit-eval-list) 443 (verify-keybinding "E" 'edebug-visit-eval-list)
421 (verify-keybinding "w" 'edebug-where) 444 (verify-keybinding "w" 'edebug-where)
422 (verify-keybinding "v" 'edebug-view-outside) ;; maybe obsolete?? 445 (verify-keybinding "v" 'edebug-view-outside)
423 (verify-keybinding "p" 'edebug-bounce-point) 446 (verify-keybinding "p" 'edebug-bounce-point)
424 (verify-keybinding "P" 'edebug-view-outside) ;; same as v 447 (verify-keybinding "P" 'edebug-bounce-to-previous-value)
425 (verify-keybinding "W" 'edebug-toggle-save-windows) 448 (verify-keybinding "W" 'edebug-toggle-save-windows)
426 (verify-keybinding "?" 'edebug-help) 449 (verify-keybinding "?" 'edebug-help)
427 (verify-keybinding "d" 'edebug-pop-to-backtrace) 450 (verify-keybinding "d" 'edebug-pop-to-backtrace)
@@ -703,6 +726,95 @@ test and possibly others should be updated."
703 edebug-tests-messages)) 726 edebug-tests-messages))
704 "g" (should (equal edebug-tests-@-result '(0 1)))))) 727 "g" (should (equal edebug-tests-@-result '(0 1))))))
705 728
729(ert-deftest edebug-tests-bounce-point ()
730 "Edebug can bounce point."
731 (unwind-protect
732 (cl-letf* (((symbol-function 'sit-for)
733 #'edebug-tests-bounce-record-outside-environment))
734 (edebug-tests-with-normal-env
735 (edebug-tests-setup-@ "bounce-point" nil t)
736 (edebug-tests-run-kbd-macro
737 "@" (edebug-tests-should-be-at
738 "bounce-point" "start")
739 (goto-char (edebug-tests-get-stop-point "bounce-point" "goto-char"))
740 "h" (edebug-tests-should-be-at
741 "bounce-point" "goto-char")
742 "p" (edebug-tests-should-have-bounced-to
743 "*edebug-test-code-buffer*" 6 nil
744 "Current buffer: *edebug-test-code-buffer* Point: 6 Mark: <not set>")
745 "SPC SPC" (edebug-tests-should-be-at
746 "bounce-point" "push-mark")
747 "p" (edebug-tests-should-have-bounced-to
748 "*edebug-test-code-buffer*" 6 1
749 "Current buffer: *edebug-test-code-buffer* Point: 6 Mark: 1")
750 "g")))
751 (when (get-buffer "*edebug-test-code-buffer*")
752 (kill-buffer "*edebug-test-code-buffer*"))))
753
754(ert-deftest edebug-tests-bounce-to-previous-value ()
755 "Edebug can bounce to previous value."
756 (unwind-protect
757 (cl-letf* (((symbol-function 'sit-for)
758 #'edebug-tests-bounce-record-outside-environment))
759 (edebug-tests-with-normal-env
760 (edebug-tests-setup-@ "bounce-point" nil t)
761 (edebug-tests-run-kbd-macro
762 "@" (edebug-tests-should-be-at
763 "bounce-point" "start")
764 (goto-char (edebug-tests-get-stop-point "bounce-point" "clear-mark"))
765 "h" (edebug-tests-should-be-at
766 "bounce-point" "clear-mark")
767 ;; Bounce to previous values seen while single-stepping.
768 "SPC SPC" (edebug-tests-should-be-at "bounce-point" "1")
769 "P" (edebug-tests-should-have-bounced-to
770 "*edebug-test-code-buffer*" 5 nil
771 "Current buffer: *edebug-test-code-buffer* Point: 1 (< Point min: 5)")
772 "SPC SPC" (edebug-tests-should-be-at "bounce-point" "6")
773 "P" (edebug-tests-should-have-bounced-to
774 "*edebug-test-code-buffer*" 6 nil
775 "Current buffer: *edebug-test-code-buffer* Point: 6")
776 "SPC SPC" (edebug-tests-should-be-at "bounce-point" "10")
777 "P" (edebug-tests-should-have-bounced-to
778 "*edebug-test-code-buffer*" 9 nil
779 "Current buffer: *edebug-test-code-buffer* Point: 10 (> Point max: 9)")
780 ;; Bounce to previous value obtained through evaluation.
781 "e 7 RET"
782 "P" (edebug-tests-should-have-bounced-to
783 "*edebug-test-code-buffer*" 7 nil
784 "Current buffer: *edebug-test-code-buffer* Point: 7")
785 "g")))
786 (when (get-buffer "*edebug-test-code-buffer*")
787 (kill-buffer "*edebug-test-code-buffer*"))))
788
789(ert-deftest edebug-tests-bounce-to-previous-non-position ()
790 "Edebug does not bounce to previous non-position."
791 (edebug-tests-with-normal-env
792 (edebug-tests-setup-@ "fac" '(1) t)
793 (let* ((debug-on-error nil)
794 (edebug-on-error nil)
795 error-message
796 (command-error-function (lambda (&rest args)
797 (setq error-message (cadar args)))))
798 (edebug-tests-run-kbd-macro
799 "@" (edebug-tests-should-be-at "fac" "start")
800 ;; Bounce to previous non-position seen while single-stepping.
801 "SPC SPC SPC"
802 (edebug-tests-should-match-result-in-messages "t")
803 "P" (should (string-match-p "Previous value not a number or marker"
804 error-message))
805 ;; The error stopped the keyboard macro. Start it again.
806 (should-not executing-kbd-macro)
807 (setq executing-kbd-macro t
808 error-message nil)
809 ;; Bounce to previous non-position obtained through evaluation.
810 "e nil RET"
811 "P" (should (string-match-p "Previous value not a number or marker"
812 error-message))
813 (should-not executing-kbd-macro)
814 (setq executing-kbd-macro t
815 error-message nil)
816 "g"))))
817
706(ert-deftest edebug-tests-step-into-function () 818(ert-deftest edebug-tests-step-into-function ()
707 "Edebug can step into a function." 819 "Edebug can step into a function."
708 (edebug-tests-with-normal-env 820 (edebug-tests-with-normal-env
@@ -838,20 +950,23 @@ test and possibly others should be updated."
838 950
839(ert-deftest edebug-tests-evaluation-of-current-buffer-bug-19611 () 951(ert-deftest edebug-tests-evaluation-of-current-buffer-bug-19611 ()
840 "Edebug can evaluate `current-buffer' in correct context. (Bug#19611)." 952 "Edebug can evaluate `current-buffer' in correct context. (Bug#19611)."
841 (edebug-tests-with-normal-env 953 (unwind-protect
842 (edebug-tests-setup-@ "current-buffer" nil t) 954 (edebug-tests-with-normal-env
843 (edebug-tests-run-kbd-macro 955 (edebug-tests-setup-@ "current-buffer" nil t)
844 "@" (edebug-tests-should-be-at 956 (edebug-tests-run-kbd-macro
845 "current-buffer" "start") 957 "@" (edebug-tests-should-be-at
846 "SPC SPC SPC" (edebug-tests-should-be-at 958 "current-buffer" "start")
847 "current-buffer" "body") 959 "SPC SPC SPC" (edebug-tests-should-be-at
848 "e (current-buffer) RET" 960 "current-buffer" "body")
849 ;; Edebug just prints the result without "Result:" 961 "e (current-buffer) RET"
850 (should (string-match-p 962 ;; Edebug just prints the result without "Result:"
851 (regexp-quote "*edebug-test-code-buffer*") 963 (should (string-match-p
852 edebug-tests-messages)) 964 (regexp-quote "*edebug-test-code-buffer*")
853 "g" (should (equal edebug-tests-@-result 965 edebug-tests-messages))
854 "current-buffer: *edebug-test-code-buffer*"))))) 966 "g" (should (equal edebug-tests-@-result
967 "current-buffer: *edebug-test-code-buffer*"))))
968 (when (get-buffer "*edebug-test-code-buffer*")
969 (kill-buffer "*edebug-test-code-buffer*"))))
855 970
856(ert-deftest edebug-tests-trivial-backquote () 971(ert-deftest edebug-tests-trivial-backquote ()
857 "Edebug can instrument a trivial backquote expression (Bug#23651)." 972 "Edebug can instrument a trivial backquote expression (Bug#23651)."