refactor: introduce doom-context

Introduces a system to announce what execution contexts are active, so I
can react appropriately, emit more helpful logs/warnings in the case of
issues, and throw more meaningful errors.

* bin/doom: load module CLIs in the 'modules' context.
* lisp/cli/doctor.el: load package files in 'packages' context.
* lisp/doom-cli.el:
  - (doom-before-init-hook, doom-after-init-hook): trigger hooks at the
    correct time. This may increase startup load time, as the benchmark
    now times more of the startup process.
  - (doom-cli-execute, doom-cli-context-execute,
    doom-cli-context-restore, doom-cli-context-parse,
    doom-cli--output-benchmark-h, doom-cli-call, doom-cli--restart,
    doom-cli-load, run!): remove redundant context prefix in debug logs,
    it's now redundant with doom-context, which doom-log now prefixes
    them with.
* lisp/doom-lib.el (doom-log): prefix doom-context to doom-log output,
  unless it starts with :.
* lisp/doom-packages.el (package!, doom-packages--read): throw error if
  not used in a packages.el file or in the context of our package
  manager.
* lisp/doom-profiles.el (doom-profile--generate-init-vars,
  doom-profile--generate-load-modules): use modules doom-context instead
  of doom-init-time to detect startup.
* lisp/doom-start.el (doom-load-packages-incrementally-h): move function
  closer to end of doom-after-init-hook.
* lisp/doom.el:
  - (doom-before-init-hook, doom--set-initial-values-h,
    doom--begin-init-h): rename doom--set-initial-values-h to
    doom--begin-init-h and ensure it runs as late in
    doom-before-init-hook as possible, as that is the point where Doom's
    "initialization" formally begins.
  - (doom-after-init-hook): don't trigger at the end of command-line-1
    in non-interactive sessions. This will be triggered manually in
    doom-cli.el's run!.
* lisp/lib/config.el (doom/reload, doom/reload-autoloads,
  doom/reload-env): use 'reload' context for reload commands.
* modules/lang/emacs-lisp/autoload.el (+emacs-lisp-eval): use 'eval'
  context.
* modules/lang/org/config.el: remove doom-reloading-p; check for
  'reload' doom context instead.
This commit is contained in:
Henrik Lissner 2022-09-24 12:38:25 +02:00
parent 1c4217aa27
commit f9201eb218
No known key found for this signature in database
GPG key ID: B60957CA074D39A3
12 changed files with 290 additions and 210 deletions

View file

@ -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