]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/edebug.el
merge trunk
[gnu-emacs] / lisp / emacs-lisp / edebug.el
index e3888db2a57d2007a99e3bccfeb9d7ee4c29bc37..867f079ce5f609459eb8094348cd9109fe1b9d0c 100644 (file)
@@ -54,6 +54,7 @@
 
 (require 'macroexp)
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'pcase))
 
 ;;; Options
 
@@ -461,8 +462,8 @@ STREAM or the value of `standard-input' may be:
 
 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'."
+also dependent on the values of the option `edebug-all-defs' and
+the option `edebug-all-forms'."
   (or stream (setq stream standard-input))
   (if (eq stream (current-buffer))
       (edebug-read-and-maybe-wrap-form)
@@ -484,8 +485,8 @@ 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
+Setting option `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,
@@ -2072,11 +2073,6 @@ expressions; a `progn' form will be returned enclosing these forms."
 
 (defvar edebug-active nil)  ;; Non-nil when edebug is active
 
-;;; add minor-mode-alist entry
-(or (assq 'edebug-active minor-mode-alist)
-    (setq minor-mode-alist (cons (list 'edebug-active " *Debugging*")
-                                minor-mode-alist)))
-
 (defvar edebug-stack nil)
 ;; Stack of active functions evaluated via edebug.
 ;; Should be nil at the top level.
@@ -2715,8 +2711,7 @@ MSG is printed after `::::} '."
   ;; Start up a recursive edit inside of edebug.
   ;; The current buffer is the edebug-buffer, which is put into edebug-mode.
   ;; Assume that none of the variables below are buffer-local.
-  (let ((edebug-buffer-read-only buffer-read-only)
-       ;; match-data must be done in the outside buffer
+  (let (;; match-data must be done in the outside buffer
        (edebug-outside-match-data
         (with-current-buffer edebug-outside-buffer ; in case match buffer different
           (match-data)))
@@ -2730,8 +2725,6 @@ MSG is printed after `::::} '."
        ;; during a recursive-edit
        edebug-inside-windows
 
-       (edebug-outside-map (current-local-map))
-
         ;; Save the outside value of executing macro.  (here??)
         (edebug-outside-executing-macro executing-kbd-macro)
         (edebug-outside-pre-command-hook
@@ -2804,10 +2797,9 @@ MSG is printed after `::::} '."
                   (not (memq arg-mode '(after error))))
              (message "Break"))
 
-         (setq buffer-read-only t)
          (setq signal-hook-function nil)
 
-         (edebug-mode)
+         (edebug-mode 1)
          (unwind-protect
              (recursive-edit)          ;  <<<<<<<<<< Recursive edit
 
@@ -2828,10 +2820,7 @@ MSG is printed after `::::} '."
                  (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)
-                 )
+                  (edebug-mode -1))
              ;; gotta have a buffer to let its buffer local variables be set
              (get-buffer-create " bogus edebug buffer"))
            ));; inner let
@@ -3773,7 +3762,9 @@ be installed in `emacs-lisp-mode-map'.")
   (interactive)
   (describe-function 'edebug-mode))
 
-(defun edebug-mode ()
+(defvar edebug--mode-saved-vars nil)
+
+(define-minor-mode edebug-mode
   "Mode for Emacs Lisp buffers while in Edebug.
 
 In addition to all Emacs Lisp commands (except those that modify the
@@ -3807,17 +3798,32 @@ Options:
 `edebug-on-signal'
 `edebug-unwrap-results'
 `edebug-global-break-condition'"
+  :lighter " *Debugging*"
+  :keymap edebug-mode-map
   ;; If the user kills the buffer in which edebug is currently active,
   ;; exit to top level, because the edebug command loop can't usefully
   ;; continue running in such a case.
-  (add-hook 'kill-buffer-hook 'edebug-kill-buffer nil t)
-  (use-local-map edebug-mode-map))
+  ;;
+  (if (not edebug-mode)
+      (progn
+        (while edebug--mode-saved-vars
+          (let ((setting (pop edebug--mode-saved-vars)))
+            (if (consp setting)
+                (set (car setting) (cdr setting))
+              (kill-local-variable setting))))
+        (remove-hook 'kill-buffer-hook 'edebug-kill-buffer t))
+    (pcase-dolist (`(,var . ,val) '((buffer-read-only . t)))
+      (push
+       (if (local-variable-p var) (cons var (symbol-value var)) var)
+       edebug--mode-saved-vars)
+      (set (make-local-variable var) val))
+    ;; Append `edebug-kill-buffer' to the hook to avoid interfering with
+    ;; other entries that are unguarded against deleted buffer.
+    (add-hook 'kill-buffer-hook 'edebug-kill-buffer t t)))
 
 (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))
+  (run-with-timer 0 nil #'top-level))
 
 ;;; edebug eval list mode
 
@@ -4140,7 +4146,7 @@ reinstrument it."
 It is removed when you hit any char."
   ;; This seems not to work with Emacs 18.59. It undoes too far.
   (interactive)
-  (let ((buffer-read-only nil))
+  (let ((inhibit-read-only t))
     (undo-boundary)
     (edebug-display-freq-count)
     (setq unread-command-events
@@ -4259,22 +4265,53 @@ With prefix argument, make it a temporary breakpoint."
 ;;; Autoloading of Edebug accessories
 
 ;; edebug-cl-read and cl-read are available from liberte@cs.uiuc.edu
+(defun edebug--require-cl-read ()
+  (require 'edebug-cl-read))
+
 (if (featurep 'cl-read)
-    (add-hook 'edebug-setup-hook
-             (function (lambda () (require 'edebug-cl-read))))
+    (add-hook 'edebug-setup-hook #'edebug--require-cl-read)
   ;; The following causes edebug-cl-read to be loaded when you load cl-read.el.
-  (add-hook 'cl-read-load-hooks
-           (function (lambda () (require 'edebug-cl-read)))))
+  (add-hook 'cl-read-load-hooks #'edebug--require-cl-read))
 
 \f
 ;;; Finalize Loading
 
+;; When edebugging a function, some of the sub-expressions are
+;; wrapped in (edebug-enter (lambda () ..)), so we need to teach
+;; called-interactively-p that calls within the inner lambda should refer to
+;; the outside function.
+(add-hook 'called-interactively-p-functions
+          #'edebug--called-interactively-skip)
+(defun edebug--called-interactively-skip (i frame1 frame2)
+  (when (and (eq (car-safe (nth 1 frame1)) 'lambda)
+             (eq (nth 1 (nth 1 frame1)) '())
+             (eq (nth 1 frame2) 'edebug-enter))
+    ;; `edebug-enter' calls itself on its first invocation.
+    (if (eq (nth 1 (internal--called-interactively-p--get-frame i))
+            'edebug-enter)
+        2 1)))
+
 ;; Finally, hook edebug into the rest of Emacs.
 ;; There are probably some other things that could go here.
 
 ;; Install edebug read and eval functions.
 (edebug-install-read-eval-functions)
 
+(defun edebug-unload-function ()
+  "Unload the Edebug source level debugger."
+  (when edebug-active
+    (setq edebug-active nil)
+    (unwind-protect
+        (abort-recursive-edit)
+      ;; We still want to run unload-feature to completion
+      (run-with-idle-timer 0 nil #'(lambda () (unload-feature 'edebug)))))
+  (remove-hook 'called-interactively-p-functions
+               'edebug--called-interactively-skip)
+  (remove-hook 'cl-read-load-hooks 'edebug--require-cl-read)
+  (edebug-uninstall-read-eval-functions)
+  ;; continue standard unloading
+  nil)
+
 (provide 'edebug)
 
 ;;; edebug.el ends here