;;; edebug.el --- a source-level debugger for Emacs Lisp -*- lexical-binding: t -*-
-;; Copyright (C) 1988-1995, 1997, 1999-2015 Free Software Foundation,
+;; Copyright (C) 1988-1995, 1997, 1999-2016 Free Software Foundation,
;; Inc.
;; Author: Daniel LaLiberte <liberte@holonexus.org>
You can use the command `edebug-all-defs' to toggle the value of this
variable. You may wish to make it local to each buffer with
-\(make-local-variable 'edebug-all-defs) in your
+\(make-local-variable \\='edebug-all-defs) in your
`emacs-lisp-mode-hook'."
:type 'boolean
:group 'edebug)
"If non-nil, an expression to test for at every stop point.
If the result is non-nil, then break. Errors are ignored."
:type 'sexp
+ :risky t
:group 'edebug)
(defcustom edebug-sit-for-seconds 1
:type 'number
:group 'edebug)
+(defcustom edebug-sit-on-break t
+ "Whether or not to pause for `edebug-sit-for-seconds' on reaching a break."
+ :type 'boolean
+ :group 'edebug
+ :version "25.2")
+
;;; Form spec utilities.
(defun get-edebug-spec (symbol)
(defun edebug-install-read-eval-functions ()
(interactive)
(add-function :around load-read-function #'edebug--read)
- (advice-add 'eval-defun :override 'edebug-eval-defun))
+ (advice-add 'eval-defun :override #'edebug-eval-defun))
(defun edebug-uninstall-read-eval-functions ()
(interactive)
(defun edebug-get-form-data-entry (pnt &optional end-point)
;; Find the edebug form data entry which is closest to PNT.
;; If END-POINT is supplied, match must be exact.
- ;; Return `nil' if none found.
+ ;; Return nil if none found.
(let ((rest edebug-form-data)
closest-entry
(closest-dist 999999)) ;; Need maxint here.
(t
(error "Bad spec: %s" specs)))))
+ ((eq 'vector spec)
+ (if (vectorp form)
+ ;; Special case: match a vector with the specs.
+ (let ((result (edebug-match-sublist
+ (edebug-new-cursor
+ form (cdr (edebug-top-offset cursor)))
+ (cdr specs))))
+ (edebug-move-cursor cursor)
+ (list (apply 'vector result)))
+ (edebug-no-match cursor "Expected" specs)))
+
((listp form)
(prog1
(list (edebug-match-sublist
specs))
(edebug-move-cursor cursor)))
- ((and (eq 'vector spec) (vectorp form))
- ;; Special case: match a vector with the specs.
- (let ((result (edebug-match-sublist
- (edebug-new-cursor
- form (cdr (edebug-top-offset cursor)))
- (cdr specs))))
- (edebug-move-cursor cursor)
- (list (apply 'vector result))))
-
(t (edebug-no-match cursor "Expected" specs)))
)))
;; Like body but body is wrapped in edebug-enter form.
;; The body is assumed to be executing inside of the function context.
;; Not to be used otherwise.
- (let ((edebug-inside-func t))
- (list (edebug-wrap-def-body (edebug-forms cursor)))))
+ (let* ((edebug-inside-func t)
+ (forms (edebug-forms cursor)))
+ ;; If there's no form, there's nothing to wrap!
+ ;; This happens to handle bug#20281, tho maybe a better fix would be to
+ ;; improve the `defun' spec.
+ (when forms
+ (list (edebug-wrap-def-body forms)))))
;;;; Edebug Form Specs
edebug-function)
))
- (setcdr edebug-window-data
- (edebug-adjust-window (cdr edebug-window-data)))
-
- ;; Test if there is input, not including keyboard macros.
- (if (input-pending-p)
- (progn
- (setq edebug-execution-mode 'step
- edebug-stop t)
- (edebug-stop)
- ;; (discard-input) ; is this unfriendly??
- ))
-
;; Make sure we bind those in the right buffer (bug#16410).
(let ((overlay-arrow-position overlay-arrow-position)
(overlay-arrow-string overlay-arrow-string))
(progn
;; Display result of previous evaluation.
(if (and edebug-break
+ edebug-sit-on-break
(not (eq edebug-execution-mode 'Continue-fast)))
(sit-for edebug-sit-for-seconds)) ; Show message.
(edebug-previous-result)))
((eq edebug-execution-mode 'Trace-fast)
(sit-for 0))) ; Force update and continue.
+ (when (input-pending-p)
+ (setq edebug-stop t)
+ (setq edebug-execution-mode 'step) ; for `edebug-overlay-arrow'
+ (edebug-stop))
+
+ (edebug-overlay-arrow)
+
(unwind-protect
(if (or edebug-stop
(memq edebug-execution-mode '(step next))
(eq arg-mode 'error))
- (progn
- ;; (setq edebug-execution-mode 'step)
- ;; (edebug-overlay-arrow) ; This doesn't always show up.
- (edebug--recursive-edit arg-mode))) ; <--- Recursive edit
+ (edebug--recursive-edit arg-mode)) ; <--- Recursive edit
;; Reset the edebug-window-data to whatever it is now.
(let ((window (if (eq (window-buffer) edebug-buffer)
(defining-kbd-macro
(if edebug-continue-kbd-macro defining-kbd-macro))
- ;; Disable command hooks. This is essential when
- ;; a hook function is instrumented - to avoid infinite loop.
- ;; This may be more than we need, however.
- (pre-command-hook nil)
- (post-command-hook nil)
-
;; others??
)
(if (buffer-name edebug-buffer) ; if it still exists
(progn
(set-buffer edebug-buffer)
- (if (memq edebug-execution-mode '(go Go-nonstop))
- (edebug-overlay-arrow))
+ (when (memq edebug-execution-mode '(go Go-nonstop))
+ (edebug-overlay-arrow)
+ (sit-for 0))
(edebug-mode -1))
;; gotta have a buffer to let its buffer local variables be set
(get-buffer-create " bogus edebug buffer"))
;;; Display related functions
-(defun edebug-adjust-window (old-start)
- ;; If pos is not visible, adjust current window to fit following context.
- ;; (message "window: %s old-start: %s window-start: %s pos: %s"
- ;; (selected-window) old-start (window-start) (point)) (sit-for 5)
- (if (not (pos-visible-in-window-p))
- (progn
- ;; First try old-start
- (if old-start
- (set-window-start (selected-window) old-start))
- (if (not (pos-visible-in-window-p))
- (progn
- ;; (message "resetting window start") (sit-for 2)
- (set-window-start
- (selected-window)
- (save-excursion
- (forward-line
- (if (< (point) (window-start)) -1 ; one line before if in back
- (- (/ (window-height) 2)) ; center the line moving forward
- ))
- (beginning-of-line)
- (point)))))))
- (window-start))
-
-
-
(defconst edebug-arrow-alist
'((Continue-fast . "=")
(Trace-fast . "-")
(step . "=>")
(next . "=>")
(go . "<>")
- (Go-nonstop . "..") ; not used
+ (Go-nonstop . "..")
)
"Association list of arrows for each edebug mode.")
One side effect of using this command is that the next time the
function or macro is called, Edebug will be called there as well."
(interactive)
- (if (not (looking-at "\("))
+ (if (not (looking-at "("))
(error "You must be before a list form")
(let ((func
(save-excursion
(down-list 1)
- (if (looking-at "\(")
+ (if (looking-at "(")
(edebug--form-data-name
(edebug-get-form-data-entry (point)))
(read (current-buffer))))))
(setq edebug-execution-mode 'Go-nonstop)
(top-level))
-
;;(defun edebug-exit-out ()
;; "Go until the current function exits."
;; (interactive)
;; (edebug-set-mode 'exiting "Exit..."))
-
-;;; The following initial mode setting definitions are not used yet.
-
-'(defconst edebug-initial-mode-alist
- '((edebug-Continue-fast . Continue-fast)
- (edebug-Trace-fast . Trace-fast)
- (edebug-continue . continue)
- (edebug-trace . trace)
- (edebug-go . go)
- (edebug-step-through . step)
- (edebug-Go-nonstop . Go-nonstop)
- )
+(defconst edebug-initial-mode-alist
+ '((edebug-step-mode . step)
+ (edebug-next-mode . next)
+ (edebug-trace-mode . trace)
+ (edebug-Trace-fast-mode . Trace-fast)
+ (edebug-go-mode . go)
+ (edebug-continue-mode . continue)
+ (edebug-Continue-fast-mode . Continue-fast)
+ (edebug-Go-nonstop-mode . Go-nonstop))
"Association list between commands and the modes they set.")
+(defvar edebug-mode-map) ; will be defined fully later.
-'(defun edebug-set-initial-mode ()
- "Ask for the initial mode of the enclosing function.
+(defun edebug-set-initial-mode ()
+ "Set the initial execution mode of Edebug.
The mode is requested via the key that would be used to set the mode in
edebug-mode."
(interactive)
- (let* ((this-function (edebug-which-function))
- (keymap (if (eq edebug-mode-map (current-local-map))
- edebug-mode-map))
- (old-mode (or (get this-function 'edebug-initial-mode)
- edebug-initial-mode))
+ (let* ((old-mode edebug-initial-mode)
(key (read-key-sequence
(format
- "Change initial edebug mode for %s from %s (%s) to (enter key): "
- this-function
- old-mode
- (where-is-internal
- (car (rassq old-mode edebug-initial-mode-alist))
- keymap 'firstonly
- ))))
- (mode (cdr (assq (key-binding key) edebug-initial-mode-alist)))
- )
- (if (and mode
- (or (get this-function 'edebug-initial-mode)
- (not (eq mode edebug-initial-mode))))
+ "Change initial edebug mode from %s (%c) to (enter key): "
+ old-mode
+ (aref (where-is-internal
+ (car (rassq old-mode edebug-initial-mode-alist))
+ edebug-mode-map 'firstonly)
+ 0))))
+ (mode (cdr (assq (lookup-key edebug-mode-map key)
+ edebug-initial-mode-alist))))
+ (if mode
(progn
- (put this-function 'edebug-initial-mode mode)
- (message "Initial mode for %s is now: %s"
- this-function mode))
- (error "Key must map to one of the mode changing commands")
- )))
+ (setq edebug-initial-mode mode)
+ (message "Edebug's initial mode is now: %s" mode))
+ (error "Key must map to one of the mode changing commands"))))
;;; Evaluation of expressions
(defalias 'edebug-prin1 'prin1)
(defalias 'edebug-print 'print)
(defalias 'edebug-prin1-to-string 'prin1-to-string)
-(defalias 'edebug-format 'format)
+(defalias 'edebug-format 'format-message)
(defalias 'edebug-message 'message)
(defun edebug-eval-expression (expr)
(define-key emacs-lisp-mode-map "\C-x\C-a\C-s" 'edebug-step-mode)
(define-key emacs-lisp-mode-map "\C-x\C-a\C-n" 'edebug-next-mode)
(define-key emacs-lisp-mode-map "\C-x\C-a\C-c" 'edebug-go-mode)
- (define-key emacs-lisp-mode-map "\C-x\C-a\C-l" 'edebug-where))
+ (define-key emacs-lisp-mode-map "\C-x\C-a\C-l" 'edebug-where)
+ ;; The following isn't a GUD binding.
+ (define-key emacs-lisp-mode-map "\C-x\C-a\C-m" 'edebug-set-initial-mode))
(defvar edebug-mode-map
(let ((map (copy-keymap emacs-lisp-mode-map)))
(if t (progn
;; Delete interspersed edebug internals.
- (while (re-search-forward "^ \(?edebug" nil t)
+ (while (re-search-forward "^ (?edebug" nil t)
(beginning-of-line)
(cond
- ((looking-at "^ \(edebug-after")
+ ((looking-at "^ (edebug-after")
;; Previous lines may contain code, so just delete this line.
(setq last-ok-point (point))
(forward-line 1)