2022-09-12 18:05:14 +02:00
|
|
|
;;; early-init.el --- Doom's universal bootstrapper -*- lexical-binding: t -*-
|
2022-06-18 15:04:12 +02:00
|
|
|
;;; Commentary:
|
|
|
|
;;
|
2022-09-25 13:28:29 +02:00
|
|
|
;; This file, in summary:
|
|
|
|
;; - Determines where `user-emacs-directory' is by:
|
|
|
|
;; - Processing `--init-directory DIR' (backported from Emacs 29),
|
|
|
|
;; - Processing `--profile NAME' (see
|
|
|
|
;; `https://docs.doomemacs.org/-/developers' or docs/developers.org),
|
|
|
|
;; - Or assume that it's the directory this file lives in.
|
|
|
|
;; - Loads Doom as efficiently as possible, with only the essential startup
|
|
|
|
;; optimizations, and prepares it for interactive or non-interactive sessions.
|
|
|
|
;; - If Doom isn't present, then we assume that Doom is being used as a
|
|
|
|
;; bootloader and the user wants to load a non-Doom config, so we undo all our
|
|
|
|
;; global side-effects, load `user-emacs-directory'/early-init.el, and carry
|
|
|
|
;; on as normal (without Doom).
|
|
|
|
;; - Do all this without breaking compatibility with Chemacs.
|
2022-06-18 15:04:12 +02:00
|
|
|
;;
|
2022-09-25 13:28:29 +02:00
|
|
|
;; early-init.el was introduced in Emacs 27.1. It is loaded before init.el,
|
|
|
|
;; before Emacs initializes its UI or package.el, and before site files are
|
|
|
|
;; loaded. This is great place for startup optimizing, because only here can you
|
|
|
|
;; *prevent* things from loading, rather than turn them off after-the-fact.
|
2022-07-27 12:06:07 +02:00
|
|
|
;;
|
2022-09-25 13:28:29 +02:00
|
|
|
;; Doom uses this file as its "universal bootstrapper" for both interactive and
|
|
|
|
;; non-interactive sessions. That means: no matter what environment you want
|
|
|
|
;; Doom in, load this file first.
|
2022-06-18 15:04:12 +02:00
|
|
|
;;
|
|
|
|
;;; Code:
|
2018-03-28 00:41:57 -04:00
|
|
|
|
2022-09-06 21:01:46 +02:00
|
|
|
;; PERF: Garbage collection is a big contributor to startup times. This fends it
|
2024-02-06 16:56:59 -05:00
|
|
|
;; off, but will be reset later by `gcmh-mode' (or in doom-cli.el, if in a
|
|
|
|
;; noninteractive session). Not resetting it later causes stuttering/freezes.
|
2019-07-21 03:01:15 +02:00
|
|
|
(setq gc-cons-threshold most-positive-fixnum)
|
2018-09-19 00:25:17 +01:00
|
|
|
|
2022-09-13 13:08:37 +02:00
|
|
|
;; PERF: Don't use precious startup time checking mtime on elisp bytecode.
|
|
|
|
;; Ensuring correctness is 'doom sync's job, not the interactive session's.
|
2024-02-06 16:56:59 -05:00
|
|
|
;; Still, stale byte-code will cause *heavy* losses in startup efficiency, but
|
|
|
|
;; performance is unimportant when Emacs is in an error state.
|
2022-09-13 13:08:37 +02:00
|
|
|
(setq load-prefer-newer noninteractive)
|
2022-06-18 15:04:12 +02:00
|
|
|
|
2024-02-06 16:56:59 -05:00
|
|
|
;; UX: Respect DEBUG envvar as an alternative to --debug-init, and to make
|
2022-09-17 20:07:51 +02:00
|
|
|
;; startup sufficiently verbose from this point on.
|
|
|
|
(when (getenv-internal "DEBUG")
|
|
|
|
(setq init-file-debug t
|
|
|
|
debug-on-error t))
|
|
|
|
|
2022-07-27 11:15:30 +02:00
|
|
|
|
2022-07-27 12:05:56 +02:00
|
|
|
;;
|
|
|
|
;;; Bootstrap
|
2022-07-27 11:15:30 +02:00
|
|
|
|
2022-09-13 13:08:37 +02:00
|
|
|
(or
|
|
|
|
;; PERF: `file-name-handler-alist' is consulted often. Unsetting it offers a
|
2024-02-06 16:56:59 -05:00
|
|
|
;; notable saving in startup time. This is just a stopgap though; this
|
|
|
|
;; optimization is continued more comprehensively in lisp/doom.el.
|
2022-09-13 13:08:37 +02:00
|
|
|
(let (file-name-handler-alist)
|
2024-02-06 15:48:39 -05:00
|
|
|
(let (;; FIX: Unset `command-line-args' in noninteractive sessions, to
|
|
|
|
;; ensure upstream switches aren't misinterpreted.
|
|
|
|
(command-line-args (unless noninteractive command-line-args))
|
|
|
|
;; I avoid using `command-switch-alist' to process --profile (and
|
|
|
|
;; --init-directory) because it is processed too late to change
|
|
|
|
;; `user-emacs-directory' in time.
|
|
|
|
(profile (or (cadr (member "--profile" command-line-args))
|
|
|
|
(getenv-internal "DOOMPROFILE"))))
|
2022-09-17 20:54:28 +02:00
|
|
|
(if (null profile)
|
|
|
|
;; REVIEW: Backported from Emacs 29. Remove when 28 support is dropped.
|
|
|
|
(let ((init-dir (or (cadr (member "--init-directory" command-line-args))
|
|
|
|
(getenv-internal "EMACSDIR"))))
|
|
|
|
(if (null init-dir)
|
|
|
|
;; FIX: If we've been loaded directly (via 'emacs -batch -l
|
|
|
|
;; early-init.el') or by a doomscript (like bin/doom), and Doom
|
|
|
|
;; is in a non-standard location (and/or Chemacs is used), then
|
|
|
|
;; `user-emacs-directory' will be wrong.
|
|
|
|
(when noninteractive
|
|
|
|
(setq user-emacs-directory
|
|
|
|
(file-name-directory (file-truename load-file-name))))
|
|
|
|
;; FIX: To prevent "invalid option" errors later.
|
|
|
|
(push (cons "--init-directory" (lambda (_) (pop argv))) command-switch-alist)
|
|
|
|
(setq user-emacs-directory (expand-file-name init-dir))))
|
2022-09-13 13:08:37 +02:00
|
|
|
;; FIX: Discard the switch to prevent "invalid option" errors later.
|
|
|
|
(push (cons "--profile" (lambda (_) (pop argv))) command-switch-alist)
|
2022-09-17 22:02:50 +02:00
|
|
|
;; Running 'doom sync' or 'doom profile sync' (re)generates a light
|
|
|
|
;; profile loader in $EMACSDIR/profiles/load.el (or
|
|
|
|
;; $DOOMPROFILELOADFILE), after reading `doom-profile-load-path'. This
|
|
|
|
;; loader requires `$DOOMPROFILE' be set to function.
|
refactor!: complete profile gen and init systems
BREAKING CHANGE: This commit makes three breaking changes:
- Doom now fully and dynamically generates (and byte-compiles) your
profile and its init files, which includes your autoloads, loading
your init files and modules, and then some. This replaces
doom-initialize-modules, doom-initialize-core-modules, and
doom-module-loader, which have been removed. This has also improved
startup time by a bit, but if you use these functions in your CLIs,
for instance, this will be a breaking change.
- `doom sync` is now required for Doom to see your profiles (and must be
run whenever you change them, or when you up/downgrade Emacs across
major versions).
- $DOOMDIR/init.el is now read much earlier than it used to be. Before
any of doom-{ui,keybinds,editor,projects}, before any autoloads are
loaded, and before your load-path has been populated with your
packages. It now runs in the context of early-init.el, giving users
freer range over what they can affect, but a more minimalistic
environment to do it in.
If you must have some logic run when all that is set up, add it to one
of the module hooks added in e08f68b or 283308a.
This also poses a significant change to Doom's load order (see the
commentary change in lib/doom.el), along with the following (non
breaking) changes:
1. Adds a new `doom profiles sync` command. This will forcibly resync
your profiles, while `doom sync` will only do so if your profiles
have changed.
2. Doom now fully and dynamically generates (and byte-compiles) your
user-init-file, which includes loading all your init files, modules,
and custom-file. This replaces the job of doom-initialize-modules,
doom-initialize-core-modules, and doom-module-loader, which have been
removed. This has also improved startup time by a bit.
3. Defines new doom-state-dir variable, though not used yet (saving that
and the other breaking changes for the 3.0 release).
4. Redesigns profile directory variables (doom-profile-*-dir) to prepare
for future XDG-compliance.
5. Removed unused/unimportant profile variables in doom.el.
6. Added lisp/doom-profiles.el. It's hardly feature complete, but it's
enough to power the system as it is now.
7. Updates the "load order" commentary in doom.el to reflect these
changes.
2022-09-15 18:53:06 +02:00
|
|
|
(setenv "DOOMPROFILE" profile)
|
2022-09-17 22:02:50 +02:00
|
|
|
(or (load (expand-file-name
|
|
|
|
(format (let ((lfile (getenv-internal "DOOMPROFILELOADFILE")))
|
|
|
|
(if lfile
|
2024-02-06 16:38:58 -05:00
|
|
|
(concat (let ((suffix ".el"))
|
|
|
|
(if (string-suffix-p suffix lfile)
|
|
|
|
(substring lfile 0 (- (length lfile) (length suffix)))
|
|
|
|
lfile))
|
2022-09-17 22:02:50 +02:00
|
|
|
".%d.elc")
|
|
|
|
"profiles/load.%d.elc"))
|
|
|
|
emacs-major-version)
|
|
|
|
user-emacs-directory)
|
2022-09-17 20:21:43 +02:00
|
|
|
'noerror (not init-file-debug) 'nosuffix)
|
refactor!: complete profile gen and init systems
BREAKING CHANGE: This commit makes three breaking changes:
- Doom now fully and dynamically generates (and byte-compiles) your
profile and its init files, which includes your autoloads, loading
your init files and modules, and then some. This replaces
doom-initialize-modules, doom-initialize-core-modules, and
doom-module-loader, which have been removed. This has also improved
startup time by a bit, but if you use these functions in your CLIs,
for instance, this will be a breaking change.
- `doom sync` is now required for Doom to see your profiles (and must be
run whenever you change them, or when you up/downgrade Emacs across
major versions).
- $DOOMDIR/init.el is now read much earlier than it used to be. Before
any of doom-{ui,keybinds,editor,projects}, before any autoloads are
loaded, and before your load-path has been populated with your
packages. It now runs in the context of early-init.el, giving users
freer range over what they can affect, but a more minimalistic
environment to do it in.
If you must have some logic run when all that is set up, add it to one
of the module hooks added in e08f68b or 283308a.
This also poses a significant change to Doom's load order (see the
commentary change in lib/doom.el), along with the following (non
breaking) changes:
1. Adds a new `doom profiles sync` command. This will forcibly resync
your profiles, while `doom sync` will only do so if your profiles
have changed.
2. Doom now fully and dynamically generates (and byte-compiles) your
user-init-file, which includes loading all your init files, modules,
and custom-file. This replaces the job of doom-initialize-modules,
doom-initialize-core-modules, and doom-module-loader, which have been
removed. This has also improved startup time by a bit.
3. Defines new doom-state-dir variable, though not used yet (saving that
and the other breaking changes for the 3.0 release).
4. Redesigns profile directory variables (doom-profile-*-dir) to prepare
for future XDG-compliance.
5. Removed unused/unimportant profile variables in doom.el.
6. Added lisp/doom-profiles.el. It's hardly feature complete, but it's
enough to power the system as it is now.
7. Updates the "load order" commentary in doom.el to reflect these
changes.
2022-09-15 18:53:06 +02:00
|
|
|
(user-error "Profiles not initialized yet; run 'doom sync' first"))))
|
2022-09-13 13:08:37 +02:00
|
|
|
|
|
|
|
;; PERF: When `load'ing or `require'ing files, each permutation of
|
|
|
|
;; `load-suffixes' and `load-file-rep-suffixes' (then `load-suffixes' +
|
2024-02-06 16:56:59 -05:00
|
|
|
;; `load-file-rep-suffixes') is used to locate the file. Each permutation
|
|
|
|
;; amounts to at least one file op, which is normally very fast, but can
|
|
|
|
;; add up over the hundreds/thousands of files Emacs loads.
|
2022-09-13 13:08:37 +02:00
|
|
|
;;
|
|
|
|
;; To reduce that burden -- and since Doom doesn't load any dynamic modules
|
2024-02-06 16:56:59 -05:00
|
|
|
;; this early -- I remove `.so' from `load-suffixes' and pass the
|
|
|
|
;; `must-suffix' arg to `load'. See the docs of `load' for details.
|
2022-09-16 11:51:19 +02:00
|
|
|
(if (let ((load-suffixes '(".elc" ".el")))
|
2024-03-11 00:47:13 -04:00
|
|
|
;; I avoid `load's NOERROR argument because it suppresses other,
|
|
|
|
;; legitimate errors (like permission or IO errors), which gets
|
|
|
|
;; incorrectly interpreted as "this is not a Doom config".
|
2022-09-25 13:25:15 +02:00
|
|
|
(condition-case _
|
|
|
|
;; Load the heart of Doom Emacs.
|
|
|
|
(load (expand-file-name "lisp/doom" user-emacs-directory)
|
|
|
|
nil (not init-file-debug) nil 'must-suffix)
|
|
|
|
;; Failing that, assume that we're loading a non-Doom config.
|
|
|
|
(file-missing
|
2022-10-02 18:06:58 +02:00
|
|
|
;; HACK: `startup--load-user-init-file' resolves $EMACSDIR from a
|
2024-02-06 16:56:59 -05:00
|
|
|
;; lexical (and so, not-trivially-modifiable)
|
|
|
|
;; `startup-init-directory', so Emacs will fail to locate the
|
|
|
|
;; correct $EMACSDIR/init.el without help.
|
2022-10-02 18:06:58 +02:00
|
|
|
(define-advice startup--load-user-init-file (:filter-args (args) reroute-to-profile)
|
|
|
|
(list (lambda () (expand-file-name "init.el" user-emacs-directory))
|
|
|
|
nil (nth 2 args)))
|
2024-02-06 16:56:59 -05:00
|
|
|
;; (Re)set `user-init-file' for the `load' call further below, and
|
|
|
|
;; do so here while our `file-name-handler-alist' optimization is
|
|
|
|
;; still effective (benefits `expand-file-name'). BTW: Emacs resets
|
2022-09-25 13:25:15 +02:00
|
|
|
;; `user-init-file' and `early-init-file' after this file is loaded.
|
|
|
|
(setq user-init-file (expand-file-name "early-init" user-emacs-directory))
|
|
|
|
;; COMPAT: I make no assumptions about the config we're going to
|
|
|
|
;; load, so undo this file's global side-effects.
|
|
|
|
(setq load-prefer-newer t)
|
|
|
|
;; PERF: But make an exception for `gc-cons-threshold', which I
|
|
|
|
;; think all Emacs users and configs will benefit from. Still,
|
|
|
|
;; setting it to `most-positive-fixnum' is dangerous if downstream
|
|
|
|
;; does not reset it later to something reasonable, so I use 16mb
|
|
|
|
;; as a best fit guess. It's better than Emacs' 80kb default.
|
|
|
|
(setq gc-cons-threshold (* 16 1024 1024))
|
|
|
|
nil)))
|
2024-02-06 16:56:59 -05:00
|
|
|
;; ...Otherwise, we're loading a Doom config, so continue as normal.
|
2022-09-25 13:25:15 +02:00
|
|
|
(doom-require (if noninteractive 'doom-cli 'doom-start))))
|
2022-09-13 13:08:37 +02:00
|
|
|
|
|
|
|
;; Then continue on to the config/profile we want to load.
|
2022-09-25 13:08:11 +02:00
|
|
|
(load user-init-file 'noerror (not init-file-debug) nil 'must-suffix))
|
2022-06-18 15:04:12 +02:00
|
|
|
|
|
|
|
;;; early-init.el ends here
|