diff --git a/lisp/doom-lib.el b/lisp/doom-lib.el index 3e1405d02..93522af63 100644 --- a/lisp/doom-lib.el +++ b/lisp/doom-lib.el @@ -246,7 +246,7 @@ unreadable. Returns the names of envvars that were changed." (defun doom-run-hook (hook) "Run HOOK (a hook function) with better error handling. Meant to be used with `run-hook-wrapped'." - (doom-log "hook:%s: run %s" (or doom--hook '*) hook) + (doom-log 2 "hook:%s: run %s" (or doom--hook '*) hook) (condition-case-unless-debug e (funcall hook) (error @@ -313,7 +313,7 @@ TRIGGER-HOOK is a list of quoted hooks and/or sharp-quoted functions." (with-memoization (get 'doom-compile-function 'timer) (run-with-idle-timer 1.5 t (fn! (when-let (fn (pop fns)) - (doom-log "compile-functions: %s" fn) + (doom-log 3 "compile-functions: %s" fn) (or (if (featurep 'native-compile) (or (subr-native-elisp-p (indirect-function fn)) (ignore-errors (native-compile fn)))) @@ -1170,7 +1170,7 @@ Never set this variable directly, use `with-doom-module'.") (if key (doom-module-context key) (make-doom-module-context))))) - (doom-log ":context:module: =%s" doom-module-context) + (doom-log 2 ":context:module: =%s" doom-module-context) ,@body)) (defun doom-module-context (key) diff --git a/lisp/lib/debug.el b/lisp/lib/debug.el index cc30606e6..30d48c452 100644 --- a/lisp/lib/debug.el +++ b/lisp/lib/debug.el @@ -6,85 +6,120 @@ ;;; Doom's debug mode ;;;###autoload -(defvar doom-debug-variables +(defvar doom-debug--variables `(;; Doom variables (doom-print-minimum-level . debug) (doom-inhibit-log . nil) - (doom-log-level . 2) ;; Emacs variables - async-debug + (async-debug t 2) debug-on-error - gcmh-verbose + (gcmh-verbose t 3) init-file-debug - jka-compr-verbose - (message-log-max . 16384) - (native-comp-async-report-warnings-errors . silent) - (native-comp-warning-on-missing-source . t) + (jka-compr-verbose t 3) + (message-log-max 16384) + (native-comp-async-report-warnings-errors silent 2) + (native-comp-warning-on-missing-source t 2) url-debug use-package-verbose - (warning-suppress-types . nil)) - "A list of variable to toggle on `doom-debug-mode'. + (warning-suppress-types nil))) -Each entry can be a variable symbol or a cons cell whose CAR is the variable -symbol and CDR is the value to set it to when `doom-debug-mode' is activated.") +;;;###autoload +(progn + (cl-defun set-debug-variable! (var &optional (debug-val t) (level 1)) + "Set VAR to DEBUG-VAL (or `t') when `doom-debug-mode' is active at >=LEVEL." + (setf (alist-get var doom-debug--variables) (cons debug-val level)))) -(defvar doom-debug--unbound-vars nil) +(defvar doom-debug--unbound-variables nil) (defun doom-debug--watch-vars-h (&rest _) - (when-let (vars (copy-sequence doom-debug--unbound-vars)) - (setq doom-debug--unbound-vars nil) + (when-let* ((vars (copy-sequence doom-debug--unbound-variables))) + (setq doom-debug--unbound-variables nil) (mapc #'doom-debug--set-var vars))) (defun doom-debug--set-var (spec) (cond ((listp spec) - (pcase-let ((`(,var . ,val) spec)) + (pcase-let ((`(,var ,val ,level) spec)) (if (boundp var) (set-default - var (if (not doom-debug-mode) + var (if (or (not doom-debug-mode) + (> (or level 1) doom-log-level)) (prog1 (get var 'initial-value) (put var 'initial-value nil)) - (doom-log "debug:vars: %s = %S" var (default-toplevel-value var)) + (doom-log 3 "debug:vars: %s = %S" var (default-toplevel-value var)) (put var 'initial-value (default-toplevel-value var)) val)) - (add-to-list 'doom-debug--unbound-vars spec)))) + (add-to-list 'doom-debug--unbound-variables spec)))) ((boundp spec) - (doom-log "debug:vars: %s = %S" spec doom-debug-mode) + (doom-log 3 "debug:vars: %s = %S" spec doom-debug-mode) (set-default-toplevel-value spec doom-debug-mode)) - ((add-to-list 'doom-debug--unbound-vars (cons spec t))))) + ((add-to-list 'doom-debug--unbound-variables (cons spec t))))) + +(defun doom-debug--timestamped-message-a (format-string &rest _args) + "Advice to run before `message' that prepends a timestamp to each message. + +Activate this advice with: +(advice-add 'message :before 'doom-debug--timestamped-message-a)" + (when (and (stringp format-string) + message-log-max ; if nil, logging is disabled + (not (equal format-string "%s%s")) + (not (equal format-string "\n"))) + (with-current-buffer "*Messages*" + (let ((timestamp (format-time-string "[%F %T] " (current-time))) + (deactivate-mark nil)) + (with-silent-modifications + (goto-char (point-max)) + (if (not (bolp)) + (newline)) + (insert timestamp)))) + (let ((window (get-buffer-window "*Messages*"))) + (when (and window (not (equal (selected-window) window))) + (with-current-buffer "*Messages*" + (goto-char (point-max)) + (set-window-point window (point-max))))))) ;;;###autoload (define-minor-mode doom-debug-mode "Toggle `debug-on-error' and `init-file-debug' for verbose logging." :global t - (let ((enabled doom-debug-mode)) - (doom-log "debug: enabled!") - (mapc #'doom-debug--set-var doom-debug-variables) - ;; Watch for changes in `doom-debug-variables', or when packages load (and - ;; potentially define one of `doom-debug-variables'), in case some of them - ;; aren't defined when `doom-debug-mode' is first loaded. - (cond (enabled - (unless noninteractive - (message "Debug mode enabled! (Run 'M-x view-echo-area-messages' to open the log buffer)")) - ;; Produce more helpful (and visible) error messages from errors - ;; emitted from hooks (particularly mode hooks), that usually go - ;; unnoticed otherwise. - (advice-add #'run-hooks :override #'doom-run-hooks) - ;; Add time stamps to lines in *Messages* - (advice-add #'message :before #'doom--timestamped-message-a) - ;; The constant debug output from GC is mostly unhelpful. I still - ;; want it logged to *Messages*, just out of the echo area. - (advice-add #'gcmh-idle-garbage-collect :around #'doom-debug-shut-up-a) - (add-variable-watcher 'doom-debug-variables #'doom-debug--watch-vars-h) - (add-hook 'after-load-functions #'doom-debug--watch-vars-h)) - (t - (advice-remove #'run-hooks #'doom-run-hooks) - (advice-remove #'message #'doom--timestamped-message-a) - (advice-remove #'gcmh-idle-garbage-collect #'doom-debug-shut-up-a) - (remove-variable-watcher 'doom-debug-variables #'doom-debug--watch-vars-h) - (remove-hook 'after-load-functions #'doom-debug--watch-vars-h) - (doom-log "debug: disabled") - (message "Debug mode disabled!"))))) + (when (or doom-debug-mode + (and (integerp current-prefix-arg) + (> current-prefix-arg 0))) + (setq doom-debug-mode t) + (let ((level (max 1 (min 3 (or current-prefix-arg 1))))) + (put 'doom-log-level 'initial-value doom-log-level) + (setq doom-log-level level))) + (doom-log "debug: enabled! (log-level=%d)" doom-log-level) + (mapc #'doom-debug--set-var doom-debug--variables) + ;; Watch for changes in `doom-debug--variables', or when packages load (and + ;; potentially define one of `doom-debug--variables'), in case some of them + ;; aren't defined when `doom-debug-mode' is first loaded. + (cond (doom-debug-mode + (unless noninteractive + (message "Debug mode level %d enabled! (Run 'M-x view-echo-area-messages' to open the log buffer)" + doom-log-level)) + ;; Produce more helpful (and visible) error messages from errors + ;; emitted from hooks (particularly mode hooks), that usually go + ;; unnoticed otherwise. + (advice-add #'run-hooks :override #'doom-run-hooks) + ;; Add time stamps to lines in *Messages* + (advice-add #'message :before #'doom-debug--timestamped-message-a) + ;; The constant debug output from GC is mostly unhelpful. I still + ;; want it logged to *Messages*, just out of the echo area. + (advice-add #'gcmh-idle-garbage-collect :around #'doom-debug-shut-up-a) + (add-variable-watcher 'doom-debug--variables #'doom-debug--watch-vars-h) + (add-hook 'after-load-functions #'doom-debug--watch-vars-h)) + (t + (when-let* ((last-level (get 'doom-log-level 'initial-value))) + (put 'doom-log-level 'initial-value nil) + (setq doom-log-level last-level)) + (advice-remove #'run-hooks #'doom-run-hooks) + (advice-remove #'message #'doom-debug--timestamped-message-a) + (advice-remove #'gcmh-idle-garbage-collect #'doom-debug-shut-up-a) + (remove-variable-watcher 'doom-debug--variables #'doom-debug--watch-vars-h) + (remove-hook 'after-load-functions #'doom-debug--watch-vars-h) + (doom-log "debug: disabled") + (message "Debug mode disabled!")))) (defun doom-debug-shut-up-a (fn &rest args) "Suppress output from FN, even in debug mode." @@ -163,33 +198,6 @@ symbol and CDR is the value to set it to when `doom-debug-mode' is activated.") file))) -;; -;;; Time-stamped *Message* logs - -(defun doom--timestamped-message-a (format-string &rest _args) - "Advice to run before `message' that prepends a timestamp to each message. - -Activate this advice with: -(advice-add 'message :before 'doom--timestamped-message-a)" - (when (and (stringp format-string) - message-log-max ; if nil, logging is disabled - (not (equal format-string "%s%s")) - (not (equal format-string "\n"))) - (with-current-buffer "*Messages*" - (let ((timestamp (format-time-string "[%F %T] " (current-time))) - (deactivate-mark nil)) - (with-silent-modifications - (goto-char (point-max)) - (if (not (bolp)) - (newline)) - (insert timestamp)))) - (let ((window (get-buffer-window "*Messages*"))) - (when (and window (not (equal (selected-window) window))) - (with-current-buffer "*Messages*" - (goto-char (point-max)) - (set-window-point window (point-max))))))) - - ;; ;;; Hooks diff --git a/modules/editor/format/config.el b/modules/editor/format/config.el index fa2fc1e15..6eebb125d 100644 --- a/modules/editor/format/config.el +++ b/modules/editor/format/config.el @@ -42,8 +42,8 @@ This is controlled by `+format-on-save-disabled-modes'." (add-hook 'lsp-managed-mode-hook #'+format-with-lsp-toggle-h)) :config - (add-to-list 'doom-debug-variables '(apheleia-log-only-errors . nil)) - (add-to-list 'doom-debug-variables '(apheleia-log-debug-info . t)) + (set-debug-variable! 'apheleia-log-only-errors nil) + (set-debug-variable! 'apheleia-log-debug-info t 2) (defadvice! +format--inhibit-reformat-on-prefix-arg-a (orig-fn &optional arg) "Make it so \\[save-buffer] with prefix arg inhibits reformatting." diff --git a/modules/editor/snippets/config.el b/modules/editor/snippets/config.el index 7690b8c02..1346c5dc4 100644 --- a/modules/editor/snippets/config.el +++ b/modules/editor/snippets/config.el @@ -31,7 +31,7 @@ (add-transient-hook! #'company-yasnippet (require 'yasnippet)) :config - (add-to-list 'doom-debug-variables '(yas-verbosity . 3)) + (set-debug-variable! 'yas-verbosity 3) ;; Allow private snippets in DOOMDIR/snippets (add-to-list 'yas-snippet-dirs '+snippets-dir) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index 2902f6ae5..fb21d6716 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -21,7 +21,7 @@ (setq mu4e-maildir "~/.mail" mu4e-user-mail-address-list nil)) :config - (add-to-list 'doom-debug-variables 'mu4e-debug) + (set-debug-variable! 'mu4e-debug) ;; mu4e now uses `display-buffer-alist' so we need to add some rules of our own (set-popup-rule! "^\\*mu4e-\\(main\\|headers\\)\\*" :ignore t) (set-popup-rule! "^\\*mu4e-log\\*" :select nil) diff --git a/modules/lang/org/config.el b/modules/lang/org/config.el index e7b077885..2fbcbaefa 100644 --- a/modules/lang/org/config.el +++ b/modules/lang/org/config.el @@ -1364,7 +1364,7 @@ between the two." (run-hooks 'org-load-hook)) :config - (add-to-list 'doom-debug-variables 'org-export-async-debug) + (set-debug-variable! 'org-export-async-debug) (set-company-backend! 'org-mode 'company-capf) (set-eval-handler! 'org-mode #'+org-eval-handler) diff --git a/modules/tools/direnv/config.el b/modules/tools/direnv/config.el index b9f4f5045..acd15ad02 100644 --- a/modules/tools/direnv/config.el +++ b/modules/tools/direnv/config.el @@ -3,7 +3,7 @@ (use-package! envrc :hook (doom-first-file . envrc-global-mode) :config - (add-to-list 'doom-debug-variables 'envrc-debug) + (set-debug-variable! 'envrc-debug) (set-popup-rule! "^\\*envrc\\*" :quit t :ttl 0) diff --git a/modules/tools/lsp/+eglot.el b/modules/tools/lsp/+eglot.el index 5c8b8837a..0990f8a1e 100644 --- a/modules/tools/lsp/+eglot.el +++ b/modules/tools/lsp/+eglot.el @@ -32,7 +32,7 @@ ;; Emacs GC is put under high pressure. (cl-callf plist-put eglot-events-buffer-config :size 0) - (add-to-list 'doom-debug-variables '(eglot-events-buffer-config :size 2000000 :format full)) + (set-debug-variable! 'eglot-events-buffer-config '(:size 2000000 :format full)) (defadvice! +lsp--defer-server-shutdown-a (fn &optional server) "Defer server shutdown for a few seconds. diff --git a/modules/tools/lsp/+lsp.el b/modules/tools/lsp/+lsp.el index 5961172cc..44334e632 100644 --- a/modules/tools/lsp/+lsp.el +++ b/modules/tools/lsp/+lsp.el @@ -59,7 +59,7 @@ Can be a list of backends; accepts any value `company-backends' accepts.") (apply fn args)))) :config - (add-to-list 'doom-debug-variables 'lsp-log-io) + (set-debug-variable! 'lsp-log-io t 2) (setq lsp-intelephense-storage-path (concat doom-data-dir "lsp-intelephense/") lsp-vetur-global-snippets-dir diff --git a/modules/tools/magit/config.el b/modules/tools/magit/config.el index 9564b5618..37c9a0381 100644 --- a/modules/tools/magit/config.el +++ b/modules/tools/magit/config.el @@ -48,7 +48,7 @@ FUNCTION transient-values-file (concat doom-data-dir "transient/values") transient-history-file (concat doom-data-dir "transient/history")) :config - (add-to-list 'doom-debug-variables 'magit-refresh-verbose) + (set-debug-variable! 'magit-refresh-verbose) (setq transient-default-level 5 magit-diff-refine-hunk t ; show granular diffs in selected hunk