;;; edebug.el --- a source-level debugger for Emacs Lisp
-;; Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1999,
-;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1988-1995, 1997, 1999-2012 Free Software Foundation, Inc.
;; Author: Daniel LaLiberte <liberte@holonexus.org>
;; Maintainer: FSF
;;; Code:
+(require 'macroexp)
+
;;; Bug reporting
(defalias 'edebug-submit-bug-report 'report-emacs-bug)
(defcustom edebug-unwrap-results nil
"Non-nil if Edebug should unwrap results of expressions.
+That is, Edebug will try to remove its own instrumentation from the result.
This is useful when debugging macros where the results of expressions
are instrumented expressions. But don't do this when results might be
circular or an infinite loop will result."
(defun get-edebug-spec (symbol)
;; Get the spec of symbol resolving all indirection.
- (let ((edebug-form-spec (get symbol 'edebug-form-spec))
- indirect)
- (while (and (symbolp edebug-form-spec)
- (setq indirect (get edebug-form-spec 'edebug-form-spec)))
+ (let ((edebug-form-spec nil)
+ (indirect symbol))
+ (while
+ (progn
+ (and (symbolp indirect)
+ (setq indirect
+ (function-get indirect 'edebug-form-spec 'autoload))))
;; (edebug-trace "indirection: %s" edebug-form-spec)
(setq edebug-form-spec indirect))
edebug-form-spec
(setq spec (cdr spec)))
t))
((symbolp spec)
- (unless (functionp spec) (get spec 'edebug-form-spec)))))
+ (unless (functionp spec) (function-get spec 'edebug-form-spec)))))
;;; Utilities
((and (eq (car form) 'defcustom)
(default-boundp (nth 1 form)))
;; Force variable to be bound.
- (set-default (nth 1 form) (eval (nth 2 form))))
+ ;; FIXME: Shouldn't this use the :setter or :initializer?
+ (set-default (nth 1 form) (eval (nth 2 form) lexical-binding)))
((eq (car form) 'defface)
;; Reset the face.
(setq face-new-frame-defaults
(assq-delete-all (nth 1 form) face-new-frame-defaults))
(put (nth 1 form) 'face-defface-spec nil)
+ (put (nth 1 form) 'face-documentation (nth 3 form))
;; See comments in `eval-defun-1' for purpose of code below
(setq form (prog1 `(prog1 ,form
(put ',(nth 1 form) 'saved-face
(put ',(nth 1 form) 'customized-face
,(nth 2 form)))
(put (nth 1 form) 'saved-face nil)))))
- (setq edebug-result (eval form))
+ (setq edebug-result (eval (eval-sexp-add-defvars form) lexical-binding))
(if (not edebugging)
(princ edebug-result)
edebug-result)))
;; but this causes problems while edebugging edebug.
(let ((edebug-all-forms t)
(edebug-all-defs t))
- (edebug-read-top-level-form))))
+ (eval-sexp-add-defvars
+ (edebug-read-top-level-form)))))
(defun edebug-read-top-level-form ()
(edebug-storing-offsets (1- (point)) 'quote)
(edebug-read-storing-offsets stream)))
-(defvar edebug-read-backquote-level 0
- "If non-zero, we're in a new-style backquote.
-It should never be negative. This controls how we read comma constructs.")
-
(defun edebug-read-backquote (stream)
;; Turn `thing into (\` thing)
(forward-char 1)
(list
(edebug-storing-offsets (1- (point)) '\`)
- (let ((edebug-read-backquote-level (1+ edebug-read-backquote-level)))
- (edebug-read-storing-offsets stream))))
+ (edebug-read-storing-offsets stream)))
(defun edebug-read-comma (stream)
;; Turn ,thing into (\, thing). Handle ,@ and ,. also.
(forward-char 1)))
;; Generate the same structure of offsets we would have
;; if the resulting list appeared verbatim in the input text.
- (if (zerop edebug-read-backquote-level)
- (edebug-storing-offsets opoint symbol)
- (list
- (edebug-storing-offsets opoint symbol)
- (let ((edebug-read-backquote-level (1- edebug-read-backquote-level)))
- (edebug-read-storing-offsets stream)))))))
+ (list
+ (edebug-storing-offsets opoint symbol)
+ (edebug-read-storing-offsets stream)))))
(defun edebug-read-function (stream)
;; Turn #'thing into (function thing)
(cond ((eq ?\' (following-char))
(forward-char 1)
(list
- (edebug-storing-offsets (- (point) 2)
- (if (featurep 'cl) 'function* 'function))
+ (edebug-storing-offsets (- (point) 2) 'function)
(edebug-read-storing-offsets stream)))
((memq (following-char) '(?: ?B ?O ?X ?b ?o ?x ?1 ?2 ?3 ?4 ?5 ?6
?7 ?8 ?9 ?0))
(prog1
(let ((elements))
(while (not (memq (edebug-next-token-class) '(rparen dot)))
- (if (and (eq (edebug-next-token-class) 'backquote)
- (null elements)
- (zerop edebug-read-backquote-level))
- (progn
- ;; Old style backquote.
- (forward-char 1) ; Skip backquote.
- ;; Call edebug-storing-offsets here so that we
- ;; produce the same offsets we would have had
- ;; if the backquote were an ordinary symbol.
- (push (edebug-storing-offsets (1- (point)) '\`) elements))
- (push (edebug-read-storing-offsets stream) elements)))
+ (push (edebug-read-storing-offsets stream) elements))
(setq elements (nreverse elements))
(if (eq 'dot (edebug-next-token-class))
(let (dotted-form)
((eq 'edebug-after (car sexp))
(nth 3 sexp))
((eq 'edebug-enter (car sexp))
- (let ((forms (nthcdr 2 (nth 1 (nth 3 sexp)))))
- (if (> (length forms) 1)
- (cons 'progn forms) ;; could return (values forms) instead.
- (car forms))))
+ (macroexp-progn (nthcdr 2 (nth 1 (nth 3 sexp)))))
(t sexp);; otherwise it is not wrapped, so just return it.
)
sexp))
;; Wrap a form, usually a defining form, but any evaluated one.
;; If speclist is non-nil, this is being called by edebug-defining-form.
;; Otherwise it is being called from edebug-read-and-maybe-wrap-form1.
- ;; This is a hack, but I havent figured out a simpler way yet.
+ ;; This is a hack, but I haven't figured out a simpler way yet.
(let* ((form-data-entry (edebug-get-form-data-entry form-begin form-end))
;; Set this marker before parsing.
(edebug-form-begin-marker
;; The first spec is handled and the remainder-handler handles the rest.
(let ((edebug-matching-depth
(if (> edebug-matching-depth edebug-max-depth)
- (error "too deep - perhaps infinite loop in spec?")
+ (error "Too deep - perhaps infinite loop in spec?")
(1+ edebug-matching-depth))))
(cond
((null specs) nil)
;;;; Edebug Form Specs
;;; ==========================================================
-;;; See cl-specs.el for common lisp specs.
;;;;* Spec for def-edebug-spec
;;; Out of date.
;; A macro is allowed by Emacs.
(def-edebug-spec function (&or symbolp lambda-expr))
-;; lambda is a macro in emacs 19.
-(def-edebug-spec lambda (&define lambda-list
- [&optional stringp]
- [&optional ("interactive" interactive)]
- def-body))
-
;; A macro expression is a lambda expression with "macro" prepended.
(def-edebug-spec macro (&define "lambda" lambda-list def-body))
(def-edebug-spec apply (function-form &rest form))
(def-edebug-spec funcall (function-form &rest form))
-;; FIXME? The manual has a gate here.
+;; FIXME? The manual uses this form (maybe that's just for illustration?):
+;; (def-edebug-spec let
+;; ((&rest &or symbolp (gate symbolp &optional form))
+;; body))
(def-edebug-spec let
((&rest &or (symbolp &optional form) symbolp)
body))
(def-edebug-spec with-custom-print body)
-(def-edebug-spec sregexq (&rest sexp))
-(def-edebug-spec rx (&rest sexp))
;;; The debugger itself
(if edebug-global-break-condition
(condition-case nil
(setq edebug-global-break-result
+ ;; FIXME: lexbind.
(eval edebug-global-break-condition))
(error nil))))
(edebug-break))
(and edebug-break-data
(or (not edebug-break-condition)
(setq edebug-break-result
+ ;; FIXME: lexbind.
(eval edebug-break-condition))))))
(if (and edebug-break
(nth 2 edebug-break-data)) ; is it temporary?
;; Set up the overlay arrow at beginning-of-line in current buffer.
;; The arrow string is derived from edebug-arrow-alist and
;; edebug-execution-mode.
- (let ((pos (save-excursion (beginning-of-line) (point))))
+ (let ((pos (line-beginning-position)))
(setq overlay-arrow-string
(cdr (assq edebug-execution-mode edebug-arrow-alist)))
(setq overlay-arrow-position (make-marker))
(edebug-toggle-save-selected-window)
(edebug-toggle-save-all-windows)))
-
(defun edebug-where ()
"Show the debug windows and where we stopped in the program."
(interactive)
"Modify the breakpoint for the form at point or after it.
Set it if FLAG is non-nil, clear it otherwise. Then move to that point.
If CONDITION or TEMPORARY are non-nil, add those attributes to
-the breakpoint. "
+the breakpoint."
(let ((edebug-stop-point (edebug-find-stop-point)))
(if edebug-stop-point
(let* ((edebug-def-name (car edebug-stop-point))
;; Return the function symbol, or nil if not instrumented.
(let ((func-marker (get func 'edebug)))
(cond
- ((markerp func-marker)
+ ((and (markerp func-marker) (marker-buffer func-marker))
;; It is uninstrumented, so instrument it.
(with-current-buffer (marker-buffer func-marker)
(goto-char func-marker)
(message "%s is already instrumented." func)
func)
(t
- (let ((loc (find-function-noselect func)))
+ (let ((loc (find-function-noselect func t)))
(unless (cdr loc)
(error "Could not find the definition in its file"))
(with-current-buffer (car loc)
(defun edebug-on-entry (function &optional flag)
"Cause Edebug to stop when FUNCTION is called.
With prefix argument, make this temporary so it is automatically
-cancelled the first time the function is entered."
+canceled the first time the function is entered."
(interactive "aEdebug on entry to: \nP")
;; Could store this in the edebug data instead.
(put function 'edebug-on-entry (if flag 'temp t)))
(defun edebug-eval (edebug-expr)
;; Are there cl lexical variables active?
- (if (bound-and-true-p cl-debug-env)
- (eval (cl-macroexpand-all edebug-expr cl-debug-env))
- (eval edebug-expr)))
+ (eval (if (bound-and-true-p cl-debug-env)
+ (cl-macroexpand-all edebug-expr cl-debug-env)
+ edebug-expr)
+ lexical-binding))
(defun edebug-safe-eval (edebug-expr)
;; Evaluate EXPR safely.
;;; Edebug Minor Mode
-;; FIXME eh?
-(defvar gud-inhibit-global-bindings
- "*Non-nil means don't do global rebindings of C-x C-a subcommands.")
+(defvar edebug-inhibit-emacs-lisp-mode-bindings nil
+ "If non-nil, inhibit Edebug bindings on the C-x C-a key.
+By default, loading the `edebug' library causes these bindings to
+be installed in `emacs-lisp-mode-map'.")
+
+(define-obsolete-variable-alias 'gud-inhibit-global-bindings
+ 'edebug-inhibit-emacs-lisp-mode-bindings "24.2")
;; Global GUD bindings for all emacs-lisp-mode buffers.
-(unless gud-inhibit-global-bindings
+(unless edebug-inhibit-emacs-lisp-mode-bindings
(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)
\\{global-edebug-map}
Options:
-edebug-setup-hook
-edebug-all-defs
-edebug-all-forms
-edebug-save-windows
-edebug-save-displayed-buffer-points
-edebug-initial-mode
-edebug-trace
-edebug-test-coverage
-edebug-continue-kbd-macro
-edebug-print-length
-edebug-print-level
-edebug-print-circle
-edebug-on-error
-edebug-on-quit
-edebug-on-signal
-edebug-unwrap-results
-edebug-global-break-condition
-"
+`edebug-setup-hook'
+`edebug-all-defs'
+`edebug-all-forms'
+`edebug-save-windows'
+`edebug-save-displayed-buffer-points'
+`edebug-initial-mode'
+`edebug-trace'
+`edebug-test-coverage'
+`edebug-continue-kbd-macro'
+`edebug-print-length'
+`edebug-print-level'
+`edebug-print-circle'
+`edebug-on-error'
+`edebug-on-quit'
+`edebug-on-signal'
+`edebug-unwrap-results'
+`edebug-global-break-condition'"
;; If the user kills the buffer in which edebug is currently active,
;; exit to top level, because the edebug command loop can't usefully
;; continue running in such a case.
-(defvar edebug-eval-mode-map nil
- "Keymap for Edebug Eval mode. Superset of Lisp Interaction mode.")
-
-(unless edebug-eval-mode-map
- (setq edebug-eval-mode-map (make-sparse-keymap))
- (set-keymap-parent edebug-eval-mode-map lisp-interaction-mode-map)
-
- (define-key edebug-eval-mode-map "\C-c\C-w" 'edebug-where)
- (define-key edebug-eval-mode-map "\C-c\C-d" 'edebug-delete-eval-item)
- (define-key edebug-eval-mode-map "\C-c\C-u" 'edebug-update-eval-list)
- (define-key edebug-eval-mode-map "\C-x\C-e" 'edebug-eval-last-sexp)
- (define-key edebug-eval-mode-map "\C-j" 'edebug-eval-print-last-sexp))
+(defvar edebug-eval-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map lisp-interaction-mode-map)
+ (define-key map "\C-c\C-w" 'edebug-where)
+ (define-key map "\C-c\C-d" 'edebug-delete-eval-item)
+ (define-key map "\C-c\C-u" 'edebug-update-eval-list)
+ (define-key map "\C-x\C-e" 'edebug-eval-last-sexp)
+ (define-key map "\C-j" 'edebug-eval-print-last-sexp)
+ map)
+"Keymap for Edebug Eval mode. Superset of Lisp Interaction mode.")
(put 'edebug-eval-mode 'mode-class 'special)
;;; Frequency count and coverage
;; FIXME should this use overlays instead?
+;; Definitely, IMO. The current business with undo in
+;; edebug-temp-display-freq-count is horrid.
(defun edebug-display-freq-count ()
"Display the frequency count data for each line of the current definition.
The frequency counts are inserted as comment lines after each line,
(insert "\n")
(setq i first-index)))))
+;; FIXME this does not work very well. Eg if you press an arrow key,
+;; or make a mouse-click, it fails with "Non-character input-event".
(defun edebug-temp-display-freq-count ()
"Temporarily display the frequency count data for the current definition.
It is removed when you hit any char."
(undo-boundary)
(edebug-display-freq-count)
(setq unread-command-char (read-char))
+ ;; Yuck! This doesn't seem to work at all for me.
(undo)))
\f
;;; Menus
(defun edebug-toggle (variable)
- (set variable (not (eval variable)))
- (message "%s: %s" variable (eval variable)))
+ (set variable (not (symbol-value variable)))
+ (message "%s: %s" variable (symbol-value variable)))
;; We have to require easymenu (even for Emacs 18) just so
;; the easy-menu-define macro call is compiled correctly.
\f
;;; Autoloading of Edebug accessories
-(if (featurep 'cl)
- (add-hook 'edebug-setup-hook
- (function (lambda () (require 'cl-specs))))
- ;; The following causes cl-specs to be loaded if you load cl.el.
- (add-hook 'cl-load-hook
- (function (lambda () (require 'cl-specs)))))
-
-;;; edebug-cl-read and cl-read are available from liberte@cs.uiuc.edu
+;; edebug-cl-read and cl-read are available from liberte@cs.uiuc.edu
(if (featurep 'cl-read)
(add-hook 'edebug-setup-hook
(function (lambda () (require 'edebug-cl-read))))
\f
;;; Finalize Loading
-;;; Finally, hook edebug into the rest of Emacs.
-;;; There are probably some other things that could go here.
+;; Finally, hook edebug into the rest of Emacs.
+;; There are probably some other things that could go here.
;; Install edebug read and eval functions.
(edebug-install-read-eval-functions)
(provide 'edebug)
-;; arch-tag: 19c8d05c-4554-426e-ac72-e0fa1fcb0808
;;; edebug.el ends here