diff options
| author | Noam Postavsky | 2015-11-21 16:03:06 -0500 |
|---|---|---|
| committer | Noam Postavsky | 2016-12-02 20:25:14 -0500 |
| commit | cfd2b9eae17754c0e109961f2880f05012a4891d (patch) | |
| tree | 6cae519f21b1f9371e13652720dd0c42c34fd08e | |
| parent | 459a23444e321d25f0b82bede76947576f01ecc3 (diff) | |
| download | emacs-cfd2b9eae17754c0e109961f2880f05012a4891d.tar.gz emacs-cfd2b9eae17754c0e109961f2880f05012a4891d.zip | |
Add function to trigger debugger on variable write
* lisp/emacs-lisp/debug.el (debug-on-variable-change):
(debug--variable-list):
(cancel-debug-on-variable-change): New functions.
(debugger-setup-buffer): Add watchpoint clause.
| -rw-r--r-- | lisp/emacs-lisp/debug.el | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el index 7d273809fcd..5430b72545a 100644 --- a/lisp/emacs-lisp/debug.el +++ b/lisp/emacs-lisp/debug.el | |||
| @@ -306,6 +306,24 @@ That buffer should be current already." | |||
| 306 | (delete-char 1) | 306 | (delete-char 1) |
| 307 | (insert ? ) | 307 | (insert ? ) |
| 308 | (beginning-of-line)) | 308 | (beginning-of-line)) |
| 309 | ;; Watchpoint triggered. | ||
| 310 | ((and `watchpoint (let `(,symbol ,newval . ,details) (cdr args))) | ||
| 311 | (insert | ||
| 312 | "--" | ||
| 313 | (pcase details | ||
| 314 | (`(makunbound nil) (format "making %s void" symbol)) | ||
| 315 | (`(makunbound ,buffer) (format "killing local value of %s in buffer %s" | ||
| 316 | symbol buffer)) | ||
| 317 | (`(defvaralias ,_) (format "aliasing %s to %s" symbol newval)) | ||
| 318 | (`(let ,_) (format "let-binding %s to %S" symbol newval)) | ||
| 319 | (`(unlet ,_) (format "ending let-binding of %s" symbol)) | ||
| 320 | (`(set nil) (format "setting %s to %S" symbol newval)) | ||
| 321 | (`(set ,buffer) (format "setting %s in buffer %s to %S" | ||
| 322 | symbol buffer newval)) | ||
| 323 | (_ (error "unrecognized watchpoint triggered %S" (cdr args)))) | ||
| 324 | ": ") | ||
| 325 | (setq pos (point)) | ||
| 326 | (insert ?\n)) | ||
| 309 | ;; Debugger entered for an error. | 327 | ;; Debugger entered for an error. |
| 310 | (`error | 328 | (`error |
| 311 | (insert "--Lisp error: ") | 329 | (insert "--Lisp error: ") |
| @@ -850,6 +868,79 @@ To specify a nil argument interactively, exit with an empty minibuffer." | |||
| 850 | (princ "Note: if you have redefined a function, then it may no longer\n") | 868 | (princ "Note: if you have redefined a function, then it may no longer\n") |
| 851 | (princ "be set to debug on entry, even if it is in the list.")))))) | 869 | (princ "be set to debug on entry, even if it is in the list.")))))) |
| 852 | 870 | ||
| 871 | (defun debug--implement-debug-watch (symbol newval op where) | ||
| 872 | "Conditionally call the debugger. | ||
| 873 | This function is called when SYMBOL's value is modified." | ||
| 874 | (if (or inhibit-debug-on-entry debugger-jumping-flag) | ||
| 875 | nil | ||
| 876 | (let ((inhibit-debug-on-entry t)) | ||
| 877 | (funcall debugger 'watchpoint symbol newval op where)))) | ||
| 878 | |||
| 879 | ;;;###autoload | ||
| 880 | (defun debug-on-variable-change (variable) | ||
| 881 | "Trigger a debugger invocation when VARIABLE is changed. | ||
| 882 | |||
| 883 | When called interactively, prompt for VARIABLE in the minibuffer. | ||
| 884 | |||
| 885 | This works by calling `add-variable-watch' on VARIABLE. If you | ||
| 886 | quit from the debugger, this will abort the change (unless the | ||
| 887 | change is caused by the termination of a let-binding). | ||
| 888 | |||
| 889 | The watchpoint may be circumvented by C code that changes the | ||
| 890 | variable directly (i.e., not via `set'). Changing the value of | ||
| 891 | the variable (e.g., `setcar' on a list variable) will not trigger | ||
| 892 | watchpoint. | ||
| 893 | |||
| 894 | Use \\[cancel-debug-on-variable-change] to cancel the effect of | ||
| 895 | this command. Uninterning VARIABLE or making it an alias of | ||
| 896 | another symbol also cancels it." | ||
| 897 | (interactive | ||
| 898 | (let* ((var-at-point (variable-at-point)) | ||
| 899 | (var (and (symbolp var-at-point) var-at-point)) | ||
| 900 | (val (completing-read | ||
| 901 | (concat "Debug when setting variable" | ||
| 902 | (if var (format " (default %s): " var) ": ")) | ||
| 903 | obarray #'boundp | ||
| 904 | t nil nil (and var (symbol-name var))))) | ||
| 905 | (list (if (equal val "") var (intern val))))) | ||
| 906 | (add-variable-watcher variable #'debug--implement-debug-watch)) | ||
| 907 | |||
| 908 | ;;;###autoload | ||
| 909 | (defalias 'debug-watch #'debug-on-variable-change) | ||
| 910 | |||
| 911 | |||
| 912 | (defun debug--variable-list () | ||
| 913 | "List of variables currently set for debug on set." | ||
| 914 | (let ((vars '())) | ||
| 915 | (mapatoms | ||
| 916 | (lambda (s) | ||
| 917 | (when (memq #'debug--implement-debug-watch | ||
| 918 | (get s 'watchers)) | ||
| 919 | (push s vars)))) | ||
| 920 | vars)) | ||
| 921 | |||
| 922 | ;;;###autoload | ||
| 923 | (defun cancel-debug-on-variable-change (&optional variable) | ||
| 924 | "Undo effect of \\[debug-on-variable-change] on VARIABLE. | ||
| 925 | If VARIABLE is nil, cancel debug-on-variable-change for all variables. | ||
| 926 | When called interactively, prompt for VARIABLE in the minibuffer. | ||
| 927 | To specify a nil argument interactively, exit with an empty minibuffer." | ||
| 928 | (interactive | ||
| 929 | (list (let ((name | ||
| 930 | (completing-read | ||
| 931 | "Cancel debug on set for variable (default all variables): " | ||
| 932 | (mapcar #'symbol-name (debug--variable-list)) nil t))) | ||
| 933 | (when name | ||
| 934 | (unless (string= name "") | ||
| 935 | (intern name)))))) | ||
| 936 | (if variable | ||
| 937 | (remove-variable-watcher variable #'debug--implement-debug-watch) | ||
| 938 | (message "Canceling debug-watch for all variables") | ||
| 939 | (mapc #'cancel-debug-watch (debug--variable-list)))) | ||
| 940 | |||
| 941 | ;;;###autoload | ||
| 942 | (defalias 'cancel-debug-watch #'cancel-debug-on-variable-change) | ||
| 943 | |||
| 853 | (provide 'debug) | 944 | (provide 'debug) |
| 854 | 945 | ||
| 855 | ;;; debug.el ends here | 946 | ;;; debug.el ends here |