(defalias 'edebug-submit-bug-report 'report-emacs-bug)
(defgroup edebug nil
"A source-level debugger for Emacs Lisp."
:group 'lisp)
(defcustom edebug-setup-hook nil
"*Functions to call before edebug is used.
Each time it is set to a new value, Edebug will call those functions
once and then `edebug-setup-hook' is reset to nil. You could use this
to load up Edebug specifications associated with a package you are
using but only when you also use Edebug."
:type 'hook
:group 'edebug)
(defcustom edebug-all-defs nil
"*If non-nil, evaluating defining forms instruments for Edebug.
This applies to `eval-defun', `eval-region', `eval-buffer', and
`eval-current-buffer'. `eval-region' is also called by
`eval-last-sexp', and `eval-print-last-sexp'.
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
`emacs-lisp-mode-hook'."
:type 'boolean
:group 'edebug)
(defcustom edebug-all-forms nil
"*Non-nil evaluation of all forms will instrument for Edebug.
This doesn't apply to loading or evaluations in the minibuffer.
Use the command `edebug-all-forms' to toggle the value of this option."
:type 'boolean
:group 'edebug)
(defcustom edebug-eval-macro-args nil
"*Non-nil means all macro call arguments may be evaluated.
If this variable is nil, the default, Edebug will *not* wrap
macro call arguments as if they will be evaluated.
For each macro, a `edebug-form-spec' overrides this option.
So to specify exceptions for macros that have some arguments evaluated
and some not, you should specify an `edebug-form-spec'."
:type 'boolean
:group 'edebug)
(defcustom edebug-save-windows t
"*If non-nil, Edebug saves and restores the window configuration.
That takes some time, so if your program does not care what happens to
the window configurations, it is better to set this variable to nil.
If the value is a list, only the listed windows are saved and
restored.
`edebug-toggle-save-windows' may be used to change this variable."
:type '(choice boolean (repeat string))
:group 'edebug)
(defcustom edebug-save-displayed-buffer-points nil
"*If non-nil, save and restore point in all displayed buffers.
Saving and restoring point in other buffers is necessary if you are
debugging code that changes the point of a buffer which is displayed
in a non-selected window. If Edebug or the user then selects the
window, the buffer's point will be changed to the window's point.
Saving and restoring point in all buffers is expensive, since it
requires selecting each window twice, so enable this only if you need
it."
:type 'boolean
:group 'edebug)
(defcustom edebug-initial-mode 'step
"*Initial execution mode for Edebug, if non-nil.
If this variable is non-nil, it specifies the initial execution mode
for Edebug when it is first activated. Possible values are step, next,
go, Go-nonstop, trace, Trace-fast, continue, and Continue-fast."
:type '(choice (const step) (const next) (const go)
(const Go-nonstop) (const trace)
(const Trace-fast) (const continue)
(const Continue-fast))
:group 'edebug)
(defcustom edebug-trace nil
"*Non-nil means display a trace of function entry and exit.
Tracing output is displayed in a buffer named `*edebug-trace*', one
function entry or exit per line, indented by the recursion level.
You can customize by replacing functions `edebug-print-trace-before'
and `edebug-print-trace-after'."
:type 'boolean
:group 'edebug)
(defcustom edebug-test-coverage nil
"*If non-nil, Edebug tests coverage of all expressions debugged.
This is done by comparing the result of each expression
with the previous result. Coverage is considered OK if two different
results are found.
Use `edebug-display-freq-count' to display the frequency count and
coverage information for a definition."
:type 'boolean
:group 'edebug)
(defcustom edebug-continue-kbd-macro nil
"*If non-nil, continue defining or executing any keyboard macro.
Use this with caution since it is not debugged."
:type 'boolean
:group 'edebug)
(defcustom edebug-print-length 50
"*Default value of `print-length' for printing results in Edebug."
:type 'integer
:group 'edebug)
(defcustom edebug-print-level 50
"*Default value of `print-level' for printing results in Edebug."
:type 'integer
:group 'edebug)
(defcustom edebug-print-circle t
"*Default value of `print-circle' for printing results in Edebug."
:type 'boolean
:group 'edebug)
(defcustom edebug-unwrap-results nil
"*Non-nil if Edebug should unwrap results of expressions.
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."
:type 'boolean
:group 'edebug)
(defcustom edebug-on-error t
"*Value bound to `debug-on-error' while Edebug is active.
If `debug-on-error' is non-nil, that value is still used.
If the value is a list of signal names, Edebug will stop when any of
these errors are signaled from Lisp code whether or not the signal is
handled by a `condition-case'. This option is useful for debugging
signals that *are* handled since they would otherwise be missed.
After execution is resumed, the error is signaled again."
:type '(choice (const :tag "off")
(repeat :menu-tag "When"
:value (nil)
(symbol :format "%v"))
(const :tag "always" t))
:group 'edebug)
(defcustom edebug-on-quit t
"*Value bound to `debug-on-quit' while Edebug is active."
:type 'boolean
:group 'edebug)
(defcustom edebug-global-break-condition nil
"*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
:group 'edebug)
(defcustom edebug-sit-for-seconds 1
"*Number of seconds to pause when execution mode is `trace'."
:type 'number
:group 'edebug)
(defmacro def-edebug-form-spec (symbol spec-form)
"For compatibility with old version."
(def-edebug-spec symbol (eval spec-form)))
(make-obsolete 'def-edebug-form-spec 'def-edebug-spec "22.1")
(defun get-edebug-spec (symbol)
(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)))
(setq edebug-form-spec indirect))
edebug-form-spec
))
(defun edebug-basic-spec (spec)
"Return t if SPEC uses only extant spec symbols.
An extant spec symbol is a symbol that is not a function and has a
`edebug-form-spec' property."
(cond ((listp spec)
(catch 'basic
(while spec
(unless (edebug-basic-spec (car spec)) (throw 'basic nil))
(setq spec (cdr spec)))
t))
((symbolp spec)
(unless (functionp spec) (get spec 'edebug-form-spec)))))
(defvar edebug-gensym-index 0
"Integer used by `edebug-gensym' to produce new names.")
(defun edebug-gensym (&optional prefix)
"Generate a fresh uninterned symbol.
There is an optional argument, PREFIX. PREFIX is the
string that begins the new name. Most people take just the default,
except when debugging needs suggest otherwise."
(if (null prefix)
(setq prefix "G"))
(let ((newsymbol nil)
(newname ""))
(while (not newsymbol)
(setq newname (concat prefix (int-to-string edebug-gensym-index)))
(setq edebug-gensym-index (+ edebug-gensym-index 1))
(if (not (intern-soft newname))
(setq newsymbol (make-symbol newname))))
newsymbol))
(defun edebug-lambda-list-keywordp (object)
"Return t if OBJECT is a lambda list keyword.
A lambda list keyword is a symbol that starts with `&'."
(and (symbolp object)
(= ?& (aref (symbol-name object) 0))))
(defun edebug-last-sexp ()
(car
(read-from-string
(buffer-substring
(save-excursion
(forward-sexp -1)
(point))
(point)))))
(defun edebug-window-list ()
"Return a list of windows, in order of `next-window'."
(let (window-list)
(walk-windows (lambda (w) (push w window-list)))
(nreverse window-list)))
'(defun edebug-two-window-p ()
"Return t if there are two windows."
(and (not (one-window-p))
(eq (selected-window)
(next-window (next-window (selected-window))))))
(defsubst edebug-lookup-function (object)
(while (and (symbolp object) (fboundp object))
(setq object (symbol-function object)))
object)
(defun edebug-macrop (object)
"Return the macro named by OBJECT, or nil if it is not a macro."
(setq object (edebug-lookup-function object))
(if (and (listp object)
(eq 'macro (car object))
(functionp (cdr object)))
object))
(defun edebug-sort-alist (alist function)
(sort alist (function
(lambda (e1 e2)
(funcall function (car e1) (car e2))))))
'(defmacro edebug-save-restriction (&rest body)
"Evaluate BODY while saving the current buffers restriction.
BODY may change buffer outside of current restriction, unlike
save-restriction. BODY may change the current buffer,
and the restriction will be restored to the original buffer,
and the current buffer remains current.
Return the result of the last expression in BODY."
`(let ((edebug:s-r-beg (point-min-marker))
(edebug:s-r-end (point-max-marker)))
(unwind-protect
(progn ,@body)
(save-excursion
(set-buffer (marker-buffer edebug:s-r-beg))
(narrow-to-region edebug:s-r-beg edebug:s-r-end)))))
(defconst edebug-trace-buffer "*edebug-trace*"
"Name of the buffer to put trace info in.")
(defun edebug-pop-to-buffer (buffer &optional window)
(setq window
(cond
((and (windowp window) (edebug-window-live-p window)
(eq (window-buffer window) buffer))
window)
((eq (window-buffer (selected-window)) buffer)
(selected-window))
((edebug-get-buffer-window buffer))
((one-window-p 'nomini)
(split-window))
((let ((trace-window (get-buffer-window edebug-trace-buffer)))
(catch 'found
(dolist (elt (window-list nil 'nomini))
(unless (or (eq elt (selected-window)) (eq elt trace-window)
(window-dedicated-p elt))
(throw 'found elt))))))
(t (split-window))))
(select-window window)
(set-window-buffer window buffer)
(set-window-hscroll window 0) )
(defun edebug-get-displayed-buffer-points ()
(let (list)
(walk-windows (lambda (w)
(unless (eq w (selected-window))
(push (cons (window-buffer w)
(window-point w))
list))))
list))
(defun edebug-set-buffer-points (buffer-points)
(save-current-buffer
(mapcar (lambda (buf-point)
(when (buffer-live-p (car buf-point))
(set-buffer (car buf-point))
(goto-char (cdr buf-point))))
buffer-points)))
(defun edebug-current-windows (which-windows)
(if (listp which-windows)
(mapcar (function (lambda (window)
(if (edebug-window-live-p window)
(list window
(window-buffer window)
(window-point window)
(window-start window)
(window-hscroll window)))))
which-windows)
(current-window-configuration)))
(defun edebug-set-windows (window-info)
(if (listp window-info)
(mapcar (function
(lambda (one-window-info)
(if one-window-info
(apply (function
(lambda (window buffer point start hscroll)
(if (edebug-window-live-p window)
(progn
(set-window-buffer window buffer)
(set-window-point window point)
(set-window-start window start)
(set-window-hscroll window hscroll)))))
one-window-info))))
window-info)
(set-window-configuration window-info)))
(defalias 'edebug-get-buffer-window 'get-buffer-window)
(defalias 'edebug-sit-for 'sit-for)
(defalias 'edebug-input-pending-p 'input-pending-p)
(or (fboundp 'edebug-original-read)
(defalias 'edebug-original-read (symbol-function 'read)))
(defun edebug-read (&optional stream)
"Read one Lisp expression as text from STREAM, return as Lisp object.
If STREAM is nil, use the value of `standard-input' (which see).
STREAM or the value of `standard-input' may be:
a buffer (read from point and advance it)
a marker (read from where it points and advance it)
a function (call it with no arguments for each character,
call it with a char as argument to push a char back)
a string (takes text from string, starting at the beginning)
t (read text line using minibuffer and use it).
This version, from Edebug, maybe instruments the expression. But the
STREAM must be the current buffer to do so. Whether it instruments is
also dependent on the values of `edebug-all-defs' and
`edebug-all-forms'."
(or stream (setq stream standard-input))
(if (eq stream (current-buffer))
(edebug-read-and-maybe-wrap-form)
(edebug-original-read stream)))
(or (fboundp 'edebug-original-eval-defun)
(defalias 'edebug-original-eval-defun (symbol-function 'eval-defun)))
(defun edebug-eval-defun (edebug-it)
"Evaluate the top-level form containing point, or after point.
If the current defun is actually a call to `defvar', then reset the
variable using its initial value expression even if the variable
already has some other value. (Normally `defvar' does not change the
variable's value if it already has a value.) Treat `defcustom'
similarly. Reinitialize the face according to `defface' specification.
With a prefix argument, instrument the code for Edebug.
Setting `edebug-all-defs' to a non-nil value reverses the meaning of
the prefix argument. Code is then instrumented when this function is
invoked without a prefix argument
If acting on a `defun' for FUNCTION, and the function was
instrumented, `Edebug: FUNCTION' is printed in the minibuffer. If not
instrumented, just FUNCTION is printed.
If not acting on a `defun', the result of evaluation is displayed in
the minibuffer."
(interactive "P")
(let* ((edebugging (not (eq (not edebug-it) (not edebug-all-defs))))
(edebug-result)
(form
(let ((edebug-all-forms edebugging)
(edebug-all-defs (eq edebug-all-defs (not edebug-it))))
(edebug-read-top-level-form))))
(cond ((and (eq (car form) 'defvar)
(cdr-safe (cdr-safe form)))
(makunbound (nth 1 form)))
((and (eq (car form) 'defcustom)
(default-boundp (nth 1 form)))
(set-default (nth 1 form) (eval (nth 2 form))))
((eq (car form) 'defface)
(setq face-new-frame-defaults
(assq-delete-all (nth 1 form) face-new-frame-defaults))
(put (nth 1 form) 'face-defface-spec nil)
(setq form (prog1 `(prog1 ,form
(put ',(nth 1 form) 'saved-face
',(get (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))
(if (not edebugging)
(princ edebug-result)
edebug-result)))
(defalias 'edebug-defun 'edebug-eval-top-level-form)
(defun edebug-eval-top-level-form ()
"Evaluate the top level form point is in, stepping through with Edebug.
This is like `eval-defun' except that it steps the code for Edebug
before evaluating it. It displays the value in the echo area
using `eval-expression' (which see).
If you do this on a function definition
such as a defun or defmacro, it defines the function and instruments
its definition for Edebug, so it will do Edebug stepping when called
later. It displays `Edebug: FUNCTION' in the echo area to indicate
that FUNCTION is now instrumented for Edebug.
If the current defun is actually a call to `defvar' or `defcustom',
evaluating it this way resets the variable using its initial value
expression even if the variable already has some other value.
\(Normally `defvar' and `defcustom' do not alter the value if there
already is one.)"
(interactive)
(eval-expression
(let ((edebug-all-forms t)
(edebug-all-defs t))
(edebug-read-top-level-form))))
(defun edebug-read-top-level-form ()
(let ((starting-point (point)))
(end-of-defun)
(beginning-of-defun)
(prog1
(edebug-read-and-maybe-wrap-form)
(goto-char starting-point))))
(defalias 'edebug-all-defuns 'edebug-all-defs)
(defun edebug-all-defs ()
"Toggle edebugging of all definitions."
(interactive)
(setq edebug-all-defs (not edebug-all-defs))
(message "Edebugging all definitions is %s."
(if edebug-all-defs "on" "off")))
(defun edebug-all-forms ()
"Toggle edebugging of all forms."
(interactive)
(setq edebug-all-forms (not edebug-all-forms))
(message "Edebugging all forms is %s."
(if edebug-all-forms "on" "off")))
(defun edebug-install-read-eval-functions ()
(interactive)
(unless load-read-function
(setq load-read-function 'edebug-read)
(defalias 'eval-defun 'edebug-eval-defun)))
(defun edebug-uninstall-read-eval-functions ()
(interactive)
(setq load-read-function nil)
(defalias 'eval-defun (symbol-function 'edebug-original-eval-defun)))
(make-variable-buffer-local 'edebug-form-data)
(defvar edebug-form-data nil)
(defun edebug-make-form-data-entry (symbol begin end)
(list symbol begin end))
(defsubst edebug-form-data-name (entry)
(car entry))
(defsubst edebug-form-data-begin (entry)
(nth 1 entry))
(defsubst edebug-form-data-end (entry)
(nth 2 entry))
(defsubst edebug-set-form-data-entry (entry name begin end)
(setcar entry name) (set-marker (nth 1 entry) begin)
(set-marker (nth 2 entry) end))
(defun edebug-get-form-data-entry (pnt &optional end-point)
(let ((rest edebug-form-data)
closest-entry
(closest-dist 999999)) (while (and rest (< 0 closest-dist))
(let* ((entry (car rest))
(begin (edebug-form-data-begin entry))
(dist (- pnt begin)))
(setq rest (cdr rest))
(if (and (<= 0 dist)
(< dist closest-dist)
(or (not end-point)
(= end-point (edebug-form-data-end entry)))
(<= pnt (edebug-form-data-end entry)))
(setq closest-dist dist
closest-entry entry))))
closest-entry))
(defun edebug-form-data-symbol ()
(or (edebug-form-data-name (edebug-get-form-data-entry (point)))
(error "Not inside instrumented form")))
(defun edebug-make-top-form-data-entry (new-entry)
(edebug-clear-form-data-entry new-entry)
(setq edebug-form-data (cons new-entry edebug-form-data)))
(defun edebug-clear-form-data-entry (entry)
(if entry
(progn
(setq edebug-form-data (delq entry edebug-form-data)))))
(defun edebug-syntax-error (&rest args)
(signal 'invalid-read-syntax args))
(defconst edebug-read-syntax-table
(let ((table (make-char-table 'syntax-table 'symbol))
(i 0))
(while (< i ?!)
(aset table i 'space)
(setq i (1+ i)))
(aset table ?\( 'lparen)
(aset table ?\) 'rparen)
(aset table ?\' 'quote)
(aset table ?\` 'backquote)
(aset table ?\, 'comma)
(aset table ?\" 'string)
(aset table ?\? 'char)
(aset table ?\[ 'lbracket)
(aset table ?\] 'rbracket)
(aset table ?\. 'dot)
(aset table ?\# 'hash)
;; We treat numbers as symbols, because of confusion with -, -1, and 1-.
;; We don't care about any other chars since they won't be seen.
table))
(defun edebug-next-token-class ()
;; Move to the next token and return its class. We only care about
;; lparen, rparen, dot, quote, backquote, comma, string, char, vector,
;; or symbol.
(edebug-skip-whitespace)
(if (and (eq (following-char) ?.)
(save-excursion
(forward-char 1)
(or (and (eq (aref edebug-read-syntax-table (following-char))
'symbol)
(not (= (following-char) ?\;)))
(memq (following-char) '(?\, ?\.)))))
'symbol
(aref edebug-read-syntax-table (following-char))))
(defun edebug-skip-whitespace ()
;; Leave point before the next token, skipping white space and comments.
(skip-chars-forward " \t\r\n\f")
(while (= (following-char) ?\;)
(skip-chars-forward "^\n") ; skip the comment
(skip-chars-forward " \t\r\n\f")))
;; Mostly obsolete reader; still used in one case.
(defun edebug-read-sexp ()
;; Read one sexp from the current buffer starting at point.
;; Leave point immediately after it. A sexp can be a list or atom.
;; An atom is a symbol (or number), character, string, or vector.
;; This works for reading anything legitimate, but it
;; is gummed up by parser inconsistencies (bugs?)
(let ((class (edebug-next-token-class)))
(cond
;; read goes one too far if a (possibly quoted) string or symbol
;; is immediately followed by non-whitespace.
((eq class 'symbol) (edebug-original-read (current-buffer)))
((eq class 'string) (edebug-original-read (current-buffer)))
((eq class 'quote) (forward-char 1)
(list 'quote (edebug-read-sexp)))
((eq class 'backquote)
(list '\` (edebug-read-sexp)))
((eq class 'comma)
(list '\, (edebug-read-sexp)))
(t ; anything else, just read it.
(edebug-original-read (current-buffer))))))
;;; Offsets for reader
;; Define a structure to represent offset positions of expressions.
;; Each offset structure looks like: (before . after) for constituents,
;; or for structures that have elements: (before <subexpressions> . after)
;; where the <subexpressions> are the offset structures for subexpressions
;; including the head of a list.
(defvar edebug-offsets nil)
;; Stack of offset structures in reverse order of the nesting.
;; This is used to get back to previous levels.
(defvar edebug-offsets-stack nil)
(defvar edebug-current-offset nil) ; Top of the stack, for convenience.
;; We must store whether we just read a list with a dotted form that
;; is itself a list. This structure will be condensed, so the offsets
;; must also be condensed.
(defvar edebug-read-dotted-list nil)
(defsubst edebug-initialize-offsets ()
;; Reinitialize offset recording.
(setq edebug-current-offset nil))
(defun edebug-store-before-offset (point)
;; Add a new offset pair with POINT as the before offset.
(let ((new-offset (list point)))
(if edebug-current-offset
(setcdr edebug-current-offset
(cons new-offset (cdr edebug-current-offset)))
;; Otherwise, we are at the top level, so initialize.
(setq edebug-offsets new-offset
edebug-offsets-stack nil
edebug-read-dotted-list nil))
;; Cons the new offset to the front of the stack.
(setq edebug-offsets-stack (cons new-offset edebug-offsets-stack)
edebug-current-offset new-offset)
))
(defun edebug-store-after-offset (point)
;; Finalize the current offset struct by reversing it and
;; store POINT as the after offset.
(if (not edebug-read-dotted-list)
;; Just reverse the offsets of all subexpressions.
(setcdr edebug-current-offset (nreverse (cdr edebug-current-offset)))
;; We just read a list after a dot, which will be abbreviated out.
(setq edebug-read-dotted-list nil)
;; Drop the corresponding offset pair.
;; That is, nconc the reverse of the rest of the offsets
;; with the cdr of last offset.
(setcdr edebug-current-offset
(nconc (nreverse (cdr (cdr edebug-current-offset)))
(cdr (car (cdr edebug-current-offset))))))
;; Now append the point using nconc.
(setq edebug-current-offset (nconc edebug-current-offset point))
;; Pop the stack.
(setq edebug-offsets-stack (cdr edebug-offsets-stack)
edebug-current-offset (car edebug-offsets-stack)))
(defun edebug-ignore-offset ()
;; Ignore the last created offset pair.
(setcdr edebug-current-offset (cdr (cdr edebug-current-offset))))
(defmacro edebug-storing-offsets (point &rest body)
(declare (debug (form body)) (indent 1))
`(unwind-protect
(progn
(edebug-store-before-offset ,point)
,@body)
(edebug-store-after-offset (point))))
;;; Reader for Emacs Lisp.
;; Uses edebug-next-token-class (and edebug-skip-whitespace) above.
(defconst edebug-read-alist
'((symbol . edebug-read-symbol)
(lparen . edebug-read-list)
(string . edebug-read-string)
(quote . edebug-read-quote)
(backquote . edebug-read-backquote)
(comma . edebug-read-comma)
(lbracket . edebug-read-vector)
(hash . edebug-read-function)
))
(defun edebug-read-storing-offsets (stream)
(let (edebug-read-dotted-list) ; see edebug-store-after-offset
(edebug-storing-offsets (point)
(funcall
(or (cdr (assq (edebug-next-token-class) edebug-read-alist))
;; anything else, just read it.
'edebug-original-read)
stream))))
(defun edebug-read-symbol (stream)
(edebug-original-read stream))
(defun edebug-read-string (stream)
(edebug-original-read stream))
(defun edebug-read-quote (stream)
;; Turn 'thing into (quote thing)
(forward-char 1)
(list
(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))))
(defun edebug-read-comma (stream)
;; Turn ,thing into (\, thing). Handle ,@ and ,. also.
(let ((opoint (point)))
(forward-char 1)
(let ((symbol '\,))
(cond ((eq (following-char) ?\.)
(setq symbol '\,\.)
(forward-char 1))
((eq (following-char) ?\@)
(setq symbol '\,@)
(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)))))))
(defun edebug-read-function (stream)
;; Turn #'thing into (function thing)
(forward-char 1)
(cond ((eq ?\' (following-char))
(forward-char 1)
(list
(edebug-storing-offsets (- (point) 2)
(if (featurep 'cl) 'function* '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))
(backward-char 1)
(edebug-original-read stream))
(t (edebug-syntax-error "Bad char after #"))))
(defun edebug-read-list (stream)
(forward-char 1) ; skip \(
(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)))
(setq elements (nreverse elements))
(if (eq 'dot (edebug-next-token-class))
(let (dotted-form)
(forward-char 1) ; skip \.
(setq dotted-form (edebug-read-storing-offsets stream))
elements (nconc elements dotted-form)
(if (not (eq (edebug-next-token-class) 'rparen))
(edebug-syntax-error "Expected `)'"))
(setq edebug-read-dotted-list (listp dotted-form))
))
elements)
(forward-char 1) ; skip \)
))
(defun edebug-read-vector (stream)
(forward-char 1) ; skip \[
(prog1
(let ((elements))
(while (not (eq 'rbracket (edebug-next-token-class)))
(push (edebug-read-storing-offsets stream) elements))
(apply 'vector (nreverse elements)))
(forward-char 1) ; skip \]
))
;;; Cursors for traversal of list and vector elements with offsets.
(defvar edebug-dotted-spec nil)
(defun edebug-new-cursor (expressions offsets)
;; Return a new cursor for EXPRESSIONS with OFFSETS.
(if (vectorp expressions)
(setq expressions (append expressions nil)))
(cons expressions offsets))
(defsubst edebug-set-cursor (cursor expressions offsets)
;; Set the CURSOR's EXPRESSIONS and OFFSETS to the given.
;; Return the cursor.
(setcar cursor expressions)
(setcdr cursor offsets)
cursor)
(defun edebug-copy-cursor (cursor)
;; Copy the cursor using the same object and offsets.
(cons (car cursor) (cdr cursor)))
(defsubst edebug-cursor-expressions (cursor)
(car cursor))
(defsubst edebug-cursor-offsets (cursor)
(cdr cursor))
(defsubst edebug-empty-cursor (cursor)
;; Return non-nil if CURSOR is empty - meaning no more elements.
(null (car cursor)))
(defsubst edebug-top-element (cursor)
;; Return the top element at the cursor.
;; Assumes not empty.
(car (car cursor)))
(defun edebug-top-element-required (cursor &rest error)
;; Check if a dotted form is required.
(if edebug-dotted-spec (edebug-no-match cursor "Dot expected."))
;; Check if there is at least one more argument.
(if (edebug-empty-cursor cursor) (apply 'edebug-no-match cursor error))
;; Return that top element.
(edebug-top-element cursor))
(defsubst edebug-top-offset (cursor)
;; Return the top offset pair corresponding to the top element.
(car (cdr cursor)))
(defun edebug-move-cursor (cursor)
;; Advance and return the cursor to the next element and offset.
;; throw no-match if empty before moving.
;; This is a violation of the cursor encapsulation, but
;; there is plenty of that going on while matching.
;; The following test should always fail.
(if (edebug-empty-cursor cursor)
(edebug-no-match cursor "Not enough arguments."))
(setcar cursor (cdr (car cursor)))
(setcdr cursor (cdr (cdr cursor)))
cursor)
(defun edebug-before-offset (cursor)
;; Return the before offset of the cursor.
;; If there is nothing left in the offsets,
;; return one less than the offset itself,
;; which is the after offset for a list.
(let ((offset (edebug-cursor-offsets cursor)))
(if (consp offset)
(car (car offset))
(1- offset))))
(defun edebug-after-offset (cursor)
;; Return the after offset of the cursor object.
(let ((offset (edebug-top-offset cursor)))
(while (consp offset)
(setq offset (cdr offset)))
offset))
;;; The Parser
;; The top level function for parsing forms is
;; edebug-read-and-maybe-wrap-form; it calls all the rest. It checks the
;; syntax a bit and leaves point at any error it finds, but otherwise
;; should appear to work like eval-defun.
;; The basic plan is to surround each expression with a call to
;; the edebug debugger together with indexes into a table of positions of
;; all expressions. Thus an expression "exp" becomes:
;; (edebug-after (edebug-before 1) 2 exp)
;; When this is evaluated, first point is moved to the beginning of
;; exp at offset 1 of the current function. The expression is
;; evaluated, which may cause more edebug calls, and then point is
;; moved to offset 2 after the end of exp.
;; The highest level expressions of the function are wrapped in a call to
;; edebug-enter, which supplies the function name and the actual
;; arguments to the function. See functions edebug-enter, edebug-before,
;; and edebug-after for more details.
;; Dynamically bound vars, left unbound, but globally declared.
;; This is to quiet the byte compiler.
;; Window data of the highest definition being wrapped.
;; This data is shared by all embedded definitions.
(defvar edebug-top-window-data)
(defvar edebug-&optional)
(defvar edebug-&rest)
(defvar edebug-gate nil) ;; whether no-match forces an error.
(defvar edebug-def-name nil) ; name of definition, used by interactive-form
(defvar edebug-old-def-name nil) ; previous name of containing definition.
(defvar edebug-error-point nil)
(defvar edebug-best-error nil)
(defun edebug-read-and-maybe-wrap-form ()
;; Read a form and wrap it with edebug calls, if the conditions are right.
;; Here we just catch any no-match not caught below and signal an error.
;; Run the setup hook.
;; If it gets an error, make it nil.
(let ((temp-hook edebug-setup-hook))
(setq edebug-setup-hook nil)
(run-hooks 'temp-hook))
(let (result
edebug-top-window-data
edebug-def-name;; make sure it is locally nil
;; I don't like these here!!
edebug-&optional
edebug-&rest
edebug-gate
edebug-best-error
edebug-error-point
no-match
;; Do this once here instead of several times.
(max-lisp-eval-depth (+ 800 max-lisp-eval-depth))
(max-specpdl-size (+ 2000 max-specpdl-size)))
(setq no-match
(catch 'no-match
(setq result (edebug-read-and-maybe-wrap-form1))
nil))
(if no-match
(apply 'edebug-syntax-error no-match))
result))
(defun edebug-read-and-maybe-wrap-form1 ()
(let (spec
def-kind
defining-form-p
def-name
;; These offset things don't belong here, but to support recursive
;; calls to edebug-read, they need to be here.
edebug-offsets
edebug-offsets-stack
edebug-current-offset ; reset to nil
)
(save-excursion
(if (and (eq 'lparen (edebug-next-token-class))
(eq 'symbol (progn (forward-char 1) (edebug-next-token-class))))
;; Find out if this is a defining form from first symbol
(setq def-kind (edebug-original-read (current-buffer))
spec (and (symbolp def-kind) (get-edebug-spec def-kind))
defining-form-p (and (listp spec)
(eq '&define (car spec)))
;; This is incorrect in general!! But OK most of the time.
def-name (if (and defining-form-p
(eq 'name (car (cdr spec)))
(eq 'symbol (edebug-next-token-class)))
(edebug-original-read (current-buffer))))))
;;;(message "all defs: %s all forms: %s" edebug-all-defs edebug-all-forms)
(cond
(defining-form-p
(if (or edebug-all-defs edebug-all-forms)
;; If it is a defining form and we are edebugging defs,
;; then let edebug-list-form start it.
(let ((cursor (edebug-new-cursor
(list (edebug-read-storing-offsets (current-buffer)))
(list edebug-offsets))))
(car
(edebug-make-form-wrapper
cursor
(edebug-before-offset cursor)
(1- (edebug-after-offset cursor))
(list (cons (symbol-name def-kind) (cdr spec))))))
;; Not edebugging this form, so reset the symbol's edebug
;; property to be just a marker at the definition's source code.
;; This only works for defs with simple names.
(put def-name 'edebug (point-marker))
;; Also nil out dependent defs.
'(mapcar (function
(lambda (def)
(put def-name 'edebug nil)))
(get def-name 'edebug-dependents))
(edebug-read-sexp)))
;; If all forms are being edebugged, explicitly wrap it.
(edebug-all-forms
(let ((cursor (edebug-new-cursor
(list (edebug-read-storing-offsets (current-buffer)))
(list edebug-offsets))))
(edebug-make-form-wrapper
cursor
(edebug-before-offset cursor)
(edebug-after-offset cursor)
nil)))
;; Not a defining form, and not edebugging.
(t (edebug-read-sexp)))
))
(defvar edebug-def-args) ; args of defining form.
(defvar edebug-def-interactive) ; is it an emacs interactive function?
(defvar edebug-inside-func) ;; whether code is inside function context.
;; Currently def-form sets this to nil; def-body sets it to t.
(defun edebug-interactive-p-name ()
;; Return a unique symbol for the variable used to store the
;; status of interactive-p for this function.
(intern (format "edebug-%s-interactive-p" edebug-def-name)))
(defun edebug-wrap-def-body (forms)
"Wrap the FORMS of a definition body."
(if edebug-def-interactive
`(let ((,(edebug-interactive-p-name)
(interactive-p)))
,(edebug-make-enter-wrapper forms))
(edebug-make-enter-wrapper forms)))
(defun edebug-make-enter-wrapper (forms)
;; Generate the enter wrapper for some forms of a definition.
;; This is not to be used for the body of other forms, e.g. `while',
;; since it wraps the list of forms with a call to `edebug-enter'.
;; Uses the dynamically bound vars edebug-def-name and edebug-def-args.
;; Do this after parsing since that may find a name.
(setq edebug-def-name
(or edebug-def-name edebug-old-def-name (edebug-gensym "edebug-anon")))
`(edebug-enter
(quote ,edebug-def-name)
,(if edebug-inside-func
`(list
;; Doesn't work with more than one def-body!!
;; But the list will just be reversed.
,@(nreverse edebug-def-args))
'nil)
(function (lambda () ,@forms))
))
(defvar edebug-form-begin-marker) ; the mark for def being instrumented
(defvar edebug-offset-index) ; the next available offset index.
(defvar edebug-offset-list) ; the list of offset positions.
(defun edebug-inc-offset (offset)
;; modifies edebug-offset-index and edebug-offset-list
;; accesses edebug-func-marc and buffer point
(prog1
edebug-offset-index
(setq edebug-offset-list (cons (- offset edebug-form-begin-marker)
edebug-offset-list)
edebug-offset-index (1+ edebug-offset-index))))
(defun edebug-make-before-and-after-form (before-index form after-index)
;; Return the edebug form for the current function at offset BEFORE-INDEX
;; given FORM. Looks like:
;; (edebug-after (edebug-before BEFORE-INDEX) AFTER-INDEX FORM)
;; Also increment the offset index for subsequent use.
(list 'edebug-after
(list 'edebug-before before-index)
after-index form))
(defun edebug-make-after-form (form after-index)
;; Like edebug-make-before-and-after-form, but only after.
(list 'edebug-after 0 after-index form))
(defun edebug-unwrap (sexp)
"Return the unwrapped SEXP or return it as is if it is not wrapped.
The SEXP might be the result of wrapping a body, which is a list of
expressions (if (consp sexp)
(cond
((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) (car forms))))
(t sexp) )
sexp))
(defun edebug-unwrap* (sexp)
"Return the sexp recursively unwrapped."
(let ((new-sexp (edebug-unwrap sexp)))
(while (not (eq sexp new-sexp))
(setq sexp new-sexp
new-sexp (edebug-unwrap sexp)))
(if (consp new-sexp)
(mapcar 'edebug-unwrap* new-sexp)
new-sexp)))
(defun edebug-defining-form (cursor form-begin form-end speclist)
(edebug-set-cursor cursor (edebug-cursor-expressions cursor)
(cdr (edebug-cursor-offsets cursor)))
(edebug-make-form-wrapper
cursor
form-begin (1- form-end)
speclist))
(defun edebug-make-form-wrapper (cursor form-begin form-end
&optional speclist)
(let* ((form-data-entry (edebug-get-form-data-entry form-begin form-end))
(edebug-form-begin-marker
(if form-data-entry
(edebug-form-data-begin form-data-entry)
(set-marker (make-marker) form-begin))))
(let (edebug-offset-list
(edebug-offset-index 0)
result
(edebug-old-def-name (edebug-form-data-name form-data-entry))
edebug-def-name
edebug-def-args
edebug-def-interactive
edebug-inside-func )
(setq result
(if speclist
(edebug-match cursor speclist)
(edebug-make-enter-wrapper (list (edebug-form cursor)))))
(setq edebug-def-name
(or edebug-def-name edebug-old-def-name (edebug-gensym "edebug-anon")))
'(if (and edebug-containing-def-name
(not (get edebug-containing-def-name 'edebug-dependents)))
(put edebug-containing-def-name 'edebug-dependents
(cons edebug-def-name
(get edebug-containing-def-name
'edebug-dependents))))
(if (not form-data-entry)
(setq form-data-entry
(edebug-make-form-data-entry
edebug-def-name
edebug-form-begin-marker
(set-marker (make-marker) form-end)
))
(edebug-set-form-data-entry
form-data-entry edebug-def-name form-begin form-end))
(edebug-make-top-form-data-entry form-data-entry)
(message "Edebug: %s" edebug-def-name)
(setq edebug-offset-list (vconcat (nreverse edebug-offset-list)))
(edebug-clear-frequency-count edebug-def-name)
(edebug-clear-coverage edebug-def-name)
(if (not edebug-top-window-data) (let ((window (or (get-buffer-window (current-buffer))
(selected-window))))
(setq edebug-top-window-data
(cons window (window-start window)))))
(put edebug-def-name 'edebug
(list edebug-form-begin-marker
nil edebug-offset-list
edebug-top-window-data
))
result
)))
(defun edebug-clear-frequency-count (name)
(put name 'edebug-freq-count
(make-vector (length edebug-offset-list) 0)))
(defun edebug-clear-coverage (name)
(put name 'edebug-coverage
(make-vector (length edebug-offset-list) 'unknown)))
(defun edebug-form (cursor)
(let* ((form (edebug-top-element-required cursor "Expected form"))
(offset (edebug-top-offset cursor)))
(prog1
(cond
((consp form)
(if (eq 'quote (car form))
form
(let* ((head (car form))
(spec (and (symbolp head) (get-edebug-spec head)))
(new-cursor (edebug-new-cursor form offset)))
(if (and (consp spec) (eq '&define (car spec)))
(edebug-defining-form
new-cursor
(car offset) (edebug-after-offset cursor)
(cons (symbol-name head) (cdr spec)))
(edebug-make-before-and-after-form
(edebug-inc-offset (car offset))
(edebug-list-form new-cursor)
(edebug-inc-offset (edebug-cursor-offsets new-cursor))))
)))
((symbolp form)
(cond
((or (memq form '(t nil))
(keywordp form))
form)
(t (edebug-make-after-form form (edebug-inc-offset (cdr offset))))))
(t form))
(edebug-move-cursor cursor))))
(defsubst edebug-forms (cursor) (edebug-match cursor '(&rest form)))
(defsubst edebug-sexps (cursor) (edebug-match cursor '(&rest sexp)))
(defsubst edebug-list-form-args (head cursor)
(let ((spec (get-edebug-spec head)))
(cond
(spec
(cond
((consp spec)
(let (edebug-best-error
edebug-error-point) (edebug-match-sublist cursor spec)))
((eq t spec) (edebug-forms cursor))
((eq 0 spec) (edebug-sexps cursor))
((symbolp spec) (funcall spec cursor)) ))
((edebug-macrop head)
(if edebug-eval-macro-args
(edebug-forms cursor)
(edebug-sexps cursor)))
(t (edebug-forms cursor)))))
(defun edebug-list-form (cursor)
(let ((head (edebug-top-element-required cursor "Expected elements"))
(edebug-gate t)
(edebug-&optional nil)
(edebug-&rest nil))
(edebug-set-cursor cursor (edebug-cursor-expressions cursor)
(cdr (edebug-cursor-offsets cursor)))
(cond
((symbolp head)
(cond
((null head) nil) ((eq head 'interactive-p)
(setq edebug-def-interactive 'check-it)
(edebug-move-cursor cursor)
(edebug-interactive-p-name))
(t
(cons head (edebug-list-form-args
head (edebug-move-cursor cursor))))))
((consp head)
(if (eq (car head) ',)
(edebug-match cursor '(("," def-form) body))
(edebug-match-specs cursor '(lambda-expr body) 'edebug-match-specs)))
(t (edebug-syntax-error
"Head of list form must be a symbol or lambda expression")))
))
(defvar edebug-after-dotted-spec nil)
(defvar edebug-matching-depth 0) (defconst edebug-max-depth 150)
(defun edebug-no-match (cursor &rest edebug-args)
(setq edebug-error-point (or edebug-error-point
(edebug-before-offset cursor))
edebug-best-error (or edebug-best-error edebug-args))
(if (and edebug-gate (not edebug-&optional))
(progn
(if edebug-error-point
(goto-char edebug-error-point))
(apply 'edebug-syntax-error edebug-args))
(funcall 'throw 'no-match edebug-args)))
(defun edebug-match (cursor specs)
(let (edebug-&optional
edebug-&rest
edebug-best-error
edebug-error-point
(edebug-gate edebug-gate) )
(edebug-match-specs cursor specs 'edebug-match-specs)))
(defun edebug-match-one-spec (cursor spec)
(cond
((symbolp spec) (edebug-match-symbol cursor spec))
((vectorp spec) (edebug-match cursor (append spec nil)))
((stringp spec) (edebug-match-string cursor spec))
((listp spec) (edebug-match-list cursor spec))
))
(defun edebug-match-specs (cursor specs remainder-handler)
(let ((edebug-matching-depth
(if (> edebug-matching-depth edebug-max-depth)
(error "too deep - perhaps infinite loop in spec?")
(1+ edebug-matching-depth))))
(cond
((null specs) nil)
((atom specs)
(let ((edebug-dotted-spec t)) (edebug-match-specs cursor (list specs) remainder-handler)))
((not (listp (edebug-cursor-expressions cursor))) (if (not edebug-dotted-spec)
(edebug-no-match cursor "Dotted spec required."))
(let ((edebug-dotted-spec)
(this-form (edebug-cursor-expressions cursor))
(this-offset (edebug-cursor-offsets cursor)))
(edebug-set-cursor cursor (list this-form) this-offset)
(car (edebug-match-specs cursor specs remainder-handler))))
(t (let* ((spec (car specs))
(rest)
(first-char (and (symbolp spec) (aref (symbol-name spec) 0))))
(nconc
(cond
((eq ?& first-char) (funcall (get-edebug-spec spec) cursor (cdr specs)))
((eq ?: first-char) (setq rest (cdr (cdr specs)))
(funcall (get-edebug-spec spec) cursor (car (cdr specs))))
(t (setq rest (cdr specs))
(edebug-match-one-spec cursor spec)))
(funcall remainder-handler cursor rest remainder-handler)))))))
(dolist (pair '((&optional . edebug-match-&optional)
(&rest . edebug-match-&rest)
(&or . edebug-match-&or)
(form . edebug-match-form)
(sexp . edebug-match-sexp)
(body . edebug-match-body)
(&define . edebug-match-&define)
(name . edebug-match-name)
(:name . edebug-match-colon-name)
(arg . edebug-match-arg)
(def-body . edebug-match-def-body)
(def-form . edebug-match-def-form)
(lambda-expr . edebug-match-lambda-expr)
(¬ . edebug-match-¬)
(&key . edebug-match-&key)
(place . edebug-match-place)
(gate . edebug-match-gate)
))
(put (car pair) 'edebug-form-spec (cdr pair)))
(defun edebug-match-symbol (cursor symbol)
(let* ((spec (get-edebug-spec symbol)))
(cond
(spec
(if (consp spec)
(edebug-match cursor spec)
(funcall spec cursor)))
((null symbol) (edebug-match-nil cursor))
((fboundp symbol) (let ((sexp (edebug-top-element-required cursor "Expected" symbol)))
(if (and (listp sexp) (eq (car sexp) ',))
(edebug-match cursor '(("," def-form)))
(if (not (funcall symbol sexp))
(edebug-no-match cursor symbol "failed"))
(edebug-move-cursor cursor)
(list sexp))))
(t (error "%s is not a form-spec or function" symbol))
)))
(defun edebug-match-sexp (cursor)
(list (prog1 (edebug-top-element-required cursor "Expected sexp")
(edebug-move-cursor cursor))))
(defun edebug-match-form (cursor)
(list (edebug-form cursor)))
(defalias 'edebug-match-place 'edebug-match-form)
(defsubst edebug-match-body (cursor) (edebug-forms cursor))
(defun edebug-match-&optional (cursor specs)
(edebug-&optional-wrapper cursor specs 'edebug-&optional-wrapper))
(defun edebug-&optional-wrapper (cursor specs remainder-handler)
(let (result
(edebug-&optional specs)
(edebug-gate nil)
(this-form (edebug-cursor-expressions cursor))
(this-offset (edebug-cursor-offsets cursor)))
(if (null (catch 'no-match
(setq result
(edebug-match-specs cursor specs remainder-handler))
nil))
result
(edebug-set-cursor cursor this-form this-offset)
nil)))
(defun edebug-&rest-wrapper (cursor specs remainder-handler)
(if (null specs) (setq specs edebug-&rest))
(edebug-&optional-wrapper cursor specs remainder-handler))
(defun edebug-match-&rest (cursor specs)
(let ((edebug-&rest specs) edebug-best-error
edebug-error-point)
(edebug-&rest-wrapper cursor specs 'edebug-&rest-wrapper)))
(defun edebug-match-&or (cursor specs)
(let ((original-specs specs)
(this-form (edebug-cursor-expressions cursor))
(this-offset (edebug-cursor-offsets cursor)))
(catch 'matched
(while specs
(catch 'no-match
(throw 'matched
(let (edebug-gate edebug-best-error
edebug-error-point)
(edebug-match-one-spec cursor (car specs)))))
(setq specs (cdr specs))
(edebug-set-cursor cursor this-form this-offset))
(apply 'edebug-no-match cursor "Expected one of" original-specs))
))
(defun edebug-match-¬ (cursor specs)
(if (null (catch 'no-match
(let ((edebug-gate nil))
(save-excursion
(edebug-match-&or cursor specs)))
nil))
(edebug-no-match cursor "Unexpected"))
nil)
(def-edebug-spec &key edebug-match-&key)
(defun edebug-match-&key (cursor specs)
(edebug-match-&rest
cursor
(cons '&or
(mapcar (function (lambda (pair)
(vector (format ":%s" (car pair))
(car (cdr pair)))))
specs))))
(defun edebug-match-gate (cursor)
(setq edebug-gate t)
nil)
(defun edebug-match-list (cursor specs)
(if edebug-dotted-spec
(prog1
(let ((edebug-dotted-spec))
(edebug-match-specs cursor specs 'edebug-match-specs))
(setq edebug-dotted-spec nil))
(let ((spec (car specs))
(form (edebug-top-element-required cursor "Expected" specs)))
(cond
((eq 'quote spec)
(let ((spec (car (cdr specs))))
(cond
((symbolp spec)
(if (not (eq spec form))
(edebug-no-match cursor "Expected" spec))
(edebug-move-cursor cursor)
(setq edebug-gate t)
form)
(t
(error "Bad spec: %s" specs)))))
((listp form)
(prog1
(list (edebug-match-sublist
(edebug-new-cursor form (cdr (edebug-top-offset cursor)))
specs))
(edebug-move-cursor cursor)))
((and (eq 'vector spec) (vectorp form))
(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)))
)))
(defun edebug-match-sublist (cursor specs)
(let (edebug-&optional
)
(prog1
(edebug-match-specs cursor specs 'edebug-match-specs)
(if (not (edebug-empty-cursor cursor))
(if edebug-best-error
(apply 'edebug-no-match cursor edebug-best-error)
(edebug-no-match cursor "Failed matching" specs)
)))))
(defun edebug-match-string (cursor spec)
(let ((sexp (edebug-top-element-required cursor "Expected" spec)))
(if (not (eq (intern spec) sexp))
(edebug-no-match cursor "Expected" spec)
(setq edebug-gate t)
(edebug-move-cursor cursor)
(list sexp)
)))
(defun edebug-match-nil (cursor)
(if (not (edebug-empty-cursor cursor))
(edebug-no-match cursor "Unmatched argument(s)")
nil))
(defun edebug-match-function (cursor)
(error "Use function-form instead of function in edebug spec"))
(defun edebug-match-&define (cursor specs)
(edebug-make-form-wrapper
cursor
(edebug-before-offset cursor)
(let ((offsets (edebug-cursor-offsets cursor)))
(while (consp offsets) (setq offsets (cdr offsets)))
offsets)
specs))
(defun edebug-match-lambda-expr (cursor)
(let* ((sexp (edebug-top-element-required
cursor "Expected lambda expression"))
(offset (edebug-top-offset cursor))
(head (and (consp sexp) (car sexp)))
(spec (and (symbolp head) (get-edebug-spec head)))
(edebug-inside-func nil))
(if (and (consp spec) (eq '&define (car spec)))
(prog1
(list
(edebug-defining-form
(edebug-new-cursor sexp offset)
(car offset) (edebug-after-offset cursor)
(cons (symbol-name head) (cdr spec))))
(edebug-move-cursor cursor))
(edebug-no-match cursor "Expected lambda expression")
)))
(defun edebug-match-name (cursor)
(let ((name (edebug-top-element-required cursor "Expected name")))
(if (not (symbolp name))
(edebug-no-match cursor "Symbol expected for name of definition"))
(setq edebug-def-name
(if edebug-def-name
(intern (format "%s@%s" edebug-def-name name))
name))
(edebug-move-cursor cursor)
(list name)))
(defun edebug-match-colon-name (cursor spec)
(setq edebug-def-name
(if edebug-def-name
(intern (format "%s@%s" edebug-def-name spec))
spec))
nil)
(defun edebug-match-arg (cursor)
(let ((edebug-arg (edebug-top-element-required cursor "Expected arg")))
(if (or (not (symbolp edebug-arg))
(edebug-lambda-list-keywordp edebug-arg))
(edebug-no-match cursor "Bad argument:" edebug-arg))
(edebug-move-cursor cursor)
(setq edebug-def-args (cons edebug-arg edebug-def-args))
(list edebug-arg)))
(defun edebug-match-def-form (cursor)
(let ((edebug-inside-func nil))
(list (edebug-make-enter-wrapper (list (edebug-form cursor))))))
(defun edebug-match-def-body (cursor)
(let ((edebug-inside-func t))
(list (edebug-wrap-def-body (edebug-forms cursor)))))
(defun edebug-spec-p (object)
"Return non-nil if OBJECT is a symbol with an edebug-form-spec property."
(and (symbolp object)
(get object 'edebug-form-spec)))
(def-edebug-spec def-edebug-spec
(&define :name edebug-spec name
&or "nil" edebug-spec-p "t" "0" (&rest edebug-spec)))
(def-edebug-spec edebug-spec-list
((edebug-spec . [&or nil edebug-spec])))
(def-edebug-spec edebug-spec
(&or
(vector &rest edebug-spec) ("vector" &rest edebug-spec) ("quote" symbolp)
edebug-spec-list
stringp
[edebug-lambda-list-keywordp &rest edebug-spec]
[keywordp gate edebug-spec]
edebug-spec-p symbolp ))
(def-edebug-spec quote sexp)
(def-edebug-spec defconst defvar)
(def-edebug-spec defvar (symbolp &optional form stringp))
(def-edebug-spec defun
(&define name lambda-list
[&optional stringp]
[&optional ("interactive" interactive)]
def-body))
(def-edebug-spec defmacro
(&define name lambda-list [&optional ("declare" &rest sexp)] def-body))
(def-edebug-spec arglist lambda-list)
(def-edebug-spec lambda-list
(([&rest arg]
[&optional ["&optional" arg &rest arg]]
&optional ["&rest" arg]
)))
(def-edebug-spec interactive
(&optional &or stringp def-form))
(def-edebug-spec function-form
(&or ([&or "quote" "function"] &or symbolp lambda-expr) form))
(def-edebug-spec function (&or symbolp lambda-expr))
(def-edebug-spec lambda (&define lambda-list
[&optional stringp]
[&optional ("interactive" interactive)]
def-body))
(def-edebug-spec macro (&define "lambda" lambda-list def-body))
(def-edebug-spec mapcar (function-form form))
(def-edebug-spec mapconcat (function-form form form))
(def-edebug-spec mapatoms (function-form &optional form))
(def-edebug-spec apply (function-form &rest form))
(def-edebug-spec funcall (function-form &rest form))
(def-edebug-spec let
((&rest &or (symbolp &optional form) symbolp)
body))
(def-edebug-spec let* let)
(def-edebug-spec setq (&rest symbolp form))
(def-edebug-spec setq-default setq)
(def-edebug-spec cond (&rest (&rest form)))
(def-edebug-spec condition-case
(symbolp
form
&rest ([&or symbolp (&rest symbolp)] body)))
(def-edebug-spec \` (backquote-form))
(def-edebug-spec backquote-form
(&or
([&or "," ",@"] &or ("quote" backquote-form) form)
(backquote-form [&rest [¬ ","] backquote-form]
. [&or nil backquote-form])
(vector &rest backquote-form)
sexp))
(defalias 'edebug-\` '\`) (def-edebug-spec edebug-\` (def-form))
(def-edebug-spec , (&or ("quote" edebug-\`) def-form))
(def-edebug-spec ,@ (&define &or ("quote" edebug-\`) def-form))
(def-edebug-spec defsubst defun)
(def-edebug-spec dont-compile t)
(def-edebug-spec eval-when-compile t)
(def-edebug-spec eval-and-compile t)
(def-edebug-spec save-selected-window t)
(def-edebug-spec save-current-buffer t)
(def-edebug-spec delay-mode-hooks t)
(def-edebug-spec with-temp-file t)
(def-edebug-spec with-temp-message t)
(def-edebug-spec with-syntax-table t)
(def-edebug-spec push (form sexp))
(def-edebug-spec pop (sexp))
(def-edebug-spec 1value (form))
(def-edebug-spec noreturn (form))
(def-edebug-spec ad-dolist ((symbolp form &optional form) body))
(def-edebug-spec defadvice
(&define name (name name &rest sexp )
[&optional stringp]
[&optional ("interactive" interactive)]
def-body))
(def-edebug-spec easy-menu-define (symbolp body))
(def-edebug-spec with-custom-print body)
(def-edebug-spec sregexq (&rest sexp))
(def-edebug-spec rx (&rest sexp))
(defvar edebug-active nil)
(or (assq 'edebug-active minor-mode-alist)
(setq minor-mode-alist (cons (list 'edebug-active " *Debugging*")
minor-mode-alist)))
(defvar edebug-stack nil)
(defvar edebug-stack-depth -1)
(defvar edebug-offset-indices nil)
(defvar edebug-entered nil
)
(defconst edebug-debugger 'edebug
)
(defvar edebug-function) (defvar edebug-args) (defvar edebug-data) (defvar edebug-value) (defvar edebug-after-index)
(defvar edebug-def-mark) (defvar edebug-freq-count) (defvar edebug-coverage)
(defvar edebug-buffer) (defvar edebug-result) (defvar edebug-outside-executing-macro)
(defvar edebug-outside-defining-kbd-macro)
(defvar edebug-execution-mode 'step) (defvar edebug-next-execution-mode nil)
(defvar edebug-outside-debug-on-error) (defvar edebug-outside-debug-on-quit)
(defvar edebug-outside-overriding-local-map)
(defvar edebug-outside-overriding-terminal-local-map)
(defvar edebug-outside-pre-command-hook)
(defvar edebug-outside-post-command-hook)
(defvar cl-lexical-debug)
(defun edebug-signal (edebug-signal-name edebug-signal-data)
"Signal an error. Args are SIGNAL-NAME, and associated DATA.
A signal name is a symbol with an `error-conditions' property
that is a list of condition names.
A handler for any of those names will get to handle this signal.
The symbol `error' should always be one of them.
DATA should be a list. Its elements are printed as part of the error message.
If the signal is handled, DATA is made available to the handler.
See `condition-case'.
This is the Edebug replacement for the standard `signal'. It should
only be active while Edebug is. It checks `debug-on-error' to see
whether it should call the debugger. When execution is resumed, the
error is signaled again."
(if (and (listp debug-on-error) (memq edebug-signal-name debug-on-error))
(edebug 'error (cons edebug-signal-name edebug-signal-data)))
(let ((signal-hook-function nil))
(signal edebug-signal-name edebug-signal-data)))
(defun edebug-enter (edebug-function edebug-args edebug-body)
(if (not edebug-entered)
(let ((edebug-entered t)
(max-lisp-eval-depth (+ 100 max-lisp-eval-depth)) (max-specpdl-size (+ 200 max-specpdl-size))
(debugger edebug-debugger) (edebug-outside-debug-on-error debug-on-error)
(edebug-outside-debug-on-quit debug-on-quit)
(debug-on-error (or debug-on-error edebug-on-error))
(debug-on-quit edebug-on-quit)
(cl-lexical-debug t)
(edebug-outside-overriding-local-map overriding-local-map)
(edebug-outside-overriding-terminal-local-map
overriding-terminal-local-map)
(edebug-outside-executing-macro executing-kbd-macro)
(edebug-outside-pre-command-hook
(edebug-var-status 'pre-command-hook))
(edebug-outside-post-command-hook
(edebug-var-status 'post-command-hook)))
(unwind-protect
(let ( (executing-kbd-macro
(if edebug-continue-kbd-macro executing-kbd-macro))
(overriding-local-map nil)
(overriding-terminal-local-map nil)
(signal-hook-function 'edebug-signal)
(pre-command-hook nil)
(post-command-hook nil))
(setq edebug-execution-mode (or edebug-next-execution-mode
edebug-initial-mode
edebug-execution-mode)
edebug-next-execution-mode nil)
(edebug-enter edebug-function edebug-args edebug-body))
(setq executing-kbd-macro edebug-outside-executing-macro)
(edebug-restore-status
'post-command-hook edebug-outside-post-command-hook)
(edebug-restore-status
'pre-command-hook edebug-outside-pre-command-hook)))
(let* ((edebug-data (get edebug-function 'edebug))
(edebug-def-mark (car edebug-data)) (edebug-freq-count (get edebug-function 'edebug-freq-count))
(edebug-coverage (get edebug-function 'edebug-coverage))
(edebug-buffer (marker-buffer edebug-def-mark))
(edebug-stack (cons edebug-function edebug-stack))
(edebug-offset-indices (cons 0 edebug-offset-indices))
)
(if (get edebug-function 'edebug-on-entry)
(progn
(setq edebug-execution-mode 'step)
(if (eq (get edebug-function 'edebug-on-entry) 'temp)
(put edebug-function 'edebug-on-entry nil))))
(if edebug-trace
(edebug-enter-trace edebug-body)
(funcall edebug-body))
)))
(defun edebug-var-status (var)
"Return a cons cell describing the status of VAR's current binding.
The purpose of this function is so you can properly undo
subsequent changes to the same binding, by passing the status
cons cell to `edebug-restore-status'. The status cons cell
has the form (LOCUS . VALUE), where LOCUS can be a buffer
\(for a buffer-local binding), a frame (for a frame-local binding),
or nil (if the default binding is current)."
(cons (variable-binding-locus var)
(symbol-value var)))
(defun edebug-restore-status (var status)
"Reset VAR based on STATUS.
STATUS should be a list you got from `edebug-var-status'."
(let ((locus (car status))
(value (cdr status)))
(cond ((bufferp locus)
(if (buffer-live-p locus)
(with-current-buffer locus
(set var value))))
((framep locus)
(modify-frame-parameters locus (list (cons var value))))
(t
(set var value)))))
(defun edebug-enter-trace (edebug-body)
(let ((edebug-stack-depth (1+ edebug-stack-depth))
edebug-result)
(edebug-print-trace-before
(format "%s args: %s" edebug-function edebug-args))
(prog1 (setq edebug-result (funcall edebug-body))
(edebug-print-trace-after
(format "%s result: %s" edebug-function edebug-result)))))
(def-edebug-spec edebug-tracing (form body))
(defmacro edebug-tracing (msg &rest body)
"Print MSG in *edebug-trace* before and after evaluating BODY.
The result of BODY is also printed."
`(let ((edebug-stack-depth (1+ edebug-stack-depth))
edebug-result)
(edebug-print-trace-before ,msg)
(prog1 (setq edebug-result (progn ,@body))
(edebug-print-trace-after
(format "%s result: %s" ,msg edebug-result)))))
(defun edebug-print-trace-before (msg)
"Function called to print trace info before expression evaluation.
MSG is printed after `::::{ '."
(edebug-trace-display
edebug-trace-buffer "%s{ %s" (make-string edebug-stack-depth ?\:) msg))
(defun edebug-print-trace-after (msg)
"Function called to print trace info after expression evaluation.
MSG is printed after `::::} '."
(edebug-trace-display
edebug-trace-buffer "%s} %s" (make-string edebug-stack-depth ?\:) msg))
(defun edebug-slow-before (edebug-before-index)
(unless edebug-active
(setcar edebug-offset-indices edebug-before-index)
(aset edebug-freq-count edebug-before-index
(1+ (aref edebug-freq-count edebug-before-index)))
(if (or (not (memq edebug-execution-mode '(Go-nonstop next)))
(edebug-input-pending-p))
(edebug-debugger edebug-before-index 'before nil)))
edebug-before-index)
(defun edebug-fast-before (edebug-before-index)
)
(defun edebug-slow-after (edebug-before-index edebug-after-index edebug-value)
(if edebug-active
edebug-value
(setcar edebug-offset-indices edebug-after-index)
(aset edebug-freq-count edebug-after-index
(1+ (aref edebug-freq-count edebug-after-index)))
(if edebug-test-coverage (edebug-update-coverage))
(if (and (eq edebug-execution-mode 'Go-nonstop)
(not (edebug-input-pending-p)))
edebug-value
(edebug-debugger edebug-after-index 'after edebug-value)
)))
(defun edebug-fast-after (edebug-before-index edebug-after-index edebug-value)
edebug-value)
(defun edebug-run-slow ()
(defalias 'edebug-before 'edebug-slow-before)
(defalias 'edebug-after 'edebug-slow-after))
(defun edebug-run-fast ()
(defalias 'edebug-before 'edebug-fast-before)
(defalias 'edebug-after 'edebug-fast-after))
(edebug-run-slow)
(defun edebug-update-coverage ()
(let ((old-result (aref edebug-coverage edebug-after-index)))
(cond
((eq 'ok-coverage old-result))
((eq 'unknown old-result)
(aset edebug-coverage edebug-after-index edebug-value))
((not (eq edebug-value old-result))
(aset edebug-coverage edebug-after-index 'ok-coverage)))))
(defvar edebug-arg-mode) (defvar edebug-breakpoints)
(defvar edebug-break-data) (defvar edebug-break) (defvar edebug-global-break) (defvar edebug-break-condition)
(defvar edebug-break-result nil)
(defvar edebug-global-break-result nil)
(defun edebug-debugger (edebug-offset-index edebug-arg-mode edebug-value)
(if inhibit-redisplay
edebug-value
(let* ( (edebug-breakpoints (car (cdr edebug-data))) (edebug-break-data (assq edebug-offset-index edebug-breakpoints))
(edebug-break-condition (car (cdr edebug-break-data)))
(edebug-global-break
(if edebug-global-break-condition
(condition-case nil
(setq edebug-global-break-result
(eval edebug-global-break-condition))
(error nil))))
(edebug-break))
(setq edebug-break
(or edebug-global-break
(and edebug-break-data
(or (not edebug-break-condition)
(setq edebug-break-result
(eval edebug-break-condition))))))
(if (and edebug-break
(nth 2 edebug-break-data)) (setcdr edebug-data
(cons (delq edebug-break-data edebug-breakpoints)
(cdr (cdr edebug-data)))))
(if (or (not (memq edebug-execution-mode '(go continue Continue-fast)))
edebug-break
(edebug-input-pending-p))
(edebug-display))
edebug-value
)))
(defvar edebug-point) (defvar edebug-outside-buffer) (defvar edebug-outside-point) (defvar edebug-outside-mark) (defvar edebug-window-data) (defvar edebug-outside-windows) (defvar edebug-eval-buffer) (defvar edebug-outside-o-a-p) (defvar edebug-outside-o-a-s) (defvar edebug-outside-c-i-e-a) (defvar edebug-outside-d-c-i-n-s-w)
(defvar edebug-eval-list nil)
(defvar edebug-previous-result nil)
(defalias 'edebug-mark-marker 'mark-marker)
(defun edebug-display ()
(unless (marker-position edebug-def-mark)
(debug))
(let ((edebug-active t) (edebug-with-timeout-suspend (with-timeout-suspend))
edebug-stop (edebug-point (+ edebug-def-mark
(aref (nth 2 edebug-data) edebug-offset-index)))
edebug-buffer-outside-point (edebug-window-data (nth 3 edebug-data))
(edebug-outside-window (selected-window))
(edebug-outside-buffer (current-buffer))
(edebug-outside-point (point))
(edebug-outside-mark (edebug-mark))
(edebug-outside-unread-command-events unread-command-events)
edebug-outside-windows edebug-buffer-points
edebug-eval-buffer (edebug-eval-result-list (and edebug-eval-list
(edebug-eval-result-list)))
edebug-trace-window
edebug-trace-window-start
(edebug-outside-o-a-p overlay-arrow-position)
(edebug-outside-o-a-s overlay-arrow-string)
(edebug-outside-c-i-e-a cursor-in-echo-area)
(edebug-outside-d-c-i-n-s-w default-cursor-in-non-selected-windows))
(unwind-protect
(let ((overlay-arrow-position overlay-arrow-position)
(overlay-arrow-string overlay-arrow-string)
(cursor-in-echo-area nil)
(default-cursor-in-non-selected-windows t)
(unread-command-events unread-command-events)
)
(if (not (buffer-name edebug-buffer))
(let ((debug-on-error nil))
(error "Buffer defining %s not found" edebug-function)))
(if (eq 'after edebug-arg-mode)
(edebug-compute-previous-result edebug-value))
(if edebug-save-windows
(setq edebug-outside-windows
(edebug-current-windows edebug-save-windows)))
(if edebug-save-displayed-buffer-points
(setq edebug-buffer-points (edebug-get-displayed-buffer-points)))
(edebug-pop-to-buffer edebug-buffer (car edebug-window-data))
(setcar edebug-window-data (selected-window))
(edebug-eval-display edebug-eval-result-list)
(select-window (car edebug-window-data))
(set-buffer edebug-buffer)
(setq edebug-buffer-outside-point (point))
(goto-char edebug-point)
(if (eq 'before edebug-arg-mode)
(if (not (memq (following-char) '(?\( ?\# ?\` )))
(let ((debug-on-error nil))
(error "Source has changed - reevaluate definition of %s"
edebug-function)
)))
(setcdr edebug-window-data
(edebug-adjust-window (cdr edebug-window-data)))
(if (edebug-input-pending-p)
(progn
(setq edebug-execution-mode 'step
edebug-stop t)
(edebug-stop)
))
(edebug-overlay-arrow)
(cond
((eq 'error edebug-arg-mode)
(setq edebug-execution-mode 'step)
(edebug-overlay-arrow)
(beep)
(if (eq 'quit (car edebug-value))
(message "Quit")
(edebug-report-error edebug-value)))
(edebug-break
(cond
(edebug-global-break
(message "Global Break: %s => %s"
edebug-global-break-condition
edebug-global-break-result))
(edebug-break-condition
(message "Break: %s => %s"
edebug-break-condition
edebug-break-result))
((not (eq edebug-execution-mode 'Continue-fast))
(message "Break"))
(t)))
(t (message "")))
(setq unread-command-events nil)
(if (eq 'after edebug-arg-mode)
(progn
(if (and edebug-break
(not (eq edebug-execution-mode 'Continue-fast)))
(edebug-sit-for edebug-sit-for-seconds)) (edebug-previous-result)))
(cond
(edebug-break
(cond
((eq edebug-execution-mode 'continue)
(edebug-sit-for edebug-sit-for-seconds))
((eq edebug-execution-mode 'Continue-fast) (edebug-sit-for 0))
(t (setq edebug-stop t))))
((eq edebug-execution-mode 'trace)
(edebug-sit-for edebug-sit-for-seconds)) ((eq edebug-execution-mode 'Trace-fast)
(edebug-sit-for 0)))
(unwind-protect
(if (or edebug-stop
(memq edebug-execution-mode '(step next))
(eq edebug-arg-mode 'error))
(progn
(edebug-recursive-edit)))
(let ((window (if (eq (window-buffer) edebug-buffer)
(selected-window)
(edebug-get-buffer-window edebug-buffer))))
(if window
(progn
(setcar edebug-window-data window)
(setcdr edebug-window-data (window-start window)))))
(setq edebug-trace-window (get-buffer-window edebug-trace-buffer))
(if edebug-trace-window
(setq edebug-trace-window-start
(and edebug-trace-window
(window-start edebug-trace-window))))
(if edebug-save-windows
(progn
(edebug-set-windows edebug-outside-windows)
(if edebug-save-displayed-buffer-points
(edebug-set-buffer-points edebug-buffer-points))
(if edebug-trace-window
(set-window-start edebug-trace-window
edebug-trace-window-start))
(let ((window (car edebug-window-data)))
(if (and window (edebug-window-live-p window)
(eq (window-buffer) edebug-buffer))
(progn
(set-window-start window (cdr edebug-window-data)
'no-force)
)))
)
(if (edebug-window-live-p edebug-outside-window)
(select-window edebug-outside-window))
)
(if (buffer-name edebug-outside-buffer)
(set-buffer edebug-outside-buffer))
(if (not (eq edebug-buffer edebug-outside-buffer))
(goto-char edebug-outside-point))
(if (marker-buffer (edebug-mark-marker))
(set-marker (edebug-mark-marker) edebug-outside-mark))
)
(let ((current-buffer (current-buffer)))
(set-buffer edebug-buffer)
(goto-char edebug-buffer-outside-point)
(set-buffer current-buffer))
)
(with-timeout-unsuspend edebug-with-timeout-suspend)
(setq
unread-command-events edebug-outside-unread-command-events
overlay-arrow-position edebug-outside-o-a-p
overlay-arrow-string edebug-outside-o-a-s
cursor-in-echo-area edebug-outside-c-i-e-a
default-cursor-in-non-selected-windows edebug-outside-d-c-i-n-s-w)
)))
(defvar edebug-number-of-recursions 0)
(defvar edebug-recursion-depth 0)
(defvar edebug-outside-match-data) (defvar edebug-backtrace-buffer) (defvar edebug-inside-windows)
(defvar edebug-interactive-p)
(defvar edebug-outside-map)
(defvar edebug-outside-standard-output)
(defvar edebug-outside-standard-input)
(defvar edebug-outside-current-prefix-arg)
(defvar edebug-outside-last-command-char)
(defvar edebug-outside-last-command)
(defvar edebug-outside-this-command)
(defvar edebug-outside-last-input-char)
(defvar edebug-outside-unread-command-char)
(defvar edebug-outside-last-command-event)
(defvar edebug-outside-unread-command-events)
(defvar edebug-outside-last-input-event)
(defvar edebug-outside-last-event-frame)
(defvar edebug-outside-last-nonmenu-event)
(defvar edebug-outside-track-mouse)
(defvar edebug-unread-command-char-warning)
(defvar edebug-unread-command-event-warning)
(eval-when-compile
(setq edebug-unread-command-char-warning
(get 'unread-command-char 'byte-obsolete-variable))
(put 'unread-command-char 'byte-obsolete-variable nil))
(defun edebug-recursive-edit ()
(let ((edebug-buffer-read-only buffer-read-only)
(edebug-outside-match-data
(save-excursion (set-buffer edebug-outside-buffer) (match-data)))
(edebug-recursion-depth (recursion-depth))
edebug-entered (edebug-interactive-p nil) edebug-backtrace-buffer edebug-inside-windows
(edebug-outside-map (current-local-map))
(edebug-outside-standard-output standard-output)
(edebug-outside-standard-input standard-input)
(edebug-outside-defining-kbd-macro defining-kbd-macro)
(edebug-outside-last-command-char last-command-char)
(edebug-outside-last-command last-command)
(edebug-outside-this-command this-command)
(edebug-outside-last-input-char last-input-char)
(edebug-outside-unread-command-char unread-command-char)
(edebug-outside-current-prefix-arg current-prefix-arg)
(edebug-outside-last-input-event last-input-event)
(edebug-outside-last-command-event last-command-event)
(edebug-outside-last-event-frame last-event-frame)
(edebug-outside-last-nonmenu-event last-nonmenu-event)
(edebug-outside-track-mouse track-mouse)
)
(unwind-protect
(let (
(last-command-char last-command-char)
(last-command last-command)
(this-command this-command)
(last-input-char last-input-char)
(unread-command-char -1)
(current-prefix-arg nil)
(last-input-event nil)
(last-command-event nil)
(last-event-frame nil)
(last-nonmenu-event nil)
(track-mouse nil)
(debug-on-error edebug-outside-debug-on-error)
(debug-on-quit edebug-outside-debug-on-quit)
(defining-kbd-macro
(if edebug-continue-kbd-macro defining-kbd-macro))
)
(if (and (eq edebug-execution-mode 'go)
(not (memq edebug-arg-mode '(after error))))
(message "Break"))
(setq buffer-read-only t)
(setq signal-hook-function nil)
(edebug-mode)
(unwind-protect
(recursive-edit)
(setq signal-hook-function 'edebug-signal)
(if edebug-backtrace-buffer
(kill-buffer edebug-backtrace-buffer))
(if edebug-eval-buffer (kill-buffer edebug-eval-buffer))
(set-match-data edebug-outside-match-data)
(if (buffer-name edebug-buffer) (progn
(set-buffer edebug-buffer)
(if (memq edebug-execution-mode '(go Go-nonstop))
(edebug-overlay-arrow))
(setq buffer-read-only edebug-buffer-read-only)
(use-local-map edebug-outside-map)
(remove-hook 'kill-buffer-hook 'edebug-kill-buffer t)
)
(get-buffer-create " bogus edebug buffer"))
))
(setq
last-command-char edebug-outside-last-command-char
last-command-event edebug-outside-last-command-event
last-command edebug-outside-last-command
this-command edebug-outside-this-command
unread-command-char edebug-outside-unread-command-char
current-prefix-arg edebug-outside-current-prefix-arg
last-input-char edebug-outside-last-input-char
last-input-event edebug-outside-last-input-event
last-event-frame edebug-outside-last-event-frame
last-nonmenu-event edebug-outside-last-nonmenu-event
track-mouse edebug-outside-track-mouse
standard-output edebug-outside-standard-output
standard-input edebug-outside-standard-input
defining-kbd-macro edebug-outside-defining-kbd-macro
))
))
(defun edebug-adjust-window (old-start)
(if (not (pos-visible-in-window-p))
(progn
(if old-start
(set-window-start (selected-window) old-start))
(if (not (pos-visible-in-window-p))
(progn
(set-window-start
(selected-window)
(save-excursion
(forward-line
(if (< (point) (window-start)) -1 (- (/ (window-height) 2)) ))
(beginning-of-line)
(point)))))))
(window-start))
(defconst edebug-arrow-alist
'((Continue-fast . "=")
(Trace-fast . "-")
(continue . ">")
(trace . "->")
(step . "=>")
(next . "=>")
(go . "<>")
(Go-nonstop . "..") )
"Association list of arrows for each edebug mode.")
(defun edebug-overlay-arrow ()
(let ((pos (save-excursion (beginning-of-line) (point))))
(setq overlay-arrow-string
(cdr (assq edebug-execution-mode edebug-arrow-alist)))
(setq overlay-arrow-position (make-marker))
(set-marker overlay-arrow-position pos (current-buffer))))
(defun edebug-toggle-save-all-windows ()
"Toggle the saving and restoring of all windows.
Also, each time you toggle it on, the inside and outside window
configurations become the same as the current configuration."
(interactive)
(setq edebug-save-windows (not edebug-save-windows))
(if edebug-save-windows
(setq edebug-inside-windows
(setq edebug-outside-windows
(edebug-current-windows
edebug-save-windows))))
(message "Window saving is %s for all windows."
(if edebug-save-windows "on" "off")))
(defmacro edebug-changing-windows (&rest body)
`(let ((window (selected-window)))
(setq edebug-inside-windows (edebug-current-windows t))
(edebug-set-windows edebug-outside-windows)
,@body (setq edebug-outside-windows (edebug-current-windows
edebug-save-windows))
(edebug-set-windows edebug-inside-windows)))
(defun edebug-toggle-save-selected-window ()
"Toggle the saving and restoring of the selected window.
Also, each time you toggle it on, the inside and outside window
configurations become the same as the current configuration."
(interactive)
(cond
((eq t edebug-save-windows)
(edebug-changing-windows
(setq edebug-save-windows (delq window (edebug-window-list)))))
((memq (selected-window) edebug-save-windows)
(setq edebug-outside-windows
(delq (assq (selected-window) edebug-outside-windows)
edebug-outside-windows))
(setq edebug-save-windows
(delq (selected-window) edebug-save-windows)))
(t (edebug-changing-windows
(setq edebug-save-windows (cons window edebug-save-windows)))))
(message "Window saving is %s for %s."
(if (memq (selected-window) edebug-save-windows)
"on" "off")
(selected-window)))
(defun edebug-toggle-save-windows (arg)
"Toggle the saving and restoring of windows.
With prefix, toggle for just the selected window.
Otherwise, toggle for all windows."
(interactive "P")
(if arg
(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)
(if (not edebug-active)
(error "Edebug is not active"))
(edebug-pop-to-buffer edebug-buffer)
(goto-char edebug-point))
(defun edebug-view-outside ()
"Change to the outside window configuration."
(interactive)
(if (not edebug-active)
(error "Edebug is not active"))
(setq edebug-inside-windows
(edebug-current-windows edebug-save-windows))
(edebug-set-windows edebug-outside-windows)
(goto-char edebug-outside-point)
(message "Window configuration outside of Edebug. Return with %s"
(substitute-command-keys "\\<global-map>\\[edebug-where]")))
(defun edebug-bounce-point (arg)
"Bounce the point in the outside current buffer.
If prefix arg is supplied, sit for that many seconds before returning.
The default is one second."
(interactive "p")
(if (not edebug-active)
(error "Edebug is not active"))
(save-excursion
(save-window-excursion
(edebug-pop-to-buffer edebug-outside-buffer)
(goto-char edebug-outside-point)
(message "Current buffer: %s Point: %s Mark: %s"
(current-buffer) (point)
(if (marker-buffer (edebug-mark-marker))
(marker-position (edebug-mark-marker)) "<not set>"))
(edebug-sit-for arg)
(edebug-pop-to-buffer edebug-buffer (car edebug-window-data)))))
'(defvar edebug-display-buffer-list nil
"List of buffers that edebug will display when it is active.")
'(defun edebug-display-buffer (buffer)
"Toggle display of a buffer inside of edebug."
(interactive "bBuffer: ")
(let ((already-displaying (memq buffer edebug-display-buffer-list)))
(setq edebug-display-buffer-list
(if already-displaying
(delq buffer edebug-display-buffer-list)
(cons buffer edebug-display-buffer-list)))
(message "Displaying %s %s" buffer
(if already-displaying "off" "on"))))
(defun edebug-find-stop-point ()
(let* ((edebug-def-name (edebug-form-data-symbol))
(edebug-data
(let ((data (get edebug-def-name 'edebug)))
(if (or (null data) (markerp data))
(error "%s is not instrumented for Edebug" edebug-def-name))
data)) (edebug-def-mark (car edebug-data))
(offset-vector (nth 2 edebug-data))
(offset (- (save-excursion
(if (looking-at "[ \t]")
(skip-chars-backward " \t"))
(point))
edebug-def-mark))
len i)
(setq len (length offset-vector))
(setq i 0)
(while (and (< i len) (> offset (aref offset-vector i)))
(setq i (1+ i)))
(if (and (< i len)
(<= offset (aref offset-vector i)))
(cons edebug-def-name i)
(message "Point is not on an expression in %s."
edebug-def-name)
)))
(defun edebug-next-breakpoint ()
"Move point to the next breakpoint, or first if none past point."
(interactive)
(let ((edebug-stop-point (edebug-find-stop-point)))
(if edebug-stop-point
(let* ((edebug-def-name (car edebug-stop-point))
(index (cdr edebug-stop-point))
(edebug-data (get edebug-def-name 'edebug))
(edebug-def-mark (car edebug-data))
(edebug-breakpoints (car (cdr edebug-data)))
(offset-vector (nth 2 edebug-data))
breakpoint)
(if (not edebug-breakpoints)
(message "No breakpoints in this function.")
(let ((breaks edebug-breakpoints))
(while (and breaks
(<= (car (car breaks)) index))
(setq breaks (cdr breaks)))
(setq breakpoint
(if breaks
(car breaks)
(car edebug-breakpoints)))
(goto-char (+ edebug-def-mark
(aref offset-vector (car breakpoint))))
(message "%s"
(concat (if (nth 2 breakpoint)
"Temporary " "")
(if (car (cdr breakpoint))
(format "Condition: %s"
(edebug-safe-prin1-to-string
(car (cdr breakpoint))))
"")))
))))))
(defun edebug-modify-breakpoint (flag &optional condition temporary)
"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. "
(let ((edebug-stop-point (edebug-find-stop-point)))
(if edebug-stop-point
(let* ((edebug-def-name (car edebug-stop-point))
(index (cdr edebug-stop-point))
(edebug-data (get edebug-def-name 'edebug))
(edebug-def-mark (car edebug-data))
(edebug-breakpoints (car (cdr edebug-data)))
(offset-vector (nth 2 edebug-data))
present)
(setq present (assq index edebug-breakpoints))
(setq edebug-breakpoints (delq present edebug-breakpoints))
(if flag
(progn
(setq edebug-breakpoints
(edebug-sort-alist
(cons
(list index condition temporary)
edebug-breakpoints) '<))
(if condition
(message "Breakpoint set in %s with condition: %s"
edebug-def-name condition)
(message "Breakpoint set in %s" edebug-def-name)))
(if present
(message "Breakpoint unset in %s" edebug-def-name)
(message "No breakpoint here")))
(setcar (cdr edebug-data) edebug-breakpoints)
(goto-char (+ edebug-def-mark (aref offset-vector index)))
))))
(defun edebug-set-breakpoint (arg)
"Set the breakpoint of nearest sexp.
With prefix argument, make it a temporary breakpoint."
(interactive "P")
(edebug-modify-breakpoint t nil arg))
(defun edebug-unset-breakpoint ()
"Clear the breakpoint of nearest sexp."
(interactive)
(edebug-modify-breakpoint nil))
(defun edebug-set-global-break-condition (expression)
(interactive
(list
(let ((initial (and edebug-global-break-condition
(format "%s" edebug-global-break-condition))))
(read-from-minibuffer
"Global Condition: " initial read-expression-map t
(if (equal (car read-expression-history) initial)
'(read-expression-history . 1)
'read-expression-history)))))
(setq edebug-global-break-condition expression))
(defun edebug-set-mode (mode shortmsg msg)
(if (eq (1+ edebug-recursion-depth) (recursion-depth))
(progn
(setq edebug-execution-mode mode)
(message shortmsg)
(exit-recursive-edit))
(setq edebug-next-execution-mode mode)
(message msg)))
(defalias 'edebug-step-through-mode 'edebug-step-mode)
(defun edebug-step-mode ()
"Proceed to next stop point."
(interactive)
(edebug-set-mode 'step "" "Edebug will stop at next stop point."))
(defun edebug-next-mode ()
"Proceed to next `after' stop point."
(interactive)
(edebug-set-mode 'next "" "Edebug will stop after next eval."))
(defun edebug-go-mode (arg)
"Go, evaluating until break.
With prefix ARG, set temporary break at current point and go."
(interactive "P")
(if arg
(edebug-set-breakpoint t))
(edebug-set-mode 'go "Go..." "Edebug will go until break."))
(defun edebug-Go-nonstop-mode ()
"Go, evaluating without debugging."
(interactive)
(edebug-set-mode 'Go-nonstop "Go-Nonstop..."
"Edebug will not stop at breaks."))
(defun edebug-trace-mode ()
"Begin trace mode."
(interactive)
(edebug-set-mode 'trace "Tracing..." "Edebug will trace with pause."))
(defun edebug-Trace-fast-mode ()
"Trace with no wait at each step."
(interactive)
(edebug-set-mode 'Trace-fast
"Trace fast..." "Edebug will trace without pause."))
(defun edebug-continue-mode ()
"Begin continue mode."
(interactive)
(edebug-set-mode 'continue "Continue..."
"Edebug will pause at breakpoints."))
(defun edebug-Continue-fast-mode ()
"Trace with no wait at each step."
(interactive)
(edebug-set-mode 'Continue-fast "Continue fast..."
"Edebug will stop and go at breakpoints."))
(defun edebug-goto-here ()
"Proceed to first stop-point at or after current position of point."
(interactive)
(edebug-go-mode t))
(defun edebug-stop ()
"Stop execution and do not continue.
Useful for exiting from trace or continue loop."
(interactive)
(message "Stop"))
'(defun edebug-forward ()
"Proceed to the exit of the next expression to be evaluated."
(interactive)
(edebug-set-mode
'forward "Forward"
"Edebug will stop after exiting the next expression."))
(defun edebug-forward-sexp (arg)
"Proceed from the current point to the end of the ARGth sexp ahead.
If there are not ARG sexps ahead, then do edebug-step-out."
(interactive "p")
(condition-case nil
(let ((parse-sexp-ignore-comments t))
(forward-sexp arg)
(edebug-go-mode t))
(error
(edebug-step-out)
)))
(defun edebug-step-out ()
"Proceed from the current point to the end of the containing sexp.
If there is no containing sexp that is not the top level defun,
go to the end of the last sexp, or if that is the same point, then step."
(interactive)
(condition-case nil
(let ((parse-sexp-ignore-comments t))
(up-list 1)
(save-excursion
(up-list 1))
(edebug-go-mode t))
(error
(let ((start-point (point)))
(down-list -1)
(if (= (point) start-point)
(edebug-step-mode) (edebug-go-mode t)
)))))
(defun edebug-instrument-function (func)
(let ((func-marker (get func 'edebug)))
(cond
((markerp func-marker)
(with-current-buffer (marker-buffer func-marker)
(goto-char func-marker)
(edebug-eval-top-level-form)
func))
((consp func-marker)
(message "%s is already instrumented." func)
func)
(t
(let ((loc (find-function-noselect func)))
(unless (cdr loc)
(error "Could not find the definition in its file"))
(with-current-buffer (car loc)
(goto-char (cdr loc))
(edebug-eval-top-level-form)
func))))))
(defun edebug-instrument-callee ()
"Instrument the definition of the function or macro about to be called.
Do this when stopped before the form or it will be too late.
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 "\("))
(error "You must be before a list form")
(let ((func
(save-excursion
(down-list 1)
(if (looking-at "\(")
(edebug-form-data-name
(edebug-get-form-data-entry (point)))
(edebug-original-read (current-buffer))))))
(edebug-instrument-function func))))
(defun edebug-step-in ()
"Step into the definition of the function or macro about to be called.
This first does `edebug-instrument-callee' to ensure that it is
instrumented. Then it does `edebug-on-entry' and switches to `go' mode."
(interactive)
(let ((func (edebug-instrument-callee)))
(if func
(progn
(edebug-on-entry func 'temp)
(edebug-go-mode nil)))))
(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."
(interactive "aEdebug on entry to: \nP")
(put function 'edebug-on-entry (if flag 'temp t)))
(defun cancel-edebug-on-entry (function)
(interactive "aEdebug on entry to: ")
(put function 'edebug-on-entry nil))
(if (not (fboundp 'edebug-original-debug-on-entry))
(fset 'edebug-original-debug-on-entry (symbol-function 'debug-on-entry)))
'(fset 'debug-on-entry 'edebug-debug-on-entry)
'(defun edebug-debug-on-entry (function)
"Request FUNCTION to invoke debugger each time it is called.
If the user continues, FUNCTION's execution proceeds.
Works by modifying the definition of FUNCTION,
which must be written in Lisp, not predefined.
Use `cancel-debug-on-entry' to cancel the effect of this command.
Redefining FUNCTION also does that.
This version is from Edebug. If the function is instrumented for
Edebug, it calls `edebug-on-entry'."
(interactive "aDebug on entry (to function): ")
(let ((func-data (get function 'edebug)))
(if (or (null func-data) (markerp func-data))
(edebug-original-debug-on-entry function)
(edebug-on-entry function))))
(defun edebug-top-level-nonstop ()
"Set mode to Go-nonstop, and exit to top-level.
This is useful for exiting even if unwind-protect code may be executed."
(interactive)
(setq edebug-execution-mode 'Go-nonstop)
(top-level))
'(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)
)
"Association list between commands and the modes they set.")
'(defun edebug-set-initial-mode ()
"Ask for the initial mode of the enclosing function.
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))
(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))))
(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")
)))
(def-edebug-spec edebug-outside-excursion t)
(defmacro edebug-outside-excursion (&rest body)
"Evaluate an expression list in the outside context.
Return the result of the last expression."
`(save-excursion (if edebug-save-windows
(progn
(setq edebug-inside-windows
(edebug-current-windows edebug-save-windows))
(edebug-set-windows edebug-outside-windows)))
(set-buffer edebug-buffer) (set-match-data edebug-outside-match-data)
(let ( (last-command-char edebug-outside-last-command-char)
(last-command-event edebug-outside-last-command-event)
(last-command edebug-outside-last-command)
(this-command edebug-outside-this-command)
(unread-command-char edebug-outside-unread-command-char)
(unread-command-events edebug-outside-unread-command-events)
(current-prefix-arg edebug-outside-current-prefix-arg)
(last-input-char edebug-outside-last-input-char)
(last-input-event edebug-outside-last-input-event)
(last-event-frame edebug-outside-last-event-frame)
(last-nonmenu-event edebug-outside-last-nonmenu-event)
(track-mouse edebug-outside-track-mouse)
(standard-output edebug-outside-standard-output)
(standard-input edebug-outside-standard-input)
(executing-kbd-macro edebug-outside-executing-macro)
(defining-kbd-macro edebug-outside-defining-kbd-macro)
(pre-command-hook (cdr edebug-outside-pre-command-hook))
(post-command-hook (cdr edebug-outside-post-command-hook))
(overlay-arrow-position edebug-outside-o-a-p)
(overlay-arrow-string edebug-outside-o-a-s)
(cursor-in-echo-area edebug-outside-c-i-e-a)
(default-cursor-in-non-selected-windows edebug-outside-d-c-i-n-s-w)
)
(unwind-protect
(save-excursion (set-buffer edebug-outside-buffer)
(goto-char edebug-outside-point)
(if (marker-buffer (edebug-mark-marker))
(set-marker (edebug-mark-marker) edebug-outside-mark))
,@body)
(if edebug-save-windows
(edebug-set-windows edebug-inside-windows))
(setq
edebug-outside-last-command-char last-command-char
edebug-outside-last-command-event last-command-event
edebug-outside-last-command last-command
edebug-outside-this-command this-command
edebug-outside-unread-command-char unread-command-char
edebug-outside-unread-command-events unread-command-events
edebug-outside-current-prefix-arg current-prefix-arg
edebug-outside-last-input-char last-input-char
edebug-outside-last-input-event last-input-event
edebug-outside-last-event-frame last-event-frame
edebug-outside-last-nonmenu-event last-nonmenu-event
edebug-outside-track-mouse track-mouse
edebug-outside-standard-output standard-output
edebug-outside-standard-input standard-input
edebug-outside-executing-macro executing-kbd-macro
edebug-outside-defining-kbd-macro defining-kbd-macro
edebug-outside-o-a-p overlay-arrow-position
edebug-outside-o-a-s overlay-arrow-string
edebug-outside-c-i-e-a cursor-in-echo-area
edebug-outside-d-c-i-n-s-w default-cursor-in-non-selected-windows
)
(setcdr edebug-outside-pre-command-hook pre-command-hook)
(setcdr edebug-outside-post-command-hook post-command-hook)
)) ))
(defvar cl-debug-env nil)
(defun edebug-eval (edebug-expr)
(if cl-debug-env
(eval (cl-macroexpand-all edebug-expr cl-debug-env))
(eval edebug-expr)))
(defun edebug-safe-eval (edebug-expr)
(condition-case edebug-err
(edebug-eval edebug-expr)
(error (edebug-format "%s: %s" (get (car edebug-err) 'error-message)
(car (cdr edebug-err))))))
(define-obsolete-function-alias 'edebug-install-custom-print-funcs
'edebug-install-custom-print "22.1")
(define-obsolete-function-alias 'edebug-reset-print-funcs
'edebug-uninstall-custom-print "22.1")
(define-obsolete-function-alias 'edebug-uninstall-custom-print-funcs
'edebug-uninstall-custom-print "22.1")
(defun edebug-install-custom-print ()
"Replace print functions used by Edebug with custom versions."
(interactive)
(require 'cust-print)
(defalias 'edebug-prin1 'custom-prin1)
(defalias 'edebug-print 'custom-print)
(defalias 'edebug-prin1-to-string 'custom-prin1-to-string)
(defalias 'edebug-format 'custom-format)
(defalias 'edebug-message 'custom-message)
"Installed")
(eval-and-compile
(defun edebug-uninstall-custom-print ()
"Replace edebug custom print functions with internal versions."
(interactive)
(defalias 'edebug-prin1 'prin1)
(defalias 'edebug-print 'print)
(defalias 'edebug-prin1-to-string 'prin1-to-string)
(defalias 'edebug-format 'format)
(defalias 'edebug-message 'message)
"Uninstalled")
(edebug-uninstall-custom-print))
(defun edebug-report-error (edebug-value)
(message "%s: %s"
(or (get (car edebug-value) 'error-message)
(format "peculiar error (%s)" (car edebug-value)))
(mapconcat (function (lambda (edebug-arg)
(prin1-to-string edebug-arg)))
(cdr edebug-value) ", ")))
(defvar print-level nil)
(defvar print-circle nil)
(defvar print-readably)
(defun edebug-safe-prin1-to-string (value)
(let ((print-escape-newlines t)
(print-length (or edebug-print-length print-length))
(print-level (or edebug-print-level print-level))
(print-circle (or edebug-print-circle print-circle))
(print-readably nil)) (condition-case nil
(edebug-prin1-to-string value)
(error "#Apparently circular structure#"))))
(defun edebug-compute-previous-result (edebug-previous-value)
(if edebug-unwrap-results
(setq edebug-previous-value
(edebug-unwrap* edebug-previous-value)))
(setq edebug-previous-result
(concat "Result: "
(edebug-safe-prin1-to-string edebug-previous-value)
(eval-expression-print-format edebug-previous-value))))
(defun edebug-previous-result ()
"Print the previous result."
(interactive)
(message "%s" edebug-previous-result))
(defun edebug-eval-expression (edebug-expr)
"Evaluate an expression in the outside environment.
If interactive, prompt for the expression.
Print result in minibuffer."
(interactive (list (read-from-minibuffer
"Eval: " nil read-expression-map t
'read-expression-history)))
(princ
(edebug-outside-excursion
(setq values (cons (edebug-eval edebug-expr) values))
(concat (edebug-safe-prin1-to-string (car values))
(eval-expression-print-format (car values))))))
(defun edebug-eval-last-sexp ()
"Evaluate sexp before point in the outside environment.
Print value in minibuffer."
(interactive)
(edebug-eval-expression (edebug-last-sexp)))
(defun edebug-eval-print-last-sexp ()
"Evaluate sexp before point in outside environment; insert value.
This prints the value into current buffer."
(interactive)
(let* ((edebug-form (edebug-last-sexp))
(edebug-result-string
(edebug-outside-excursion
(edebug-safe-prin1-to-string (edebug-safe-eval edebug-form))))
(standard-output (current-buffer)))
(princ "\n")
(princ edebug-result-string)
(princ "\n")
))
(defvar gud-inhibit-global-bindings
"*Non-nil means don't do global rebindings of C-x C-a subcommands.")
(unless gud-inhibit-global-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)
(define-key emacs-lisp-mode-map "\C-x\C-a\C-l" 'edebug-where))
(defvar edebug-mode-map
(let ((map (copy-keymap emacs-lisp-mode-map)))
(define-key map " " 'edebug-step-mode)
(define-key map "n" 'edebug-next-mode)
(define-key map "g" 'edebug-go-mode)
(define-key map "G" 'edebug-Go-nonstop-mode)
(define-key map "t" 'edebug-trace-mode)
(define-key map "T" 'edebug-Trace-fast-mode)
(define-key map "c" 'edebug-continue-mode)
(define-key map "C" 'edebug-Continue-fast-mode)
(define-key map "f" 'edebug-forward-sexp)
(define-key map "h" 'edebug-goto-here)
(define-key map "I" 'edebug-instrument-callee)
(define-key map "i" 'edebug-step-in)
(define-key map "o" 'edebug-step-out)
(define-key map "q" 'top-level)
(define-key map "Q" 'edebug-top-level-nonstop)
(define-key map "a" 'abort-recursive-edit)
(define-key map "S" 'edebug-stop)
(define-key map "b" 'edebug-set-breakpoint)
(define-key map "u" 'edebug-unset-breakpoint)
(define-key map "B" 'edebug-next-breakpoint)
(define-key map "x" 'edebug-set-conditional-breakpoint)
(define-key map "X" 'edebug-set-global-break-condition)
(define-key map "r" 'edebug-previous-result)
(define-key map "e" 'edebug-eval-expression)
(define-key map "\C-x\C-e" 'edebug-eval-last-sexp)
(define-key map "E" 'edebug-visit-eval-list)
(define-key map "w" 'edebug-where)
(define-key map "v" 'edebug-view-outside) (define-key map "p" 'edebug-bounce-point)
(define-key map "P" 'edebug-view-outside) (define-key map "W" 'edebug-toggle-save-windows)
(define-key map "?" 'edebug-help)
(define-key map "d" 'edebug-backtrace)
(define-key map "-" 'negative-argument)
(define-key map "=" 'edebug-temp-display-freq-count)
(define-key map "\C-c\C-s" 'edebug-step-mode)
(define-key map "\C-c\C-n" 'edebug-next-mode)
(define-key map "\C-c\C-c" 'edebug-go-mode)
(define-key map "\C-x " 'edebug-set-breakpoint)
(define-key map "\C-c\C-d" 'edebug-unset-breakpoint)
(define-key map "\C-c\C-t"
(lambda () (interactive) (edebug-set-breakpoint t)))
(define-key map "\C-c\C-l" 'edebug-where)
map))
(defvar global-edebug-prefix "\^XX"
"Prefix key for global edebug commands, available from any buffer.")
(defvar global-edebug-map
(let ((map (make-sparse-keymap)))
(define-key map " " 'edebug-step-mode)
(define-key map "g" 'edebug-go-mode)
(define-key map "G" 'edebug-Go-nonstop-mode)
(define-key map "t" 'edebug-trace-mode)
(define-key map "T" 'edebug-Trace-fast-mode)
(define-key map "c" 'edebug-continue-mode)
(define-key map "C" 'edebug-Continue-fast-mode)
(define-key map "b" 'edebug-set-breakpoint)
(define-key map "u" 'edebug-unset-breakpoint)
(define-key map "x" 'edebug-set-conditional-breakpoint)
(define-key map "X" 'edebug-set-global-break-condition)
(define-key map "w" 'edebug-where)
(define-key map "W" 'edebug-toggle-save-windows)
(define-key map "q" 'top-level)
(define-key map "Q" 'edebug-top-level-nonstop)
(define-key map "a" 'abort-recursive-edit)
(define-key map "=" 'edebug-display-freq-count)
map)
"Global map of edebug commands, available from any buffer.")
(global-unset-key global-edebug-prefix)
(global-set-key global-edebug-prefix global-edebug-map)
(defun edebug-help ()
(interactive)
(describe-function 'edebug-mode))
(defun edebug-mode ()
"Mode for Emacs Lisp buffers while in Edebug.
In addition to all Emacs Lisp commands (except those that modify the
buffer) there are local and global key bindings to several Edebug
specific commands. E.g. `edebug-step-mode' is bound to \\[edebug-step-mode]
in the Edebug buffer and \\<global-map>\\[edebug-step-mode] in any buffer.
Also see bindings for the eval list buffer *edebug* in `edebug-eval-mode'.
The edebug buffer commands:
\\{edebug-mode-map}
Global commands prefixed by `global-edebug-prefix':
\\{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
"
(add-hook 'kill-buffer-hook 'edebug-kill-buffer nil t)
(use-local-map edebug-mode-map))
(defun edebug-kill-buffer ()
"Used on `kill-buffer-hook' when Edebug is operating in a buffer of Lisp code."
(let (kill-buffer-hook)
(kill-buffer (current-buffer)))
(top-level))
(defun edebug-eval-result-list ()
"Return a list of evaluations of edebug-eval-list"
(let ((edebug-execution-mode 'Go-nonstop)
(edebug-trace nil))
(mapcar 'edebug-safe-eval edebug-eval-list)))
(defun edebug-eval-display-list (edebug-eval-result-list)
(let ((edebug-eval-list-temp edebug-eval-list)
(standard-output edebug-eval-buffer)
(edebug-comment-line
(format ";%s\n" (make-string (- (window-width) 2) ?-))))
(set-buffer edebug-eval-buffer)
(erase-buffer)
(while edebug-eval-list-temp
(prin1 (car edebug-eval-list-temp)) (terpri)
(prin1 (car edebug-eval-result-list)) (terpri)
(princ edebug-comment-line)
(setq edebug-eval-list-temp (cdr edebug-eval-list-temp))
(setq edebug-eval-result-list (cdr edebug-eval-result-list)))
(edebug-pop-to-buffer edebug-eval-buffer)
))
(defun edebug-create-eval-buffer ()
(if (not (and edebug-eval-buffer (buffer-name edebug-eval-buffer)))
(progn
(set-buffer (setq edebug-eval-buffer (get-buffer-create "*edebug*")))
(edebug-eval-mode))))
(defun edebug-eval-display (edebug-eval-result-list)
"Display expressions and evaluations in EVAL-LIST.
It modifies the context by popping up the eval display."
(if edebug-eval-result-list
(progn
(edebug-create-eval-buffer)
(edebug-eval-display-list edebug-eval-result-list)
)))
(defun edebug-eval-redisplay ()
"Redisplay eval list in outside environment.
May only be called from within edebug-recursive-edit."
(edebug-create-eval-buffer)
(edebug-outside-excursion
(edebug-eval-display-list (edebug-eval-result-list))
))
(defun edebug-visit-eval-list ()
(interactive)
(edebug-eval-redisplay)
(edebug-pop-to-buffer edebug-eval-buffer))
(defun edebug-update-eval-list ()
"Replace the evaluation list with the sexps now in the eval buffer."
(interactive)
(let ((starting-point (point))
new-list)
(goto-char (point-min))
(edebug-skip-whitespace)
(if (not (eobp))
(progn
(forward-sexp 1)
(setq new-list (cons (edebug-last-sexp) new-list))))
(while (re-search-forward "^;" nil t)
(forward-line 1)
(skip-chars-forward " \t\n\r")
(if (and (/= ?\ (not (eobp)))
(progn
(forward-sexp 1)
(setq new-list (cons (edebug-last-sexp) new-list)))))
(setq edebug-eval-list (nreverse new-list))
(edebug-eval-redisplay)
(goto-char starting-point)))
(defun edebug-delete-eval-item ()
"Delete the item under point and redisplay."
(interactive)
(if (re-search-backward "^;" nil 'nofail)
(forward-line 1))
(delete-region
(point) (progn (re-search-forward "^;" nil 'nofail)
(beginning-of-line)
(point)))
(edebug-update-eval-list))
(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))
(put 'edebug-eval-mode 'mode-class 'special)
(define-derived-mode edebug-eval-mode lisp-interaction-mode "Edebug Eval"
"Mode for evaluation list buffer while in Edebug.
In addition to all Interactive Emacs Lisp commands there are local and
global key bindings to several Edebug specific commands. E.g.
`edebug-step-mode' is bound to \\[edebug-step-mode] in the Edebug
buffer and \\<global-map>\\[edebug-step-mode] in any buffer.
Eval list buffer commands:
\\{edebug-eval-mode-map}
Global commands prefixed by `global-edebug-prefix':
\\{global-edebug-map}")
(defun edebug (&optional edebug-arg-mode &rest debugger-args)
"Replacement for debug.
If we are running an edebugged function,
show where we last were. Otherwise call debug normally."
(if (and edebug-entered (eq (recursion-depth) edebug-recursion-depth))
(let ( (edebug-offset-index (car edebug-offset-indices))
(edebug-value (car debugger-args))
edebug-breakpoints
edebug-break-data
edebug-break-condition
edebug-global-break
(edebug-break (null edebug-arg-mode)) )
(edebug-display)
(if (eq edebug-arg-mode 'error)
nil
edebug-value))
(apply 'debug edebug-arg-mode debugger-args)
))
(defun edebug-backtrace ()
"Display a non-working backtrace. Better than nothing..."
(interactive)
(if (or (not edebug-backtrace-buffer)
(null (buffer-name edebug-backtrace-buffer)))
(setq edebug-backtrace-buffer
(generate-new-buffer "*Backtrace*"))
)
(with-output-to-temp-buffer (buffer-name edebug-backtrace-buffer)
(setq edebug-backtrace-buffer standard-output)
(let ((print-escape-newlines t)
(print-length 50)
last-ok-point)
(backtrace)
(set-buffer edebug-backtrace-buffer)
(setq truncate-lines t)
(goto-char (point-min))
(setq last-ok-point (point))
(if t (progn
(while (re-search-forward "^ \(?edebug" nil t)
(beginning-of-line)
(cond
((looking-at "^ \(edebug-after")
(setq last-ok-point (point))
(forward-line 1)
(delete-region last-ok-point (point)))
((looking-at "^ edebug")
(forward-line 1)
(delete-region last-ok-point (point))
)))
)))))
(defun edebug-trace-display (buf-name fmt &rest args)
"In buffer BUF-NAME, display FMT and ARGS at the end and make it visible.
The buffer is created if it does not exist.
You must include newlines in FMT to break lines, but one newline is appended."
(let* ((oldbuf (current-buffer))
(selected-window (selected-window))
(buffer (get-buffer-create buf-name))
buf-window)
(edebug-pop-to-buffer buffer)
(setq truncate-lines t)
(setq buf-window (selected-window))
(goto-char (point-max))
(insert (apply 'edebug-format fmt args) "\n")
(vertical-motion (- 1 (window-height)))
(set-window-start buf-window (point))
(goto-char (point-max))
(bury-buffer buffer)
(select-window selected-window)
(set-buffer oldbuf))
buf-name)
(defun edebug-trace (fmt &rest args)
"Convenience call to edebug-trace-display using edebug-trace-buffer"
(apply 'edebug-trace-display edebug-trace-buffer fmt args))
(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, and you can undo all insertions with one `undo' command.
The counts are inserted starting under the `(' before an expression
or the `)' after an expression, or on the last char of a symbol.
The counts are only displayed when they differ from previous counts on
the same line.
If coverage is being tested, whenever all known results of an expression
are `eq', the char `=' will be appended after the count
for that expression. Note that this is always the case for an
expression only evaluated once.
To clear the frequency count and coverage data for a definition,
reinstrument it."
(interactive)
(let* ((function (edebug-form-data-symbol))
(counts (get function 'edebug-freq-count))
(coverages (get function 'edebug-coverage))
(data (get function 'edebug))
(def-mark (car data)) (edebug-points (nth 2 data))
(i (1- (length edebug-points)))
(last-index)
(first-index)
(start-of-line)
(start-of-count-line)
(last-count)
)
(save-excursion
(while (<= 0 i)
(goto-char (+ def-mark (aref edebug-points i)))
(beginning-of-line)
(setq start-of-line (- (point) def-mark)
last-index i)
(while (and (<= 0 (setq i (1- i)))
(<= start-of-line (aref edebug-points i))))
(forward-line 1)
(setq start-of-count-line (point)
first-index i last-count -1) (insert ";#")
(while (<= (setq i (1+ i)) last-index)
(let ((count (aref counts i))
(coverage (aref coverages i))
(col (save-excursion
(goto-char (+ (aref edebug-points i) def-mark))
(- (current-column)
(if (= ?\( (following-char)) 0 1)))))
(insert (make-string
(max 0 (- col (- (point) start-of-count-line))) ?\s)
(if (and (< 0 count)
(not (memq coverage
'(unknown ok-coverage))))
"=" "")
(if (= count last-count) "" (int-to-string count))
" ")
(setq last-count count)))
(insert "\n")
(setq i first-index)))))
(defun edebug-temp-display-freq-count ()
"Temporarily display the frequency count data for the current definition.
It is removed when you hit any char."
(interactive)
(let ((buffer-read-only nil))
(undo-boundary)
(edebug-display-freq-count)
(setq unread-command-char (read-char))
(undo)))
(defun edebug-toggle (variable)
(set variable (not (eval variable)))
(message "%s: %s" variable (eval variable)))
(require 'easymenu)
(defconst edebug-mode-menus
'("Edebug"
["Stop" edebug-stop t]
["Step" edebug-step-mode t]
["Next" edebug-next-mode t]
["Trace" edebug-trace-mode t]
["Trace Fast" edebug-Trace-fast-mode t]
["Continue" edebug-continue-mode t]
["Continue Fast" edebug-Continue-fast-mode t]
["Go" edebug-go-mode t]
["Go Nonstop" edebug-Go-nonstop-mode t]
"----"
["Help" edebug-help t]
["Abort" abort-recursive-edit t]
["Quit to Top Level" top-level t]
["Quit Nonstop" edebug-top-level-nonstop t]
"----"
("Jumps"
["Forward Sexp" edebug-forward-sexp t]
["Step In" edebug-step-in t]
["Step Out" edebug-step-out t]
["Goto Here" edebug-goto-here t])
("Breaks"
["Set Breakpoint" edebug-set-breakpoint t]
["Unset Breakpoint" edebug-unset-breakpoint t]
["Set Conditional Breakpoint" edebug-set-conditional-breakpoint t]
["Set Global Break Condition" edebug-set-global-break-condition t]
["Show Next Breakpoint" edebug-next-breakpoint t])
("Views"
["Where am I?" edebug-where t]
["Bounce to Current Point" edebug-bounce-point t]
["View Outside Windows" edebug-view-outside t]
["Previous Result" edebug-previous-result t]
["Show Backtrace" edebug-backtrace t]
["Display Freq Count" edebug-display-freq-count t])
("Eval"
["Expression" edebug-eval-expression t]
["Last Sexp" edebug-eval-last-sexp t]
["Visit Eval List" edebug-visit-eval-list t])
("Options"
["Edebug All Defs" edebug-all-defs
:style toggle :selected edebug-all-defs]
["Edebug All Forms" edebug-all-forms
:style toggle :selected edebug-all-forms]
"----"
["Tracing" (edebug-toggle 'edebug-trace)
:style toggle :selected edebug-trace]
["Test Coverage" (edebug-toggle 'edebug-test-coverage)
:style toggle :selected edebug-test-coverage]
["Save Windows" edebug-toggle-save-windows
:style toggle :selected edebug-save-windows]
["Save Point"
(edebug-toggle 'edebug-save-displayed-buffer-points)
:style toggle :selected edebug-save-displayed-buffer-points]
))
"Menus for Edebug.")
(defalias 'edebug-window-live-p 'window-live-p)
(defun edebug-mark ()
(mark t))
(defun edebug-set-conditional-breakpoint (arg condition)
"Set a conditional breakpoint at nearest sexp.
The condition is evaluated in the outside context.
With prefix argument, make it a temporary breakpoint."
(interactive
(list
current-prefix-arg
(let ((edebug-stop-point (edebug-find-stop-point)))
(if edebug-stop-point
(let* ((edebug-def-name (car edebug-stop-point))
(index (cdr edebug-stop-point))
(edebug-data (get edebug-def-name 'edebug))
(edebug-breakpoints (car (cdr edebug-data)))
(edebug-break-data (assq index edebug-breakpoints))
(edebug-break-condition (car (cdr edebug-break-data)))
(initial (and edebug-break-condition
(format "%s" edebug-break-condition))))
(read-from-minibuffer
"Condition: " initial read-expression-map t
(if (equal (car read-expression-history) initial)
'(read-expression-history . 1)
'read-expression-history)))))))
(edebug-modify-breakpoint t condition arg))
(easy-menu-define edebug-menu edebug-mode-map "Edebug menus" edebug-mode-menus)
(eval-when-compile
(if edebug-unread-command-char-warning
(put 'unread-command-char 'byte-obsolete-variable
edebug-unread-command-char-warning)))
(eval-when-compile
(if (featurep 'byte-compile) (progn
(defun byte-compile-resolve-functions (funcs)
"Say it is OK for the named functions to be unresolved."
(mapcar
(function
(lambda (func)
(setq byte-compile-unresolved-functions
(delq (assq func byte-compile-unresolved-functions)
byte-compile-unresolved-functions))))
funcs)
nil)
'(defun byte-compile-resolve-free-references (vars)
"Say it is OK for the named variables to be referenced."
(mapcar
(function
(lambda (var)
(setq byte-compile-free-references
(delq var byte-compile-free-references))))
vars)
nil)
'(defun byte-compile-resolve-free-assignments (vars)
"Say it is OK for the named variables to be assigned."
(mapcar
(function
(lambda (var)
(setq byte-compile-free-assignments
(delq var byte-compile-free-assignments))))
vars)
nil)
(byte-compile-resolve-functions
'(reporter-submit-bug-report
edebug-gensym edebug-original-eval-defun
edebug-original-read
edebug-get-buffer-window
edebug-mark
edebug-mark-marker
edebug-input-pending-p
edebug-sit-for
edebug-prin1-to-string
edebug-format
zmacs-deactivate-region
popup-menu
cl-macroexpand-all
byte-compile-resolve-functions
))
'(byte-compile-resolve-free-references
'(read-expression-history
read-expression-map))
'(byte-compile-resolve-free-assignments
'(read-expression-history))
)))
(if (featurep 'cl)
(add-hook 'edebug-setup-hook
(function (lambda () (require 'cl-specs))))
(add-hook 'cl-load-hook
(function (lambda () (require 'cl-specs)))))
(if (featurep 'cl-read)
(add-hook 'edebug-setup-hook
(function (lambda () (require 'edebug-cl-read))))
(add-hook 'cl-read-load-hooks
(function (lambda () (require 'edebug-cl-read)))))
(edebug-install-read-eval-functions)
(provide 'edebug)