mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 06:20:55 -08:00
Add backtrace-mode and use it in the debugger, ERT and Edebug
* doc/lispref/debugging.texi (Using Debugger): Remove explanation of backtrace buffer. Refer to new node. (Backtraces): New node. (Debugger Commands): Refer to new node. Remove 'v'. * doc/lispref/edebug.texi (Edebug Misc): Refer to new node. * doc/misc/ert.texi (Running Tests Interactively): Refer to new node. * lisp/emacs-lisp-backtrace.el: New file. * test/lisp/emacs-lisp/backtrace-tests.el: New file. * lisp/emacs-lisp/debug.el: (debugger-buffer-state): New cl-defstruct. (debugger--restore-buffer-state): New function. (debug): Use a debugger-buffer-state object to save and restore buffer state. Fix bug#15749 by leaving an unused buffer in debugger-mode, empty, instead of in fundamental-mode, and then when reusing a buffer, not calling debugger-mode if the buffer is already in debugger-mode. (debugger-insert-backtrace): Remove. (debugger-setup-buffer): Use backtrace-mode. (debugger--insert-header): New function. (debugger-continue, debugger-return-value): Change check for flags to use backtrace-frames. (debugger-frame-number): Determine backtrace frame number from backtrace-frames. (debugger--locals-visible-p, debugger--insert-locals) (debugger--show-locals, debugger--hide-locals) (debugger-toggle-locals): Remove. (debugger-mode-map): Make a child of backtrace-mode-map. Move navigation commands to backtrace-mode-map. Bind 'q' to debugger-quit instead of top-level. Make Help Follow menu item call backtrace-help-follow-symbol. (debugger-mode): Derive from backtrace-mode. (debug-help-follow): Remove. Move body of this function to 'backtrace-help-follow-symbol' in backtrace.el. (debugger-quit): New function. * lisp/emacs-lisp/edebug.el (edebug-unwrap-results): Remove warning in docstring about circular results. (edebug-unwrap): Use pcase. (edebug-unwrap1): New function to unwrap circular objects. (edebug-unwrap*): Use it. (edebug--frame): New cl-defstruct. (edebug-backtrace): Call the buffer *Edebug Backtrace* and use backtrace-mode. Get the frames from edebug--backtrace-frames. (edebug--backtrace-frames, edebug--unwrap-and-add-info) (edebug--symbol-not-prefixed-p): New functions. * lisp/emacs-lisp/lisp-mode.el (lisp-el-font-lock-keywords-for-backtraces) (lisp-el-font-lock-keywords-for-backtraces-1) (lisp-el-font-lock-keywords-for-backtraces-2): New constants. * lisp/emacs-lisp/ert.el (ert--print-backtrace): Remove. (ert--run-test-debugger): Use backtrace-get-frames. (ert-run-tests-batch): Use backtrace-to-string. (ert-results-pop-to-backtrace-for-test-at-point): Use backtrace-mode. (ert--insert-backtrace-header): New function. * tests/lisp/emacs-lisp/ert-tests.el (ert-test--which-file): Use backtrace-frame slot accessor.
This commit is contained in:
parent
8a7620955b
commit
e09120d686
11 changed files with 1260 additions and 350 deletions
|
|
@ -28,6 +28,7 @@
|
|||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'backtrace)
|
||||
(require 'button)
|
||||
|
||||
(defgroup debugger nil
|
||||
|
|
@ -133,6 +134,25 @@ where CAUSE can be:
|
|||
- exit: called because of exit of a flagged function.
|
||||
- error: called because of `debug-on-error'.")
|
||||
|
||||
(cl-defstruct (debugger--buffer-state
|
||||
(:constructor debugger--save-buffer-state
|
||||
(&aux (mode major-mode)
|
||||
(header backtrace-insert-header-function)
|
||||
(frames backtrace-frames)
|
||||
(content (buffer-string))
|
||||
(pos (point)))))
|
||||
mode header frames content pos)
|
||||
|
||||
(defun debugger--restore-buffer-state (state)
|
||||
(unless (derived-mode-p (debugger--buffer-state-mode state))
|
||||
(funcall (debugger--buffer-state-mode state)))
|
||||
(setq backtrace-insert-header-function (debugger--buffer-state-header state)
|
||||
backtrace-frames (debugger--buffer-state-frames state))
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(insert (debugger--buffer-state-content state)))
|
||||
(goto-char (debugger--buffer-state-pos state)))
|
||||
|
||||
;;;###autoload
|
||||
(setq debugger 'debug)
|
||||
;;;###autoload
|
||||
|
|
@ -174,7 +194,7 @@ first will be printed into the backtrace buffer."
|
|||
(debugger-previous-state
|
||||
(if (get-buffer "*Backtrace*")
|
||||
(with-current-buffer (get-buffer "*Backtrace*")
|
||||
(list major-mode (buffer-string)))))
|
||||
(debugger--save-buffer-state))))
|
||||
(debugger-args args)
|
||||
(debugger-buffer (get-buffer-create "*Backtrace*"))
|
||||
(debugger-old-buffer (current-buffer))
|
||||
|
|
@ -236,7 +256,8 @@ first will be printed into the backtrace buffer."
|
|||
(window-total-height debugger-window)))
|
||||
(error nil)))
|
||||
(setq debugger-previous-window debugger-window))
|
||||
(debugger-mode)
|
||||
(unless (derived-mode-p 'debugger-mode)
|
||||
(debugger-mode))
|
||||
(debugger-setup-buffer debugger-args)
|
||||
(when noninteractive
|
||||
;; If the backtrace is long, save the beginning
|
||||
|
|
@ -280,15 +301,14 @@ first will be printed into the backtrace buffer."
|
|||
(setq debugger-previous-window nil))
|
||||
;; Restore previous state of debugger-buffer in case we were
|
||||
;; in a recursive invocation of the debugger, otherwise just
|
||||
;; erase the buffer and put it into fundamental mode.
|
||||
;; erase the buffer.
|
||||
(when (buffer-live-p debugger-buffer)
|
||||
(with-current-buffer debugger-buffer
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(if (null debugger-previous-state)
|
||||
(fundamental-mode)
|
||||
(insert (nth 1 debugger-previous-state))
|
||||
(funcall (nth 0 debugger-previous-state))))))
|
||||
(if debugger-previous-state
|
||||
(debugger--restore-buffer-state debugger-previous-state)
|
||||
(setq backtrace-insert-header-function nil)
|
||||
(setq backtrace-frames nil)
|
||||
(backtrace-print))))
|
||||
(with-timeout-unsuspend debugger-with-timeout-suspend)
|
||||
(set-match-data debugger-outer-match-data)))
|
||||
(setq debug-on-next-call debugger-step-after-exit)
|
||||
|
|
@ -301,112 +321,80 @@ first will be printed into the backtrace buffer."
|
|||
(message "Error in debug printer: %S" err)
|
||||
(prin1 obj stream))))
|
||||
|
||||
(defun debugger-insert-backtrace (frames do-xrefs)
|
||||
"Format and insert the backtrace FRAMES at point.
|
||||
Make functions into cross-reference buttons if DO-XREFS is non-nil."
|
||||
(let ((standard-output (current-buffer))
|
||||
(eval-buffers eval-buffer-list))
|
||||
(require 'help-mode) ; Define `help-function-def' button type.
|
||||
(pcase-dolist (`(,evald ,fun ,args ,flags) frames)
|
||||
(insert (if (plist-get flags :debug-on-exit)
|
||||
"* " " "))
|
||||
(let ((fun-file (and do-xrefs (symbol-file fun 'defun)))
|
||||
(fun-pt (point)))
|
||||
(cond
|
||||
((and evald (not debugger-stack-frame-as-list))
|
||||
(debugger--print fun)
|
||||
(if args (debugger--print args) (princ "()")))
|
||||
(t
|
||||
(debugger--print (cons fun args))
|
||||
(cl-incf fun-pt)))
|
||||
(when fun-file
|
||||
(make-text-button fun-pt (+ fun-pt (length (symbol-name fun)))
|
||||
:type 'help-function-def
|
||||
'help-args (list fun fun-file))))
|
||||
;; After any frame that uses eval-buffer, insert a line that
|
||||
;; states the buffer position it's reading at.
|
||||
(when (and eval-buffers (memq fun '(eval-buffer eval-region)))
|
||||
(insert (format " ; Reading at buffer position %d"
|
||||
;; This will get the wrong result if there are
|
||||
;; two nested eval-region calls for the same
|
||||
;; buffer. That's not a very useful case.
|
||||
(with-current-buffer (pop eval-buffers)
|
||||
(point)))))
|
||||
(insert "\n"))))
|
||||
|
||||
(defun debugger-setup-buffer (args)
|
||||
"Initialize the `*Backtrace*' buffer for entry to the debugger.
|
||||
That buffer should be current already."
|
||||
(setq buffer-read-only nil)
|
||||
(erase-buffer)
|
||||
(set-buffer-multibyte t) ;Why was it nil ? -stef
|
||||
(setq buffer-undo-list t)
|
||||
That buffer should be current already and in debugger-mode."
|
||||
(setq backtrace-frames (nthcdr
|
||||
;; Remove debug--implement-debug-on-entry and the
|
||||
;; advice's `apply' frame.
|
||||
(if (eq (car args) 'debug) 3 1)
|
||||
(backtrace-get-frames 'debug)))
|
||||
(when (eq (car-safe args) 'exit)
|
||||
(setq debugger-value (nth 1 args))
|
||||
(setf (cl-getf (backtrace-frame-flags (car backtrace-frames))
|
||||
:debug-on-exit)
|
||||
nil))
|
||||
|
||||
(setq backtrace-view '(:do-xrefs t :show-flags t)
|
||||
backtrace-insert-header-function (lambda ()
|
||||
(debugger--insert-header args))
|
||||
backtrace-print-function debugger-print-function)
|
||||
(backtrace-print)
|
||||
;; Place point on "stack frame 0" (bug#15101).
|
||||
(goto-char (point-min))
|
||||
(search-forward ":" (line-end-position) t)
|
||||
(when (and (< (point) (line-end-position))
|
||||
(= (char-after) ?\s))
|
||||
(forward-char)))
|
||||
|
||||
(defun debugger--insert-header (args)
|
||||
"Insert the header for the debugger's Backtrace buffer.
|
||||
Include the reason for debugger entry from ARGS."
|
||||
(insert "Debugger entered")
|
||||
(let ((frames (nthcdr
|
||||
;; Remove debug--implement-debug-on-entry and the
|
||||
;; advice's `apply' frame.
|
||||
(if (eq (car args) 'debug) 3 1)
|
||||
(backtrace-frames 'debug)))
|
||||
(print-escape-newlines t)
|
||||
(print-escape-control-characters t)
|
||||
;; If you increase print-level, add more depth in call_debugger.
|
||||
(print-level 8)
|
||||
(print-length 50)
|
||||
(pos (point)))
|
||||
(pcase (car args)
|
||||
;; lambda is for debug-on-call when a function call is next.
|
||||
;; debug is for debug-on-entry function called.
|
||||
((or `lambda `debug)
|
||||
(insert "--entering a function:\n")
|
||||
(setq pos (1- (point))))
|
||||
;; Exiting a function.
|
||||
(`exit
|
||||
(insert "--returning value: ")
|
||||
(setq pos (point))
|
||||
(setq debugger-value (nth 1 args))
|
||||
(debugger--print debugger-value (current-buffer))
|
||||
(setf (cl-getf (nth 3 (car frames)) :debug-on-exit) nil)
|
||||
(insert ?\n))
|
||||
;; Watchpoint triggered.
|
||||
((and `watchpoint (let `(,symbol ,newval . ,details) (cdr args)))
|
||||
(insert
|
||||
"--"
|
||||
(pcase details
|
||||
(`(makunbound nil) (format "making %s void" symbol))
|
||||
(`(makunbound ,buffer) (format "killing local value of %s in buffer %s"
|
||||
symbol buffer))
|
||||
(`(defvaralias ,_) (format "aliasing %s to %s" symbol newval))
|
||||
(`(let ,_) (format "let-binding %s to %S" symbol newval))
|
||||
(`(unlet ,_) (format "ending let-binding of %s" symbol))
|
||||
(`(set nil) (format "setting %s to %S" symbol newval))
|
||||
(`(set ,buffer) (format "setting %s in buffer %s to %S"
|
||||
symbol buffer newval))
|
||||
(_ (error "unrecognized watchpoint triggered %S" (cdr args))))
|
||||
": ")
|
||||
(setq pos (point))
|
||||
(insert ?\n))
|
||||
;; Debugger entered for an error.
|
||||
(`error
|
||||
(insert "--Lisp error: ")
|
||||
(setq pos (point))
|
||||
(debugger--print (nth 1 args) (current-buffer))
|
||||
(insert ?\n))
|
||||
;; debug-on-call, when the next thing is an eval.
|
||||
(`t
|
||||
(insert "--beginning evaluation of function call form:\n")
|
||||
(setq pos (1- (point))))
|
||||
;; User calls debug directly.
|
||||
(_
|
||||
(insert ": ")
|
||||
(setq pos (point))
|
||||
(debugger--print
|
||||
(if (eq (car args) 'nil)
|
||||
(cdr args) args)
|
||||
(current-buffer))
|
||||
(insert ?\n)))
|
||||
(debugger-insert-backtrace frames t)
|
||||
;; Place point on "stack frame 0" (bug#15101).
|
||||
(goto-char pos)))
|
||||
(pcase (car args)
|
||||
;; lambda is for debug-on-call when a function call is next.
|
||||
;; debug is for debug-on-entry function called.
|
||||
((or `lambda `debug)
|
||||
(insert "--entering a function:\n"))
|
||||
;; Exiting a function.
|
||||
(`exit
|
||||
(insert "--returning value: ")
|
||||
(insert (backtrace-print-to-string debugger-value))
|
||||
(insert ?\n))
|
||||
;; Watchpoint triggered.
|
||||
((and `watchpoint (let `(,symbol ,newval . ,details) (cdr args)))
|
||||
(insert
|
||||
"--"
|
||||
(pcase details
|
||||
(`(makunbound nil) (format "making %s void" symbol))
|
||||
(`(makunbound ,buffer) (format "killing local value of %s in buffer %s"
|
||||
symbol buffer))
|
||||
(`(defvaralias ,_) (format "aliasing %s to %s" symbol newval))
|
||||
(`(let ,_) (format "let-binding %s to %s" symbol
|
||||
(backtrace-print-to-string newval)))
|
||||
(`(unlet ,_) (format "ending let-binding of %s" symbol))
|
||||
(`(set nil) (format "setting %s to %s" symbol
|
||||
(backtrace-print-to-string newval)))
|
||||
(`(set ,buffer) (format "setting %s in buffer %s to %s"
|
||||
symbol buffer
|
||||
(backtrace-print-to-string newval)))
|
||||
(_ (error "unrecognized watchpoint triggered %S" (cdr args))))
|
||||
": ")
|
||||
(insert ?\n))
|
||||
;; Debugger entered for an error.
|
||||
(`error
|
||||
(insert "--Lisp error: ")
|
||||
(insert (backtrace-print-to-string (nth 1 args)))
|
||||
(insert ?\n))
|
||||
;; debug-on-call, when the next thing is an eval.
|
||||
(`t
|
||||
(insert "--beginning evaluation of function call form:\n"))
|
||||
;; User calls debug directly.
|
||||
(_
|
||||
(insert ": ")
|
||||
(insert (backtrace-print-to-string (if (eq (car args) 'nil)
|
||||
(cdr args) args)))
|
||||
(insert ?\n))))
|
||||
|
||||
|
||||
(defun debugger-step-through ()
|
||||
|
|
@ -426,12 +414,12 @@ Enter another debugger on next entry to eval, apply or funcall."
|
|||
(unless debugger-may-continue
|
||||
(error "Cannot continue"))
|
||||
(message "Continuing.")
|
||||
(save-excursion
|
||||
;; Check to see if we've flagged some frame for debug-on-exit, in which
|
||||
;; case we'll probably come back to the debugger soon.
|
||||
(goto-char (point-min))
|
||||
(if (re-search-forward "^\\* " nil t)
|
||||
(setq debugger-will-be-back t)))
|
||||
|
||||
;; Check to see if we've flagged some frame for debug-on-exit, in which
|
||||
;; case we'll probably come back to the debugger soon.
|
||||
(dolist (frame backtrace-frames)
|
||||
(when (plist-get (backtrace-frame-flags frame) :debug-on-exit)
|
||||
(setq debugger-will-be-back t)))
|
||||
(exit-recursive-edit))
|
||||
|
||||
(defun debugger-return-value (val)
|
||||
|
|
@ -446,12 +434,11 @@ will be used, such as in a debug on exit from a frame."
|
|||
(setq debugger-value val)
|
||||
(princ "Returning " t)
|
||||
(debugger--print debugger-value)
|
||||
(save-excursion
|
||||
;; Check to see if we've flagged some frame for debug-on-exit, in which
|
||||
;; case we'll probably come back to the debugger soon.
|
||||
(goto-char (point-min))
|
||||
(if (re-search-forward "^\\* " nil t)
|
||||
(setq debugger-will-be-back t)))
|
||||
(dolist (frame backtrace-frames)
|
||||
(when (plist-get (backtrace-frame-flags frame) :debug-on-exit)
|
||||
(setq debugger-will-be-back t)))
|
||||
(exit-recursive-edit))
|
||||
|
||||
(defun debugger-jump ()
|
||||
|
|
@ -473,63 +460,40 @@ removes itself from that hook."
|
|||
|
||||
(defun debugger-frame-number (&optional skip-base)
|
||||
"Return number of frames in backtrace before the one point points at."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(if (looking-at " *;;;\\|[a-z]")
|
||||
(error "This line is not a function call"))
|
||||
(let ((opoint (point))
|
||||
(count 0))
|
||||
(unless skip-base
|
||||
(let ((index (backtrace-get-index))
|
||||
(count 0))
|
||||
(unless index
|
||||
(error "This line is not a function call"))
|
||||
(unless skip-base
|
||||
(while (not (eq (cadr (backtrace-frame count)) 'debug))
|
||||
(setq count (1+ count)))
|
||||
;; Skip debug--implement-debug-on-entry frame.
|
||||
(when (eq 'debug--implement-debug-on-entry
|
||||
(cadr (backtrace-frame (1+ count))))
|
||||
(setq count (+ 2 count))))
|
||||
(goto-char (point-min))
|
||||
(when (looking-at "Debugger entered--\\(Lisp error\\|returning value\\):")
|
||||
(goto-char (match-end 0))
|
||||
(forward-sexp 1))
|
||||
(forward-line 1)
|
||||
(while (progn
|
||||
(forward-char 2)
|
||||
(cond ((debugger--locals-visible-p)
|
||||
(goto-char (next-single-char-property-change
|
||||
(point) 'locals-visible)))
|
||||
((= (following-char) ?\()
|
||||
(forward-sexp 1))
|
||||
(t
|
||||
(forward-sexp 2)))
|
||||
(forward-line 1)
|
||||
(<= (point) opoint))
|
||||
(if (looking-at " *;;;")
|
||||
(forward-line 1))
|
||||
(setq count (1+ count)))
|
||||
count)))
|
||||
(+ count index)))
|
||||
|
||||
(defun debugger-frame ()
|
||||
"Request entry to debugger when this frame exits.
|
||||
Applies to the frame whose line point is on in the backtrace."
|
||||
(interactive)
|
||||
(backtrace-debug (debugger-frame-number) t)
|
||||
(beginning-of-line)
|
||||
(if (= (following-char) ? )
|
||||
(let ((inhibit-read-only t))
|
||||
(delete-char 1)
|
||||
(insert ?*)))
|
||||
(beginning-of-line))
|
||||
(setf
|
||||
(cl-getf (backtrace-frame-flags (nth (backtrace-get-index) backtrace-frames))
|
||||
:debug-on-exit)
|
||||
t)
|
||||
(backtrace-update-flags))
|
||||
|
||||
(defun debugger-frame-clear ()
|
||||
"Do not enter debugger when this frame exits.
|
||||
Applies to the frame whose line point is on in the backtrace."
|
||||
(interactive)
|
||||
(backtrace-debug (debugger-frame-number) nil)
|
||||
(beginning-of-line)
|
||||
(if (= (following-char) ?*)
|
||||
(let ((inhibit-read-only t))
|
||||
(delete-char 1)
|
||||
(insert ? )))
|
||||
(beginning-of-line))
|
||||
(setf
|
||||
(cl-getf (backtrace-frame-flags (nth (backtrace-get-index) backtrace-frames))
|
||||
:debug-on-exit)
|
||||
nil)
|
||||
(backtrace-update-flags))
|
||||
|
||||
(defmacro debugger-env-macro (&rest body)
|
||||
"Run BODY in original environment."
|
||||
|
|
@ -564,69 +528,11 @@ The environment used is the one when entering the activation frame at point."
|
|||
(let ((str (eval-expression-print-format val)))
|
||||
(if str (princ str t))))))))
|
||||
|
||||
(defun debugger--locals-visible-p ()
|
||||
"Are the local variables of the current stack frame visible?"
|
||||
(save-excursion
|
||||
(move-to-column 2)
|
||||
(get-text-property (point) 'locals-visible)))
|
||||
|
||||
(defun debugger--insert-locals (locals)
|
||||
"Insert the local variables LOCALS at point."
|
||||
(cond ((null locals)
|
||||
(insert "\n [no locals]"))
|
||||
(t
|
||||
(let ((print-escape-newlines t))
|
||||
(dolist (s+v locals)
|
||||
(let ((symbol (car s+v))
|
||||
(value (cdr s+v)))
|
||||
(insert "\n ")
|
||||
(prin1 symbol (current-buffer))
|
||||
(insert " = ")
|
||||
(debugger--print value (current-buffer))))))))
|
||||
|
||||
(defun debugger--show-locals ()
|
||||
"For the frame at point, insert locals and add text properties."
|
||||
(let* ((nframe (1+ (debugger-frame-number 'skip-base)))
|
||||
(base (debugger--backtrace-base))
|
||||
(locals (backtrace--locals nframe base))
|
||||
(inhibit-read-only t))
|
||||
(save-excursion
|
||||
(let ((start (progn
|
||||
(move-to-column 2)
|
||||
(point))))
|
||||
(end-of-line)
|
||||
(debugger--insert-locals locals)
|
||||
(add-text-properties start (point) '(locals-visible t))))))
|
||||
|
||||
(defun debugger--hide-locals ()
|
||||
"Delete local variables and remove the text property."
|
||||
(let* ((col (current-column))
|
||||
(end (progn
|
||||
(move-to-column 2)
|
||||
(next-single-char-property-change (point) 'locals-visible)))
|
||||
(start (previous-single-char-property-change end 'locals-visible))
|
||||
(inhibit-read-only t))
|
||||
(remove-text-properties start end '(locals-visible))
|
||||
(goto-char start)
|
||||
(end-of-line)
|
||||
(delete-region (point) end)
|
||||
(move-to-column col)))
|
||||
|
||||
(defun debugger-toggle-locals ()
|
||||
"Show or hide local variables of the current stack frame."
|
||||
(interactive)
|
||||
(cond ((debugger--locals-visible-p)
|
||||
(debugger--hide-locals))
|
||||
(t
|
||||
(debugger--show-locals))))
|
||||
|
||||
|
||||
(defvar debugger-mode-map
|
||||
(let ((map (make-keymap))
|
||||
(menu-map (make-sparse-keymap)))
|
||||
(set-keymap-parent map button-buffer-map)
|
||||
(suppress-keymap map)
|
||||
(define-key map "-" 'negative-argument)
|
||||
(set-keymap-parent map backtrace-mode-map)
|
||||
(define-key map "b" 'debugger-frame)
|
||||
(define-key map "c" 'debugger-continue)
|
||||
(define-key map "j" 'debugger-jump)
|
||||
|
|
@ -634,24 +540,20 @@ The environment used is the one when entering the activation frame at point."
|
|||
(define-key map "u" 'debugger-frame-clear)
|
||||
(define-key map "d" 'debugger-step-through)
|
||||
(define-key map "l" 'debugger-list-functions)
|
||||
(define-key map "h" 'describe-mode)
|
||||
(define-key map "q" 'top-level)
|
||||
(define-key map "q" 'debugger-quit)
|
||||
(define-key map "e" 'debugger-eval-expression)
|
||||
(define-key map "v" 'debugger-toggle-locals) ; "v" is for "variables".
|
||||
(define-key map " " 'next-line)
|
||||
(define-key map "R" 'debugger-record-expression)
|
||||
(define-key map "\C-m" 'debug-help-follow)
|
||||
(define-key map [mouse-2] 'push-button)
|
||||
(define-key map [menu-bar debugger] (cons "Debugger" menu-map))
|
||||
(define-key menu-map [deb-top]
|
||||
'(menu-item "Quit" top-level
|
||||
'(menu-item "Quit" debugger-quit
|
||||
:help "Quit debugging and return to top level"))
|
||||
(define-key menu-map [deb-s0] '("--"))
|
||||
(define-key menu-map [deb-descr]
|
||||
'(menu-item "Describe Debugger Mode" describe-mode
|
||||
:help "Display documentation for debugger-mode"))
|
||||
(define-key menu-map [deb-hfol]
|
||||
'(menu-item "Help Follow" debug-help-follow
|
||||
'(menu-item "Help Follow" backtrace-help-follow-symbol
|
||||
:help "Follow cross-reference"))
|
||||
(define-key menu-map [deb-nxt]
|
||||
'(menu-item "Next Line" next-line
|
||||
|
|
@ -689,8 +591,8 @@ The environment used is the one when entering the activation frame at point."
|
|||
|
||||
(put 'debugger-mode 'mode-class 'special)
|
||||
|
||||
(define-derived-mode debugger-mode fundamental-mode "Debugger"
|
||||
"Mode for backtrace buffers, selected in debugger.
|
||||
(define-derived-mode debugger-mode backtrace-mode "Debugger"
|
||||
"Mode for debugging Emacs Lisp using a backtrace.
|
||||
\\<debugger-mode-map>
|
||||
A line starts with `*' if exiting that frame will call the debugger.
|
||||
Type \\[debugger-frame] or \\[debugger-frame-clear] to set or remove the `*'.
|
||||
|
|
@ -704,8 +606,6 @@ which functions will enter the debugger when called.
|
|||
|
||||
Complete list of commands:
|
||||
\\{debugger-mode-map}"
|
||||
(setq truncate-lines t)
|
||||
(set-syntax-table emacs-lisp-mode-syntax-table)
|
||||
(add-hook 'kill-buffer-hook
|
||||
(lambda () (if (> (recursion-depth) 0) (top-level)))
|
||||
nil t)
|
||||
|
|
@ -732,27 +632,6 @@ Complete list of commands:
|
|||
(buffer-substring (line-beginning-position 0)
|
||||
(line-end-position 0)))))
|
||||
|
||||
(defun debug-help-follow (&optional pos)
|
||||
"Follow cross-reference at POS, defaulting to point.
|
||||
|
||||
For the cross-reference format, see `help-make-xrefs'."
|
||||
(interactive "d")
|
||||
;; Ideally we'd just do (call-interactively 'help-follow) except that this
|
||||
;; assumes we're already in a *Help* buffer and reuses it, so it ends up
|
||||
;; incorrectly "reusing" the *Backtrace* buffer to show the help info.
|
||||
(unless pos
|
||||
(setq pos (point)))
|
||||
(unless (push-button pos)
|
||||
;; check if the symbol under point is a function or variable
|
||||
(let ((sym
|
||||
(intern
|
||||
(save-excursion
|
||||
(goto-char pos) (skip-syntax-backward "w_")
|
||||
(buffer-substring (point)
|
||||
(progn (skip-syntax-forward "w_")
|
||||
(point)))))))
|
||||
(when (or (boundp sym) (fboundp sym) (facep sym))
|
||||
(describe-symbol sym)))))
|
||||
|
||||
;; When you change this, you may also need to change the number of
|
||||
;; frames that the debugger skips.
|
||||
|
|
@ -853,6 +732,13 @@ To specify a nil argument interactively, exit with an empty minibuffer."
|
|||
;;(princ "be set to debug on entry, even if it is in the list.")
|
||||
)))))
|
||||
|
||||
(defun debugger-quit ()
|
||||
"Quit debugging and return to the top level."
|
||||
(interactive)
|
||||
(if (= (recursion-depth) 0)
|
||||
(quit-window)
|
||||
(top-level)))
|
||||
|
||||
(defun debug--implement-debug-watch (symbol newval op where)
|
||||
"Conditionally call the debugger.
|
||||
This function is called when SYMBOL's value is modified."
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue