From ff64a9d10649f80dc3a53d542d5276fddfabc591 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Wed, 5 May 2021 16:12:35 -0400 Subject: [PATCH] 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. --- core/autoload/config.el | 4 ++-- core/autoload/debug.el | 12 +++++------- core/autoload/sandbox.el | 5 +++-- core/core-modules.el | 4 ++-- core/core-ui.el | 6 +++++- core/core.el | 24 ++++++++++++++++++------ 6 files changed, 35 insertions(+), 20 deletions(-) diff --git a/core/autoload/config.el b/core/autoload/config.el index d6bdbdd81..74fb1deb9 100644 --- a/core/autoload/config.el +++ b/core/autoload/config.el @@ -82,14 +82,14 @@ Runs `doom-after-reload-hook' afterwards." (mapc #'require (cdr doom-incremental-packages)) (doom--if-compile (format "%S sync -e" doom-bin) (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) (with-demoted-errors "PRIVATE CONFIG ERROR: %s" (general-auto-unbind-keys) (unwind-protect (doom-initialize-modules 'force) (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!")) (user-error "Failed to reload your config"))) diff --git a/core/autoload/debug.el b/core/autoload/debug.el index 1a4356681..80c932d06 100644 --- a/core/autoload/debug.el +++ b/core/autoload/debug.el @@ -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" (setq after-init-time (current-time)) (let ((inhibit-startup-hooks nil)) - (mapc (lambda (hook) - (run-hook-wrapped hook #'doom-try-run-hook)) - '(after-init-hook - delayed-warnings-hook - emacs-startup-hook - tty-setup-hook - window-setup-hook)))) + (doom-run-hooks 'after-init-hook + 'delayed-warnings-hook + 'emacs-startup-hook + 'tty-setup-hook + 'window-setup-hook))) ;; diff --git a/core/autoload/sandbox.el b/core/autoload/sandbox.el index 59999ad4c..412e2b8db 100644 --- a/core/autoload/sandbox.el +++ b/core/autoload/sandbox.el @@ -116,7 +116,7 @@ (--run--) (maphash (doom-module-loader doom-module-init-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 `(progn (load-file ,(expand-file-name "core.el" doom-core-dir)) @@ -130,7 +130,8 @@ (--run--)))) ;; Then rerun Emacs' startup hooks to simulate a fresh Emacs session, ;; 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)) (doom-run-all-startup-hooks-h)))))) diff --git a/core/core-modules.el b/core/core-modules.el index 3316a69d5..688899778 100644 --- a/core/core-modules.el +++ b/core/core-modules.el @@ -117,10 +117,10 @@ non-nil." (when-let (init-p (load! doom-module-init-file doom-private-dir t)) (doom-log "Initializing user config") (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 (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 custom-file 'noerror (not doom-debug-mode)))))) diff --git a/core/core-ui.el b/core/core-ui.el index b5130d5b6..457d0a789 100644 --- a/core/core-ui.el +++ b/core/core-ui.el @@ -675,7 +675,11 @@ This offers a moderate boost in startup (or theme switch) time, so long as (defun doom-init-ui-h () "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 'after-change-major-mode-hook #'doom-highlight-non-default-indentation-h 'append) diff --git a/core/core.el b/core/core.el index 8bf51b3c8..97dd6c809 100644 --- a/core/core.el +++ b/core/core.el @@ -383,8 +383,7 @@ config.el instead." "Run MODE-local-vars-hook after local variables are initialized." (unless doom-inhibit-local-var-hooks (setq-local doom-inhibit-local-var-hooks t) - (run-hook-wrapped (intern-soft (format "%s-local-vars-hook" major-mode)) - #'doom-try-run-hook))) + (doom-run-hooks (intern-soft (format "%s-local-vars-hook" major-mode))))) ;; @@ -500,17 +499,30 @@ unreadable. Returns the names of envvars that were changed." (default-value 'shell-file-name))) env)))) -(defun doom-try-run-hook (hook) +(defun doom-run-hook (hook) "Run HOOK (a hook function) with better error handling. Meant to be used with `run-hook-wrapped'." (doom-log "Running doom hook: %s" hook) - (condition-case e + (condition-case-unless-debug e (funcall hook) - ((debug error) + (user-error + (warn "Warning: %s" (error-message-string e))) + (error (signal 'doom-hook-error (list hook e)))) ;; return nil so `run-hook-wrapped' won't short circuit 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) "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. @@ -530,7 +542,7 @@ TRIGGER-HOOK is a list of quoted hooks and/or sharp-quoted functions." ;; interactively. (boundp hook) (symbol-value hook)) - (run-hook-wrapped hook-var #'doom-try-run-hook) + (doom-run-hooks hook-var) (set hook-var nil)))) ;; DEPRECATED This target switcheroo won't be necessary when 26 support is ;; dropped; `add-hook''s DEPTH argument was added in 27.1.