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:
parent
1c4217aa27
commit
f9201eb218
12 changed files with 290 additions and 210 deletions
9
bin/doom
9
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)
|
||||
|
|
|
@ -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)
|
||||
|
|
201
lisp/doom-cli.el
201
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
|
||||
|
|
|
@ -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))))))
|
||||
|
||||
|
||||
;;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
87
lisp/doom.el
87
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
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue