From 0d7c3eaf24b53348a6e9f0b988b3d353b1c9cc85 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Wed, 14 Sep 2022 19:01:57 +0200 Subject: [PATCH] feat: add doom-{before,after}-init-hook doom-before-init-hook runs before $DOOMDIR/init.el is loaded. doom-after-init-hook runs at the *very* end of the Emacs startup process (after window-setup-hook). --- lisp/doom-cli.el | 39 +++++++++++++++---------------- lisp/doom-start.el | 12 ++++------ lisp/doom-ui.el | 7 ++---- lisp/doom.el | 57 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 81 insertions(+), 34 deletions(-) diff --git a/lisp/doom-cli.el b/lisp/doom-cli.el index 7061382a3..8b952ffd8 100644 --- a/lisp/doom-cli.el +++ b/lisp/doom-cli.el @@ -25,27 +25,22 @@ ;; HACK: Load `cl' and site files manually to prevent polluting logs and ;; stdout with deprecation and/or file load messages. - (when noninteractive - (let ((inhibit-message (not init-file-debug))) - (require 'cl nil t) - (unless site-run-file - (let ((site-run-file "site-start") - (tail load-path) - (lispdir (expand-file-name "../lisp" data-directory)) - dir) - (while tail - (setq dir (car tail)) + (let ((inhibit-message (not init-file-debug))) + (require 'cl nil t) + (unless site-run-file + (let ((site-run-file "site-start") + (tail load-path) + (lispdir (expand-file-name "../lisp" data-directory)) + dir) + (while tail + (setq dir (car tail)) + (let ((default-directory dir)) + (load (expand-file-name "subdirs.el") t inhibit-message t)) + (unless (string-prefix-p lispdir dir) (let ((default-directory dir)) - (load (expand-file-name "subdirs.el") t inhibit-message t)) - (unless (string-prefix-p lispdir dir) - (let ((default-directory dir)) - (load (expand-file-name "leim-list.el") t inhibit-message t))) - (setq tail (cdr tail))) - (load site-run-file t inhibit-message))))) - - ;; Reset these vars' initial values, in case the site files have changed them. - (dolist (var '(exec-path load-path process-environment)) - (put var 'initial-value (default-value var))) + (load (expand-file-name "leim-list.el") t inhibit-message t))) + (setq tail (cdr tail))) + (load site-run-file t inhibit-message)))) (setq-default ;; PERF: Don't generate superfluous files when writing temp buffers. @@ -79,7 +74,9 @@ ;; Ensure straight and core packages are ready to go for CLI commands. ;; (require 'doom-profiles) (require 'doom-modules) - (require 'doom-packages)) + (require 'doom-packages) + ;; For any last-minute initialization. + (run-hooks 'doom-before-init-hook)) ;; diff --git a/lisp/doom-start.el b/lisp/doom-start.el index dbb92b458..a1529c29d 100644 --- a/lisp/doom-start.el +++ b/lisp/doom-start.el @@ -295,8 +295,8 @@ If RETURN-P, return the message as a string instead of displaying it." ;; Bootstrap the interactive session (add-hook 'after-change-major-mode-hook #'doom-run-local-var-hooks-h 100) (add-hook 'hack-local-variables-hook #'doom-run-local-var-hooks-h) -(add-hook 'emacs-startup-hook #'doom-load-packages-incrementally-h) -(add-hook 'window-setup-hook #'doom-display-benchmark-h 105) +(add-hook 'doom-after-init-hook #'doom-load-packages-incrementally-h) +(add-hook 'doom-after-init-hook #'doom-display-benchmark-h 110) (doom-run-hook-on 'doom-first-buffer-hook '(find-file-hook doom-switch-buffer-hook)) (doom-run-hook-on 'doom-first-file-hook '(find-file-hook dired-initial-position-hook)) (doom-run-hook-on 'doom-first-input-hook '(pre-command-hook)) @@ -310,11 +310,9 @@ If RETURN-P, return the message as a string instead of displaying it." (eval-after-load 'straight '(doom-initialize-packages)) (require 'doom-modules) -;; Undo any problematic startup optimizations; from this point, I make no -;; assumptions about what might be loaded in userland. -(when (get 'load-suffixes 'initial-value) - (setq load-suffixes (get 'load-suffixes 'initial-value) - load-file-rep-suffixes (get 'load-file-rep-suffixes 'initial-value))) +;; A last ditch opportunity to undo dodgy optimizations or do extra +;; configuration before the session is complicated by user config and packages. +(doom-run-hooks 'doom-before-init-hook) ;; Load user config + modules (doom-initialize-modules) diff --git a/lisp/doom-ui.el b/lisp/doom-ui.el index dbbf4df8e..4008b41da 100644 --- a/lisp/doom-ui.el +++ b/lisp/doom-ui.el @@ -622,10 +622,7 @@ triggering hooks during startup." ;; Initialize `doom-switch-buffer-hook' (add-hook 'window-buffer-change-functions #'doom-run-switch-buffer-hooks-h) ;; `window-buffer-change-functions' doesn't trigger for files visited via the server. - (add-hook 'server-visit-hook #'doom-run-switch-buffer-hooks-h) - - ;; Only execute this function once. - (remove-hook 'window-buffer-change-functions #'doom-init-ui-h)) + (add-hook 'server-visit-hook #'doom-run-switch-buffer-hooks-h)) ;; Apply fonts and theme (let ((hook (if (daemonp) @@ -636,7 +633,7 @@ triggering hooks during startup." ;; Initialize UI as late as possible. `window-buffer-change-functions' runs ;; once, when the scratch/dashboard buffer is first displayed. -(add-hook 'window-buffer-change-functions #'doom-init-ui-h -100) +(add-hook 'doom-after-init-hook #'doom-init-ui-h -100) ;; diff --git a/lisp/doom.el b/lisp/doom.el index c635ba0b6..9821dcd5a 100644 --- a/lisp/doom.el +++ b/lisp/doom.el @@ -35,6 +35,7 @@ ;; $EMACSDIR/early-init.el ;; $EMACSDIR/lisp/doom.el ;; $EMACSDIR/lisp/doom-start.el +;; `doom-before-init-hook' ;; $DOOMDIR/init.el ;; `doom-before-modules-init-hook' ;; {$DOOMDIR,~/.emacs.d}/modules/*/*/init.el @@ -47,6 +48,7 @@ ;; `emacs-startup-hook' ;; `doom-init-ui-hook' ;; `window-setup-hook' +;; `doom-after-init-hook' ;; ;;; Code: @@ -294,7 +296,7 @@ users).") ;; `load', or various file/io functions (like `expand-file-name' or ;; `file-remote-p'). You get a noteable boost to startup time by unsetting ;; or simplifying its value. - (let ((old-value (get 'file-name-handler-alist 'initial-value))) + (let ((old-value (default-toplevel-value 'file-name-handler-alist))) (setq file-name-handler-alist ;; HACK: If the bundled elisp for this Emacs install isn't ;; byte-compiled (but is compressed), then leave the gzip file @@ -375,12 +377,21 @@ users).") ;; PERF: `load-suffixes' and `load-file-rep-suffixes' are consulted on each ;; `require' and `load'. Doom won't load any dmodules this early, so omit ;; .so for a small startup boost. This is later restored in doom-start. + (put 'load-suffixes 'initial-value (default-toplevel-value 'load-suffixes)) + (put 'load-file-rep-suffixes 'initial-value (default-toplevel-value 'load-file-rep-suffixes)) (set-default-toplevel-value 'load-suffixes '(".elc" ".el")) (set-default-toplevel-value 'load-file-rep-suffixes '("")) + ;; COMPAT: Undo any problematic startup optimizations; from this point, I make + ;; no assumptions about what might be loaded in userland. + (add-hook! 'doom-before-init-hook + (defun doom--reset-load-suffixes-h () + (setq load-suffixes (get 'load-suffixes 'initial-value) + load-file-rep-suffixes (get 'load-file-rep-suffixes 'initial-value)))) ;; PERF: The mode-line procs a couple dozen times during startup. This is ;; normally quite fast, but disabling the default mode-line and reducing the ;; update delay timer seems to stave off ~30-50ms. + (put 'mode-line-format 'initial-value (default-toplevel-value 'mode-line-format)) (setq-default mode-line-format nil) (dolist (buf (buffer-list)) (with-current-buffer buf (setq mode-line-format nil))) @@ -508,5 +519,49 @@ Otherwise, `en/disable-command' (in novice.el.gz) is hardcoded to write them to ;; compatibility fallbacks "gnutls-cli -p %p %h")) + +;; +;;; Custom hooks + +(defcustom doom-before-init-hook () + "A hook run before Doom has been initialized and before $DOOMDIR/init.el. + +This occurs in the context of early-init.el. Much of Emacs and Doom isn't +initialized at this point, only loaded. Use this for configuration at the latest +opportunity before the session becomes unpredictably complicated by user config, +packages, etc. + +Do not use this for interactive functionality, as it's triggered in +noninteractive sessions as well, after Doom core has been loaded, but not +initialized. + +In contrast, `before-init-hook' is run just after $DOOMDIR/init.el is loaded, +but before the rest of Doom is loaded." + :group 'doom + :type 'hook) + +(defcustom doom-after-init-hook () + "A hook run at the (true) end of Emacs startup. + +When this runs, all modules, config files, and startup hooks have been +triggered. This is the absolute latest point in the startup process." + :group 'doom + :type 'hook) + + +;; +;;; Last minute initialization + +(add-hook! 'doom-before-init-hook + (defun doom--set-initial-values-h () + ;; Remember these variables' initial values, so we can safely reset them at + ;; a later time, or consult them without fear of contamination. + (dolist (var '(exec-path load-path process-environment)) + (put var 'initial-value (default-toplevel-value var))))) + +;; This is the absolute latest a hook can run in Emacs' startup process. +(define-advice command-line-1 (:after (&rest _) run-after-init-hook) + (doom-run-hooks 'doom-after-init-hook)) + (provide 'doom) ;;; doom.el ends here