summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/backtrace.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp/backtrace.el')
-rw-r--r--lisp/emacs-lisp/backtrace.el52
1 files changed, 48 insertions, 4 deletions
diff --git a/lisp/emacs-lisp/backtrace.el b/lisp/emacs-lisp/backtrace.el
index b6ca2890764..5169c305035 100644
--- a/lisp/emacs-lisp/backtrace.el
+++ b/lisp/emacs-lisp/backtrace.el
@@ -66,7 +66,14 @@ abbreviate the forms it prints."
(cl-defstruct
(backtrace-frame
(:constructor backtrace-make-frame))
- evald fun args flags locals buffer pos)
+ evald ; Non-nil if argument evaluation is complete.
+ fun ; The function called/to call in this frame.
+ args ; Either evaluated or unevaluated arguments to the function.
+ flags ; A plist, possible properties are :debug-on-exit and :source-available.
+ locals ; An alist containing variable names and values.
+ buffer ; If non-nil, the buffer in use by eval-buffer or eval-region.
+ pos ; The position in the buffer.
+ )
(cl-defun backtrace-get-frames
(&optional base &key (constructor #'backtrace-make-frame))
@@ -181,6 +188,15 @@ This is commonly used to recompute `backtrace-frames'.")
(defvar-local backtrace-print-function #'cl-prin1
"Function used to print values in the current Backtrace buffer.")
+(defvar-local backtrace-goto-source-functions nil
+ "Abnormal hook used to jump to the source code for the current frame.
+Each hook function is called with no argument, and should return
+non-nil if it is able to switch to the buffer containing the
+source code. Execution of the hook will stop if one of the
+functions returns non-nil. When adding a function to this hook,
+you should also set the :source-available flag for the backtrace
+frames where the source code location is known.")
+
(defvar backtrace-mode-map
(let ((map (copy-keymap special-mode-map)))
(set-keymap-parent map button-buffer-map)
@@ -188,6 +204,7 @@ This is commonly used to recompute `backtrace-frames'.")
(define-key map "p" 'backtrace-backward-frame)
(define-key map "v" 'backtrace-toggle-locals)
(define-key map "#" 'backtrace-toggle-print-circle)
+ (define-key map "s" 'backtrace-goto-source)
(define-key map "\C-m" 'backtrace-help-follow-symbol)
(define-key map "+" 'backtrace-pretty-print)
(define-key map "-" 'backtrace-collapse)
@@ -212,6 +229,12 @@ This is commonly used to recompute `backtrace-frames'.")
:help "Use line breaks and indentation to make a form more readable"]
["Collapse to Single Line" backtrace-collapse]
"--"
+ ["Go to Source" backtrace-goto-source
+ :active (and (backtrace-get-index)
+ (plist-get (backtrace-frame-flags
+ (nth (backtrace-get-index) backtrace-frames))
+ :source-available))
+ :help "Show the source code for the current frame"]
["Help for Symbol" backtrace-help-follow-symbol
:help "Show help for symbol at point"]
["Describe Backtrace Mode" describe-mode
@@ -219,6 +242,9 @@ This is commonly used to recompute `backtrace-frames'.")
map)
"Local keymap for `backtrace-mode' buffers.")
+(defconst backtrace--flags-width 2
+ "Width in characters of the flags for a backtrace frame.")
+
;;; Navigation and Text Properties
;; This mode uses the following text properties:
@@ -580,6 +606,20 @@ content of the sexp."
'(backtrace-section backtrace-index backtrace-view
backtrace-form))))
+(defun backtrace-goto-source ()
+ "If its location is known, jump to the source code for the frame at point."
+ (interactive)
+ (let* ((index (or (backtrace-get-index) (user-error "Not in a stack frame")))
+ (frame (nth index backtrace-frames))
+ (source-available (plist-get (backtrace-frame-flags frame)
+ :source-available)))
+ (unless (and source-available
+ (catch 'done
+ (dolist (func backtrace-goto-source-functions)
+ (when (funcall func)
+ (throw 'done t)))))
+ (user-error "Source code location not known"))))
+
(defun backtrace-help-follow-symbol (&optional pos)
"Follow cross-reference at POS, defaulting to point.
For the cross-reference format, see `help-make-xrefs'."
@@ -681,8 +721,12 @@ property for use by navigation."
(defun backtrace--print-flags (frame view)
"Print the flags of a backtrace FRAME if enabled in VIEW."
(let ((beg (point))
- (flag (plist-get (backtrace-frame-flags frame) :debug-on-exit)))
- (insert (if (and (plist-get view :show-flags) flag) "* " " "))
+ (flag (plist-get (backtrace-frame-flags frame) :debug-on-exit))
+ (source (plist-get (backtrace-frame-flags frame) :source-available)))
+ (when (plist-get view :show-flags)
+ (when source (insert ">"))
+ (when flag (insert "*")))
+ (insert (make-string (- backtrace--flags-width (- (point) beg)) ?\s))
(put-text-property beg (point) 'backtrace-section 'func)))
(defun backtrace--print-func-and-args (frame _view)
@@ -770,7 +814,7 @@ Fall back to `prin1' if there is an error."
(let ((props (backtrace-get-text-properties begin))
(inhibit-read-only t)
(standard-output (current-buffer)))
- (delete-char 2)
+ (delete-char backtrace--flags-width)
(backtrace--print-flags (nth (backtrace-get-index) backtrace-frames)
view)
(add-text-properties begin (point) props))))))