;;; debug.el --- debuggers and related commands for Emacs -*- lexical-binding: t -*-
-;; Copyright (C) 1985-1986, 1994, 2001-2013 Free Software Foundation,
+;; Copyright (C) 1985-1986, 1994, 2001-2015 Free Software Foundation,
;; Inc.
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
;; Keywords: lisp, tools, maint
;; This file is part of GNU Emacs.
(window-resize
debugger-window
(- debugger-previous-window-height
- (window-total-size debugger-window)))
+ (window-total-height debugger-window)))
(error nil)))
(setq debugger-previous-window debugger-window))
(debugger-mode)
(eq (window-buffer debugger-window) debugger-buffer))
;; Record height of debugger window.
(setq debugger-previous-window-height
- (window-total-size debugger-window)))
+ (window-total-height debugger-window)))
(if debugger-will-be-back
;; Restore previous window configuration (Bug#12623).
(set-window-configuration window-configuration)
(forward-line 1)
(while (progn
(forward-char 2)
- (if (= (following-char) ?\()
- (forward-sexp 1)
- (forward-sexp 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 " *;;;")
(progn ,@body)
(setq debugger-outer-match-data (match-data)))))
+(defun debugger--backtrace-base ()
+ "Return the function name that marks the top of the backtrace.
+See `backtrace-frame'."
+ (cond ((eq 'debug--implement-debug-on-entry
+ (cadr (backtrace-frame 1 'debug)))
+ 'debug--implement-debug-on-entry)
+ (t 'debug)))
+
(defun debugger-eval-expression (exp &optional nframe)
"Eval an expression, in an environment like that outside the debugger.
The environment used is the one when entering the activation frame at point."
(let ((nframe (or nframe
(condition-case nil (1+ (debugger-frame-number 'skip-base))
(error 0)))) ;; If on first line.
- (base (if (eq 'debug--implement-debug-on-entry
- (cadr (backtrace-frame 1 'debug)))
- 'debug--implement-debug-on-entry 'debug)))
+ (base (debugger--backtrace-base)))
(debugger-env-macro
(let ((val (backtrace-eval exp nframe base)))
(prog1
(prin1 val t)
(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 " = ")
+ (prin1 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))))
+
\f
(defvar debugger-mode-map
(let ((map (make-keymap))
(define-key map "h" 'describe-mode)
(define-key map "q" 'top-level)
(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)
(not (special-form-p symbol))))
t nil nil (symbol-name fn)))
(list (if (equal val "") fn (intern val)))))
- (advice-add function :before #'debug--implement-debug-on-entry)
+ (advice-add function :before #'debug--implement-debug-on-entry
+ '((depth . -100)))
function)
(defun debug--function-list ()
(progn
(advice-remove function #'debug--implement-debug-on-entry)
function)
- (message "Cancelling debug-on-entry for all functions")
+ (message "Canceling debug-on-entry for all functions")
(mapcar #'cancel-debug-on-entry (debug--function-list))))
(defun debugger-list-functions ()