diff --git a/bin/doom b/bin/doom index 71641a219..5b9149084 100755 --- a/bin/doom +++ b/bin/doom @@ -304,10 +304,11 @@ SEE ALSO: (let ((cli-file "cli.el")) (defcli-group! "Module commands" - (dolist (key (doom-module-list)) - (when-let (path (doom-module-locate-path (car key) (cdr key) cli-file)) - (defcli-group! :prefix (if (cdr key) (format "+%s" (cdr key))) - (doom-load (file-name-sans-extension path))))))) + (doom-context-with 'modules + (dolist (key (doom-module-list)) + (when-let (path (doom-module-locate-path (car key) (cdr key) cli-file)) + (defcli-group! :prefix (if (cdr key) (format "+%s" (cdr key))) + (doom-load (file-name-sans-extension path)))))))) ;; Allow per-project Doom settings in .doom files. (let (doomrc) diff --git a/lisp/cli/doctor.el b/lisp/cli/doctor.el index 604c2975d..564654e6c 100644 --- a/lisp/cli/doctor.el +++ b/lisp/cli/doctor.el @@ -247,10 +247,11 @@ in." (doctor-file (doom-module-expand-path (car key) (cdr key) "doctor.el")) (packages-file (doom-module-expand-path (car key) (cdr key) doom-module-packages-file))) (cl-loop with doom-output-indent = 6 - for name in (let* (doom-packages - doom-disabled-packages) - (load packages-file 'noerror 'nomessage) - (mapcar #'car doom-packages)) + for name in (doom-context-with 'packages + (let* (doom-packages + doom-disabled-packages) + (load packages-file 'noerror 'nomessage) + (mapcar #'car doom-packages))) unless (or (doom-package-get name :disable) (eval (doom-package-get name :ignore)) (plist-member (doom-package-get name :recipe) :local-repo) diff --git a/lisp/doom-cli.el b/lisp/doom-cli.el index c3f2c9569..684fc0239 100644 --- a/lisp/doom-cli.el +++ b/lisp/doom-cli.el @@ -72,9 +72,7 @@ ;; Ensure straight and core packages are ready to go for CLI commands. (require 'doom-modules) (require 'doom-packages) - (require 'doom-profiles) - ;; For any last-minute initialization. - (run-hooks 'doom-before-init-hook)) + (require 'doom-profiles)) ;; @@ -298,7 +296,7 @@ the return value of the executed CLI.") BINDINGS is an alist of (SYMBOL . VALUE) to bind lexically during CLI's execution. Can be generated from a `doom-cli-context' with `doom-cli--bindings'." - (doom-log "cli-execute: %s %s" (doom-cli-key cli) bindings) + (doom-log "execute: %s %s" (doom-cli-key cli) bindings) (funcall (doom-cli-fn cli) cli bindings)) (defun doom-cli-key (cli) @@ -725,7 +723,7 @@ executable context." (let* ((command (doom-cli-context-command context)) (cli (doom-cli-get command t)) (prefix (doom-cli-context-prefix context))) - (doom-log "cli-context-execute: %s" + (doom-log "context-execute: %s" (mapconcat #'doom-cli-command-string (delq nil (list (car (doom-cli-context-path context)) command)) " -> ")) @@ -786,7 +784,7 @@ executable context." (_ old-value)))))) (run-hook-with-args 'doom-cli-create-context-functions context) (delete-file file) - (doom-log "cli-context-restore: %s" (doom-cli-context-pid context)))) + (doom-log "context-restore: %s" (doom-cli-context-pid context)))) context) (defun doom-cli-context-parse (args context) @@ -801,7 +799,7 @@ executable context." (save-match-data (cond ((equal arg "--") - (doom-log "cli-context-parse: found arg separator" arg) + (doom-log "context-parse: found arg separator" arg) (setq arguments (cdr args) args nil)) @@ -814,7 +812,7 @@ executable context." ((and (stringp arg) (or (string-match "^\\(--\\w[a-z0-9-_]+\\)\\(?:=\\(.*\\)\\)?$" arg) (string-match "^\\(-[^-]\\)$" arg))) - (doom-log "cli-context-parse: found switch %S" arg) + (doom-log "context-parse: found switch %S" arg) (catch :skip (let* ((fullflag (match-string 1 arg)) (normflag (if (string-prefix-p "--no-" fullflag) @@ -822,7 +820,7 @@ executable context." fullflag)) (option (or (doom-cli-context-find-option context normflag) (when (member fullflag '("-?" "--help" "--version")) - (doom-log "cli-context-parse: found help switch %S" arg) + (doom-log "context-parse: found help switch %S" arg) (setf (doom-cli-context-meta-p context) fullflag) (throw :skip t)) (when rest? @@ -866,11 +864,11 @@ executable context." (cli (doom-cli-get command t)) (rcli (doom-cli-get command)) (key (doom-cli-key rcli))) - (doom-log "cli-context-parse: found command %s" command) + (doom-log "context-parse: found command %s" command) ;; Show warnings depending on CLI plists (when (doom-cli-alias cli) (dolist (pcli (doom-cli-path cli)) - (doom-log "cli-context-parse: path += %s" (doom-cli-key pcli)) + (doom-log "context-parse: path += %s" (doom-cli-key pcli)) (push (doom-cli-key pcli) (doom-cli-context-path context)))) ;; Collect &rest for this command (setf (doom-cli-context-command context) key @@ -893,7 +891,7 @@ executable context." t)) ((push arg arguments) - (doom-log "cli-context-parse: found arg %S" arg))))) + (doom-log "context-parse: found arg %S" arg))))) (setf (alist-get t (doom-cli-context-arguments context)) (append (alist-get t (doom-cli-context-arguments context)) @@ -1111,7 +1109,7 @@ command takes >5s to run. If :benchmark is explicitly set to nil (or `doom-cli-benchmark-threshold' is nil), under no condition should a benchmark be shown." (doom-cli-redirect-output context - (doom-log "cli: %s (GCs: %d, elapsed: %.6fs)" + (doom-log "%s (GCs: %d, elapsed: %.6fs)" (if (= doom-cli--exit-code 254) "Restarted" "Finished") gcs-done gc-elapsed) (when-let* ((init-time (doom-cli-context-init-time context)) @@ -1144,8 +1142,8 @@ If ERROR is provided, store the error in CONTEXT, in case a later CLI wants to read/use it (e.g. like a :help CLI)." (let ((oldcommand (doom-cli-context-command context))) (if oldcommand - (doom-log "cli-call: %s -> %s" oldcommand args) - (doom-log "cli-call: %s" oldcommand args)) + (doom-log "call: %s -> %s" oldcommand args) + (doom-log "call: %s" oldcommand args)) (when error (setf (doom-cli-context-error context) error)) (setf (doom-cli-context-command context) nil @@ -1183,7 +1181,7 @@ Emacs' batch library lacks an implementation of the exec system call." (shell-quote-argument (match-string 2 env))))))) (cl-incf (doom-cli-context-step context)) (with-file-modes #o600 - (doom-log "cli:restart: writing context to %s" context-file) + (doom-log "restart: writing context to %s" context-file) (doom-file-write context-file (let ((newcontext (copy-doom-cli-context context)) (print-level nil) @@ -1199,7 +1197,7 @@ Emacs' batch library lacks an implementation of the exec system call." (convert-buffer doom-cli-context-stdout) (convert-buffer doom-cli-context-stderr)) newcontext)) - (doom-log "cli:restart: writing post-script to %s" script-file) + (doom-log "restart: writing post-script to %s" script-file) (doom-file-write script-file `("#!/usr/bin/env sh\n" "trap _doomcleanup EXIT\n" @@ -1437,7 +1435,7 @@ ARGS are options passed to less. If DOOMPAGER is set, ARGS are ignored." "If CLI is autoloaded, load it, otherwise return it unchanged." (or (when-let* ((path (doom-cli-autoload cli)) (path (locate-file-internal path doom-cli-load-path load-suffixes))) - (doom-log "cli-load: autoload %s" path) + (doom-log "load: autoload %s" path) (let ((doom-cli--plist (doom-cli-plist cli))) (load! path)) (let* ((key (doom-cli-key cli)) @@ -1888,85 +1886,87 @@ Once done, this function kills Emacs gracefully and writes output to log files errors to `doom-cli-error-file')." (when doom-cli--context (error "Cannot nest `run!' calls")) - (let* ((args (flatten-list args)) - (context (make-doom-cli-context :prefix prefix :whole args)) - (doom-cli--context context) - (write-logs-fn (doom-partial #'doom-cli--output-write-logs-h context)) - (show-benchmark-fn (doom-partial #'doom-cli--output-benchmark-h context))) - ;; Clone output to stdout/stderr buffers for logging. - (doom-cli-redirect-output context - (doom-log "run!: %s %s" prefix (combine-and-quote-strings args)) - (add-hook 'kill-emacs-hook show-benchmark-fn 94) - (add-hook 'kill-emacs-hook write-logs-fn 95) - (when (doom-cli-context-pipe-p context :out t) - (setq doom-print-backend nil)) - (when (doom-cli-context-pipe-p context :in) - (with-current-buffer (doom-cli-context-stdin context) - (while (if-let (in (ignore-errors (read-from-minibuffer ""))) - (insert in "\n") - (ignore-errors (delete-char -1)))))) - (doom-cli--exit - (condition-case e - (let* ((args (cons (if (getenv "__DOOMDUMP") :dump prefix) args)) - (context (doom-cli-context-restore (getenv "__DOOMCONTEXT") context)) - (context (doom-cli-context-parse args context))) - (run-hook-with-args 'doom-cli-before-run-functions context) - (let ((result (doom-cli-context-execute context))) - (run-hook-with-args 'doom-cli-after-run-functions context result)) - 0) - (doom-cli-wrong-number-of-arguments-error - (pcase-let ((`(,command ,flag ,args ,min ,max) (cdr e))) - (print! (red "Error: %S expected %s argument%s, but got %d") - (or flag (doom-cli-command-string - (if (keywordp (car command)) - command - (cdr command)))) - (if (or (= min max) - (= max most-positive-fixnum)) - min - (format "%d-%d" min max)) - (if (or (= min 0) (> min 1)) "s" "") - (length args)) - (doom-cli-call `(:help "--synopsis" "--postamble" ,@(cdr (doom-cli--command context))) context e)) - 5) - (doom-cli-unrecognized-option-error - (print! (red "Error: unknown option %s") (cadr e)) - (doom-cli-call `(:help "--synopsis" "--postamble" ,@(cdr (doom-cli--command context))) context e) - 5) - (doom-cli-invalid-option-error - (pcase-let ((`(,types ,option ,value ,errors) (cdr e))) - (print! (red "Error: %s received invalid value %S") - (string-join (doom-cli-option-switches option) "/") - value) - (print! (bold "\nValidation errors:")) - (dolist (err errors) (print! (item "%s." (fill err))))) - (doom-cli-call `(:help "--postamble" ,@(cdr (doom-cli--command context))) context e) - 5) - (doom-cli-command-not-found-error - (let* ((command (cdr e)) - (cli (doom-cli-get command))) - (cond ((null cli) - (print! (red "Error: unrecognized command '%s'") - (doom-cli-command-string (or (cdr command) command))) - (doom-cli-call `(:help "--similar" "--postamble" ,@(cdr command)) context e)) - ((null (doom-cli-fn cli)) - (print! (red "Error: a subcommand is required")) - (doom-cli-call `(:help "--subcommands" "--postamble" ,@(cdr command)) context e)))) - 4) - (doom-cli-invalid-prefix-error - (let ((prefix (cadr e))) - (print! (red "Error: `run!' called with invalid prefix %S") prefix) - (if-let (suggested (cl-loop for cli being the hash-value of doom-cli--table - unless (doom-cli-type cli) - return (car (doom-cli-command cli)))) - (print! "Did you mean %S?" suggested) - (print! "There are no commands defined under %S." prefix))) - 4) - (user-error - (print! (red "Error: %s") (cadr e)) - (print! "\nAborting...") - 3)) - context)))) + (doom-run-hooks 'doom-after-init-hook) + (doom-context-with 'cli + (let* ((args (flatten-list args)) + (context (make-doom-cli-context :prefix prefix :whole args)) + (doom-cli--context context) + (write-logs-fn (doom-partial #'doom-cli--output-write-logs-h context)) + (show-benchmark-fn (doom-partial #'doom-cli--output-benchmark-h context))) + ;; Clone output to stdout/stderr buffers for logging. + (doom-cli-redirect-output context + (doom-log "run!: %s %s" prefix (combine-and-quote-strings args)) + (add-hook 'kill-emacs-hook show-benchmark-fn 94) + (add-hook 'kill-emacs-hook write-logs-fn 95) + (when (doom-cli-context-pipe-p context :out t) + (setq doom-print-backend nil)) + (when (doom-cli-context-pipe-p context :in) + (with-current-buffer (doom-cli-context-stdin context) + (while (if-let (in (ignore-errors (read-from-minibuffer ""))) + (insert in "\n") + (ignore-errors (delete-char -1)))))) + (doom-cli--exit + (condition-case e + (let* ((args (cons (if (getenv "__DOOMDUMP") :dump prefix) args)) + (context (doom-cli-context-restore (getenv "__DOOMCONTEXT") context)) + (context (doom-cli-context-parse args context))) + (run-hook-with-args 'doom-cli-before-run-functions context) + (let ((result (doom-cli-context-execute context))) + (run-hook-with-args 'doom-cli-after-run-functions context result)) + 0) + (doom-cli-wrong-number-of-arguments-error + (pcase-let ((`(,command ,flag ,args ,min ,max) (cdr e))) + (print! (red "Error: %S expected %s argument%s, but got %d") + (or flag (doom-cli-command-string + (if (keywordp (car command)) + command + (cdr command)))) + (if (or (= min max) + (= max most-positive-fixnum)) + min + (format "%d-%d" min max)) + (if (or (= min 0) (> min 1)) "s" "") + (length args)) + (doom-cli-call `(:help "--synopsis" "--postamble" ,@(cdr (doom-cli--command context))) context e)) + 5) + (doom-cli-unrecognized-option-error + (print! (red "Error: unknown option %s") (cadr e)) + (doom-cli-call `(:help "--synopsis" "--postamble" ,@(cdr (doom-cli--command context))) context e) + 5) + (doom-cli-invalid-option-error + (pcase-let ((`(,types ,option ,value ,errors) (cdr e))) + (print! (red "Error: %s received invalid value %S") + (string-join (doom-cli-option-switches option) "/") + value) + (print! (bold "\nValidation errors:")) + (dolist (err errors) (print! (item "%s." (fill err))))) + (doom-cli-call `(:help "--postamble" ,@(cdr (doom-cli--command context))) context e) + 5) + (doom-cli-command-not-found-error + (let* ((command (cdr e)) + (cli (doom-cli-get command))) + (cond ((null cli) + (print! (red "Error: unrecognized command '%s'") + (doom-cli-command-string (or (cdr command) command))) + (doom-cli-call `(:help "--similar" "--postamble" ,@(cdr command)) context e)) + ((null (doom-cli-fn cli)) + (print! (red "Error: a subcommand is required")) + (doom-cli-call `(:help "--subcommands" "--postamble" ,@(cdr command)) context e)))) + 4) + (doom-cli-invalid-prefix-error + (let ((prefix (cadr e))) + (print! (red "Error: `run!' called with invalid prefix %S") prefix) + (if-let (suggested (cl-loop for cli being the hash-value of doom-cli--table + unless (doom-cli-type cli) + return (car (doom-cli-command cli)))) + (print! "Did you mean %S?" suggested) + (print! "There are no commands defined under %S." prefix))) + 4) + (user-error + (print! (red "Error: %s") (cadr e)) + (print! "\nAborting...") + 3)) + context))))) (defalias 'sh! #'doom-call-process) @@ -1998,5 +1998,12 @@ errors to `doom-cli-error-file')." ;; Kill manually so we don't save output to logs. (let (kill-emacs) (kill-emacs 0)))) + +;; +;;; Last minute initialization + +(when noninteractive + (doom-run-hooks 'doom-before-init-hook)) + (provide 'doom-cli) ;;; doom-cli.el ends here diff --git a/lisp/doom-lib.el b/lisp/doom-lib.el index f7d677185..4b242eddc 100644 --- a/lisp/doom-lib.el +++ b/lisp/doom-lib.el @@ -17,6 +17,10 @@ ;; ;;; Logging +(defun doom--log (text) + (let ((inhibit-message (not init-file-debug))) + (message "%s" (propertize text 'face 'font-lock-doc-face)))) + (defmacro doom-log (output &rest args) "Log a message in *Messages*. @@ -25,15 +29,17 @@ function to prevent the potentially expensive evaluation of its arguments when debug mode is off." (declare (debug t)) `(when (or init-file-debug noninteractive) - (let ((inhibit-message (not init-file-debug))) - (message - "%s" (propertize - ;; Byte compiler: don't complain about more args than %-sequences. - (with-no-warnings - (format (concat "* %.06f: " ,output) - (float-time (time-subtract (current-time) before-init-time)) - ,@args)) - 'face 'font-lock-doc-face))))) + (doom--log + (with-no-warnings ; suppress 'more args than %-sequences' warning + (let* ((output ,output) + (absolute? (string-prefix-p ":" output))) + (format (concat "* %.06f%s" (if absolute? output (concat ":" output))) + (float-time (time-subtract (current-time) before-init-time)) + (let ((context (remq t (reverse doom-context)))) + (if (and context (not absolute?)) + (concat "::" (mapconcat #'symbol-name context ":")) + "")) + ,@args)))))) ;; diff --git a/lisp/doom-packages.el b/lisp/doom-packages.el index 36b0ed6c6..e8506feaa 100644 --- a/lisp/doom-packages.el +++ b/lisp/doom-packages.el @@ -410,39 +410,40 @@ installed." ;;; Package getters (defun doom-packages--read (file &optional noeval noerror) - (condition-case-unless-debug e - (with-temp-buffer ; prevent buffer-local state from propagating - (let* ((doom--current-module (doom-module-from-path file)) - (doom--current-flags - (doom-module-get (car doom--current-module) - (cdr doom--current-module) - :flags))) - (if (not noeval) - (load file noerror 'nomessage 'nosuffix) - (when (file-exists-p file) - (insert-file-contents file) - (let (emacs-lisp-mode) (emacs-lisp-mode)) - ;; Scrape `package!' blocks from FILE for a comprehensive listing of - ;; packages used by this module. - (while (search-forward "(package!" nil t) - (let ((ppss (save-excursion (syntax-ppss)))) - ;; Don't collect packages in comments or strings - (unless (or (nth 3 ppss) - (nth 4 ppss)) - (goto-char (match-beginning 0)) - (cl-destructuring-bind (_ name . plist) - (read (current-buffer)) - (push (cons - name (plist-put - plist :modules - (list doom--current-module))) - doom-packages))))))))) - (user-error - (user-error (error-message-string e))) - (error - (signal 'doom-package-error - (list (doom-module-from-path file) - file e))))) + (doom-context-with 'packages + (condition-case-unless-debug e + (with-temp-buffer ; prevent buffer-local state from propagating + (let* ((doom--current-module (doom-module-from-path file)) + (doom--current-flags + (doom-module-get (car doom--current-module) + (cdr doom--current-module) + :flags))) + (if (not noeval) + (load file noerror 'nomessage 'nosuffix) + (when (file-exists-p file) + (insert-file-contents file) + (let (emacs-lisp-mode) (emacs-lisp-mode)) + ;; Scrape `package!' blocks from FILE for a comprehensive listing of + ;; packages used by this module. + (while (search-forward "(package!" nil t) + (let ((ppss (save-excursion (syntax-ppss)))) + ;; Don't collect packages in comments or strings + (unless (or (nth 3 ppss) + (nth 4 ppss)) + (goto-char (match-beginning 0)) + (cl-destructuring-bind (_ name . plist) + (read (current-buffer)) + (push (cons + name (plist-put + plist :modules + (list doom--current-module))) + doom-packages))))))))) + (user-error + (user-error (error-message-string e))) + (error + (signal 'doom-package-error + (list (doom-module-from-path file) + file e)))))) (defun doom-package-list (&optional module-list) "Retrieve a list of explicitly declared packages from MODULE-LIST. @@ -454,7 +455,7 @@ also be a list of module keys." (let ((module-list (cond ((null module-list) (doom-module-list)) ((symbolp module-list) (doom-module-list 'all)) (module-list))) - ;; TODO: doom-module-context + doom-context + ;; TODO: doom-module-context (packages-file doom-module-packages-file) doom-disabled-packages doom-packages) @@ -552,10 +553,13 @@ elsewhere." (cl-callf plist-put plist :ignore built-in)) `(let* ((name ',name) (plist (cdr (assq name doom-packages))) - (dir (dir!))) + (dir (dir!)) + (module (doom-module-from-path dir))) + (unless (doom-context-p 'packages) + (signal 'doom-module-error + (list module "package! can only be used in packages.el files"))) ;; Record what module this declaration was found in - (let ((module-list (plist-get plist :modules)) - (module (doom-module-from-path dir))) + (let ((module-list (plist-get plist :modules))) (unless (member module module-list) (cl-callf plist-put plist :modules (append module-list diff --git a/lisp/doom-profiles.el b/lisp/doom-profiles.el index 593d316cc..39417dc1f 100644 --- a/lisp/doom-profiles.el +++ b/lisp/doom-profiles.el @@ -365,15 +365,10 @@ Defaults to the profile at `doom-profile-default'." (let ((v (version-to-list doom-version)) (ref (doom-call-process "git" "-C" (doom-path doom-emacs-dir) "rev-parse" "HEAD")) (branch (doom-call-process "git" "-C" (doom-path doom-emacs-dir) "branch" "--show-current"))) - ;; FIX: The `doom-init-time' guard protects us from a nefarious edge case in - ;; which Emacs' interpreter, while lazy-loading docstrings in - ;; byte-compiled elisp, ends up re-evaluating the whole file. This can - ;; happen rapidly, multiple times, if something loads these docstrings (by - ;; calling the `documentation' function) rapidly, which is the case for - ;; `marginalia' and each symbol in the M-x and describe-* command - ;; completion lists. By guarding the expensive part of this file, this - ;; process becomes instant. - `((unless doom-init-time + ;; FIX: Make sure this only runs at startup to protect us Emacs' interpreter + ;; re-evaluating this file when lazy-loading dynamic docstrings from the + ;; byte-compiled init file. + `((when (doom-context-p 'init) ,@(cl-loop for var in doom-autoloads-cached-vars if (boundp var) collect `(set-default ',var ',(symbol-value var))) @@ -411,28 +406,30 @@ Defaults to the profile at `doom-profile-default'." if (doom-module-locate-path cat mod file) collect (module-loader cat mod it noerror)))) ;; FIX: Same as above (see `doom-profile--generate-init-vars'). - `((unless doom-init-time - (set 'doom-modules ',doom-modules) - (set 'doom-disabled-packages ',doom-disabled-packages) - ;; Cache module state and flags in symbol plists for quick lookup by - ;; `modulep!' later. - ,@(cl-loop - for (category . modules) in (seq-group-by #'car config-modules-list) - collect - `(setplist ',category - (quote ,(cl-loop for (_ . module) in modules - nconc `(,module ,(get category module)))))) - (let ((old-custom-file custom-file)) - ,@(module-list-loader pre-init-modules init-file) - (doom-run-hooks 'doom-before-modules-init-hook) - ,@(module-list-loader init-modules init-file) - (doom-run-hooks 'doom-after-modules-init-hook) - (doom-run-hooks 'doom-before-modules-config-hook) - ,@(module-list-loader config-modules config-file) - (doom-run-hooks 'doom-after-modules-config-hook) - ,@(module-list-loader post-config-modules config-file t) - (when (eq custom-file old-custom-file) - (doom-load custom-file 'noerror)))))))) + `((if (or (doom-context-p 'init) + (doom-context-p 'reload)) + (doom-context-with 'modules + (set 'doom-modules ',doom-modules) + (set 'doom-disabled-packages ',doom-disabled-packages) + ;; Cache module state and flags in symbol plists for quick lookup by + ;; `modulep!' later. + ,@(cl-loop + for (category . modules) in (seq-group-by #'car config-modules-list) + collect + `(setplist ',category + (quote ,(cl-loop for (_ . module) in modules + nconc `(,module ,(get category module)))))) + (let ((old-custom-file custom-file)) + ,@(module-list-loader pre-init-modules init-file) + (doom-run-hooks 'doom-before-modules-init-hook) + ,@(module-list-loader init-modules init-file) + (doom-run-hooks 'doom-after-modules-init-hook) + (doom-run-hooks 'doom-before-modules-config-hook) + ,@(module-list-loader config-modules config-file) + (doom-run-hooks 'doom-after-modules-config-hook) + ,@(module-list-loader post-config-modules config-file t) + (when (eq custom-file old-custom-file) + (doom-load custom-file 'noerror))))))))) (defun doom-profile--generate-doom-autoloads () (doom-autoloads--scan diff --git a/lisp/doom-start.el b/lisp/doom-start.el index 17c4988cf..bf1ccc00c 100644 --- a/lisp/doom-start.el +++ b/lisp/doom-start.el @@ -302,7 +302,7 @@ If RETURN-P, return the message as a string instead of displaying it." (doom-load-envvars-file doom-env-file 'noerror)) ;;; Last minute setup -(add-hook 'doom-after-init-hook #'doom-load-packages-incrementally-h) +(add-hook 'doom-after-init-hook #'doom-load-packages-incrementally-h 100) (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)) diff --git a/lisp/doom.el b/lisp/doom.el index 84dbb1bc8..582583f55 100644 --- a/lisp/doom.el +++ b/lisp/doom.el @@ -442,6 +442,67 @@ users).") (setq command-line-x-option-alist nil)))) +;; +;;; `doom-context' + +(defvar doom-context '(t) + "A list of symbols identifying all active Doom execution contexts. + +This should never be directly changed, only let-bound, and should never be +empty. Each context describes what phase Doom is in, and may respond to. + +All valid contexts: + cli -- while executing a Doom CLI + compile -- while byte-compilation is in progress + eval -- during inline evaluation of elisp + init -- while doom is formally starting up for the first time, after its + core libraries are loaded, but before user config is. + modules -- while loading modules and their files + sandbox -- This session was launched from Doom's sandbox. + packages -- when packagedefs are being read + reload -- while reloading doom") +(put 'doom-context 'valid-values '(cli compile eval init modules packages reload sandbox)) +(put 'doom-context 'risky-local-variable t) + +(defun doom-context--check (context) + (let ((valid (get 'doom-context 'valid-values))) + (unless (memq context valid) + (signal 'doom-context-error + (list context "Unrecognized context" valid))))) + +(defun doom-context-p (context) + "Return t if CONTEXT is active (i.e. in `doom-context')." + (if (memq context doom-context) t)) + +(defun doom-context-push (context) + "Add CONTEXT to `doom-context', if it isn't already. + +Return non-nil if successful. Throws an error if CONTEXT is invalid." + (unless (memq context doom-context) + (doom-context--check context) + (doom-log ":context: +%s %s" context doom-context) + (push context doom-context))) + +(defun doom-context-pop (context &optional strict?) + "Remove CONTEXT from `doom-context'. + +Return non-nil if successful. If STRICT? is non-nil, throw an error if CONTEXT +wasn't active when this was called." + (if (not (doom-context-p context)) + (when strict? + (signal 'doom-context-error + (list doom-context "Attempt to pop missing context" context))) + (doom-log ":context: -%s %s" context doom-context) + (setq doom-context (delq context doom-context)))) + +(defmacro doom-context-with (contexts &rest body) + "Evaluate BODY with CONTEXT added to `doom-context'." + (declare (indent 1)) + `(let ((doom-context doom-context)) + (dolist (context (ensure-list ,contexts)) + (doom-context-push context)) + ,@body)) + ;; ;;; Reasonable, global defaults @@ -588,21 +649,25 @@ appropriately against `noninteractive' or the `cli' context." ;; ;;; 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))))) +(add-hook! 'doom-before-init-hook :depth -105 + (defun doom--begin-init-h () + "Begin the startup process." + (when (doom-context-push 'init) + ;; 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)))))) -(add-hook! 'doom-after-init-hook :depth -110 +(add-hook! 'doom-after-init-hook :depth 105 (defun doom--end-init-h () "Set `doom-init-time'." - (setq doom-init-time (float-time (time-subtract (current-time) before-init-time))))) + (when (doom-context-pop 'init) + (setq doom-init-time (float-time (time-subtract (current-time) before-init-time)))))) -;; 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)) +(unless noninteractive + ;; 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 diff --git a/lisp/lib/config.el b/lisp/lib/config.el index 418fb2c82..d128b1997 100644 --- a/lisp/lib/config.el +++ b/lisp/lib/config.el @@ -11,10 +11,6 @@ (defvar doom-before-reload-hook nil "A list of hooks to run before `doom/reload' has reloaded Doom.") -;;;###autoload -(defvar doom-reloading-p nil - "TODO") - ;;;###autoload (defun doom/open-private-config () "Browse your `doom-user-dir'." @@ -85,7 +81,7 @@ Runs `doom-after-reload-hook' afterwards." (interactive) (mapc #'require (cdr doom-incremental-packages)) (doom--if-compile (format "%S sync -e" doom-bin) - (let ((doom-reloading-p t)) + (doom-with-context '(reload modules) (doom-run-hooks 'doom-before-reload-hook) (doom-load (file-name-concat doom-user-dir doom-module-init-file) t) (with-demoted-errors "PRIVATE CONFIG ERROR: %s" @@ -110,10 +106,11 @@ line." (interactive) (require 'doom-profiles) ;; TODO: Make this more robust - (dolist (file (mapcar #'car doom-profile-generators)) - (when (string-match-p "/[0-9]+-loaddefs[.-]" file) - (load (doom-path doom-profile-dir doom-profile-init-dir-name file) - 'noerror)))) + (doom-with-context 'reload + (dolist (file (mapcar #'car doom-profile-generators)) + (when (string-match-p "/[0-9]+-loaddefs[.-]" file) + (load (doom-path doom-profile-dir doom-profile-init-dir-name file) + 'noerror))))) ;;;###autoload (defun doom/reload-env () @@ -125,10 +122,11 @@ Doing so from within Emacs will taint your shell environment. An envvar file contains a snapshot of your shell environment, which can be imported into Emacs." (interactive) - (let ((default-directory doom-emacs-dir)) - (with-temp-buffer - (doom-load-envvars-file doom-env-file) - (message "Reloaded %S" (abbreviate-file-name doom-env-file))))) + (doom-with-context 'reload + (let ((default-directory doom-emacs-dir)) + (with-temp-buffer + (doom-load-envvars-file doom-env-file) + (message "Reloaded %S" (abbreviate-file-name doom-env-file)))))) ;;;###autoload (defun doom/upgrade () diff --git a/modules/editor/evil/init.el b/modules/editor/evil/init.el index 79f27125d..a53f148e8 100644 --- a/modules/editor/evil/init.el +++ b/modules/editor/evil/init.el @@ -20,7 +20,7 @@ ;; `evil-collection-list' (now I can just copy it from time to time). (when (and (not noninteractive) - (not doom-reloading-p) + (not (doom-context-p 'reload)) (modulep! +everywhere)) (setq evil-collection-company-use-tng (modulep! :completion company +tng) diff --git a/modules/lang/emacs-lisp/autoload.el b/modules/lang/emacs-lisp/autoload.el index 6e7d620e1..4fd26dd82 100644 --- a/modules/lang/emacs-lisp/autoload.el +++ b/modules/lang/emacs-lisp/autoload.el @@ -14,7 +14,8 @@ to a pop up buffer." (unwind-protect (condition-case-unless-debug e (let ((doom--current-module (ignore-errors (doom-module-from-path buffer-file-name)))) - (eval-region beg end buffer load-read-function) + (doom-context-with 'eval + (eval-region beg end buffer load-read-function)) (with-current-buffer buffer (let ((pp-max-width nil)) (require 'pp) diff --git a/modules/lang/org/config.el b/modules/lang/org/config.el index 173c05031..0d8285c27 100644 --- a/modules/lang/org/config.el +++ b/modules/lang/org/config.el @@ -1417,7 +1417,7 @@ between the two." ;; In case the user has eagerly loaded org from their configs (when (and (featurep 'org) (not byte-compile-current-file)) - (unless doom-reloading-p + (unless (doom-context-p 'reload) (message "`org' was already loaded by the time lang/org loaded, this may cause issues")) (run-hooks 'org-load-hook))