Add doom-run-hooks

Produces more helpful (and harder-to-miss) error messages when a hook
emits an error. Also advises run-hook when doom-debug-mode is active, so
errors in hooks (generally, major mode hooks) don't quietly go
unnoticed.
This commit is contained in:
Henrik Lissner 2021-05-05 16:12:35 -04:00
parent df10383a26
commit ff64a9d106
6 changed files with 35 additions and 20 deletions

View file

@ -82,14 +82,14 @@ Runs `doom-after-reload-hook' afterwards."
(mapc #'require (cdr doom-incremental-packages)) (mapc #'require (cdr doom-incremental-packages))
(doom--if-compile (format "%S sync -e" doom-bin) (doom--if-compile (format "%S sync -e" doom-bin)
(let ((doom-reloading-p t)) (let ((doom-reloading-p t))
(run-hook-wrapped 'doom-before-reload-hook #'doom-try-run-hook) (doom-run-hooks 'doom-before-reload-hook)
(doom-initialize 'force) (doom-initialize 'force)
(with-demoted-errors "PRIVATE CONFIG ERROR: %s" (with-demoted-errors "PRIVATE CONFIG ERROR: %s"
(general-auto-unbind-keys) (general-auto-unbind-keys)
(unwind-protect (unwind-protect
(doom-initialize-modules 'force) (doom-initialize-modules 'force)
(general-auto-unbind-keys t))) (general-auto-unbind-keys t)))
(run-hook-wrapped 'doom-after-reload-hook #'doom-try-run-hook) (doom-run-hooks 'doom-after-reload-hook)
(message "Config successfully reloaded!")) (message "Config successfully reloaded!"))
(user-error "Failed to reload your config"))) (user-error "Failed to reload your config")))

View file

@ -77,13 +77,11 @@ symbol and CDR is the value to set it to when `doom-debug-mode' is activated.")
emacs -Q -l init.el -f doom-run-all-startup-hooks-h" emacs -Q -l init.el -f doom-run-all-startup-hooks-h"
(setq after-init-time (current-time)) (setq after-init-time (current-time))
(let ((inhibit-startup-hooks nil)) (let ((inhibit-startup-hooks nil))
(mapc (lambda (hook) (doom-run-hooks 'after-init-hook
(run-hook-wrapped hook #'doom-try-run-hook)) 'delayed-warnings-hook
'(after-init-hook 'emacs-startup-hook
delayed-warnings-hook 'tty-setup-hook
emacs-startup-hook 'window-setup-hook)))
tty-setup-hook
window-setup-hook))))
;; ;;

View file

@ -116,7 +116,7 @@
(--run--) (--run--)
(maphash (doom-module-loader doom-module-init-file) doom-modules) (maphash (doom-module-loader doom-module-init-file) doom-modules)
(maphash (doom-module-loader doom-module-config-file) doom-modules) (maphash (doom-module-loader doom-module-config-file) doom-modules)
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook))) (doom-run-hooks 'doom-init-modules-hook)))
(`vanilla-doom ; only Doom core (`vanilla-doom ; only Doom core
`(progn `(progn
(load-file ,(expand-file-name "core.el" doom-core-dir)) (load-file ,(expand-file-name "core.el" doom-core-dir))
@ -130,7 +130,8 @@
(--run--)))) (--run--))))
;; Then rerun Emacs' startup hooks to simulate a fresh Emacs session, ;; Then rerun Emacs' startup hooks to simulate a fresh Emacs session,
;; because they've already fired. ;; because they've already fired.
(fset 'doom-try-run-hook #',(symbol-function #'doom-try-run-hook)) (fset 'doom-run-hook #',(symbol-function #'doom-run-hook))
(fset 'doom-run-hooks #',(symbol-function #'doom-run-hooks))
(fset 'doom-run-all-startup-hooks-h #',(symbol-function #'doom-run-all-startup-hooks-h)) (fset 'doom-run-all-startup-hooks-h #',(symbol-function #'doom-run-all-startup-hooks-h))
(doom-run-all-startup-hooks-h)))))) (doom-run-all-startup-hooks-h))))))

View file

@ -117,10 +117,10 @@ non-nil."
(when-let (init-p (load! doom-module-init-file doom-private-dir t)) (when-let (init-p (load! doom-module-init-file doom-private-dir t))
(doom-log "Initializing user config") (doom-log "Initializing user config")
(maphash (doom-module-loader doom-module-init-file) doom-modules) (maphash (doom-module-loader doom-module-init-file) doom-modules)
(run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook) (run-hook-wrapped 'doom-before-init-modules-hook #'doom-run-hook)
(unless no-config-p (unless no-config-p
(maphash (doom-module-loader doom-module-config-file) doom-modules) (maphash (doom-module-loader doom-module-config-file) doom-modules)
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook) (run-hook-wrapped 'doom-init-modules-hook #'doom-run-hook)
(load! "config" doom-private-dir t) (load! "config" doom-private-dir t)
(load custom-file 'noerror (not doom-debug-mode)))))) (load custom-file 'noerror (not doom-debug-mode))))))

View file

@ -675,7 +675,11 @@ This offers a moderate boost in startup (or theme switch) time, so long as
(defun doom-init-ui-h () (defun doom-init-ui-h ()
"Initialize Doom's user interface by applying all its advice and hooks." "Initialize Doom's user interface by applying all its advice and hooks."
(run-hook-wrapped 'doom-init-ui-hook #'doom-try-run-hook) ;; 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)
(doom-run-hooks 'doom-init-ui-hook)
(add-hook 'kill-buffer-query-functions #'doom-protect-fallback-buffer-h) (add-hook 'kill-buffer-query-functions #'doom-protect-fallback-buffer-h)
(add-hook 'after-change-major-mode-hook #'doom-highlight-non-default-indentation-h 'append) (add-hook 'after-change-major-mode-hook #'doom-highlight-non-default-indentation-h 'append)

View file

@ -383,8 +383,7 @@ config.el instead."
"Run MODE-local-vars-hook after local variables are initialized." "Run MODE-local-vars-hook after local variables are initialized."
(unless doom-inhibit-local-var-hooks (unless doom-inhibit-local-var-hooks
(setq-local doom-inhibit-local-var-hooks t) (setq-local doom-inhibit-local-var-hooks t)
(run-hook-wrapped (intern-soft (format "%s-local-vars-hook" major-mode)) (doom-run-hooks (intern-soft (format "%s-local-vars-hook" major-mode)))))
#'doom-try-run-hook)))
;; ;;
@ -500,17 +499,30 @@ unreadable. Returns the names of envvars that were changed."
(default-value 'shell-file-name))) (default-value 'shell-file-name)))
env)))) env))))
(defun doom-try-run-hook (hook) (defun doom-run-hook (hook)
"Run HOOK (a hook function) with better error handling. "Run HOOK (a hook function) with better error handling.
Meant to be used with `run-hook-wrapped'." Meant to be used with `run-hook-wrapped'."
(doom-log "Running doom hook: %s" hook) (doom-log "Running doom hook: %s" hook)
(condition-case e (condition-case-unless-debug e
(funcall hook) (funcall hook)
((debug error) (user-error
(warn "Warning: %s" (error-message-string e)))
(error
(signal 'doom-hook-error (list hook e)))) (signal 'doom-hook-error (list hook e))))
;; return nil so `run-hook-wrapped' won't short circuit ;; return nil so `run-hook-wrapped' won't short circuit
nil) nil)
(defun doom-run-hooks (&rest hooks)
"Run HOOKS (a list of hook variable symbols) with better error handling.
Is used as advice to replace `run-hooks'."
(dolist (hook hooks)
(condition-case-unless-debug e
(run-hook-wrapped hook #'doom-run-hook)
(doom-hook-error
(unless debug-on-error
(lwarn hook :error "Error running hook %S because: %s" (cadr e) (caddr e)))
(signal 'doom-hook-error (cons hook (cdr e)))))))
(defun doom-run-hook-on (hook-var trigger-hooks) (defun doom-run-hook-on (hook-var trigger-hooks)
"Configure HOOK-VAR to be invoked exactly once when any of the TRIGGER-HOOKS "Configure HOOK-VAR to be invoked exactly once when any of the TRIGGER-HOOKS
are invoked. Once HOOK-VAR is triggered, it is reset to nil. are invoked. Once HOOK-VAR is triggered, it is reset to nil.
@ -530,7 +542,7 @@ TRIGGER-HOOK is a list of quoted hooks and/or sharp-quoted functions."
;; interactively. ;; interactively.
(boundp hook) (boundp hook)
(symbol-value hook)) (symbol-value hook))
(run-hook-wrapped hook-var #'doom-try-run-hook) (doom-run-hooks hook-var)
(set hook-var nil)))) (set hook-var nil))))
;; DEPRECATED This target switcheroo won't be necessary when 26 support is ;; DEPRECATED This target switcheroo won't be necessary when 26 support is
;; dropped; `add-hook''s DEPTH argument was added in 27.1. ;; dropped; `add-hook''s DEPTH argument was added in 27.1.