doom-emacs/early-init.el

114 lines
5.8 KiB
EmacsLisp
Raw Normal View History

;;; early-init.el --- Doom's universal bootstrapper -*- lexical-binding: t -*-
;;; Commentary:
;;
;; early-init.el was introduced in Emacs 27.1 and is loaded before init.el, and
;; before Emacs initializes its UI or package.el, and before site files are
;; loaded. This is good place for startup optimizating, because only here can
;; you *prevent* things from loading, rather than turn them off after-the-fact.
;; As such, Doom does all its initializing here.
;;
;; This file is Doom's "universal bootstrapper" for both interactive and
;; non-interactive sessions. It's also the heart of its profile bootloader,
;; which allows you to switch between Emacs configs on demand using
;; `--init-directory DIR' (which was backported from Emacs 29) or `--profile
;; NAME` (more about profiles at `https://docs.doomemacs.org/-/developers' or
;; docs/developers.org).
2022-07-27 10:06:07 +00:00
;;
;; In summary, this file is responsible for:
;; - Setting up some universal startup optimizations.
;; - Determining where `user-emacs-directory' is from one of:
;; - `--init-directory DIR' (backported from 29)
;; - `--profile PROFILENAME'
;; - Do one of the following:
;; - Load `doom' and one of `doom-start' or `doom-cli'.
;; - Or (if the user is trying to load a non-Doom config) load
;; `user-emacs-directory'/early-init.el.
;;
;;; Code:
2018-03-28 04:41:57 +00:00
;; PERF: Garbage collection is a big contributor to startup times. This fends it
;; off, but will be reset later by `gcmh-mode'. Not resetting it later will
;; cause stuttering/freezes.
(setq gc-cons-threshold most-positive-fixnum)
;; PERF: Don't use precious startup time checking mtime on elisp bytecode.
;; Ensuring correctness is 'doom sync's job, not the interactive session's.
;; Still, stale byte-code will cause *heavy* losses in startup efficiency.
(setq load-prefer-newer noninteractive)
;; UX: Respect DEBUG envvar as an alternative to --debug-init, and to make are
;; startup sufficiently verbose from this point on.
(when (getenv-internal "DEBUG")
(setq init-file-debug t
debug-on-error t))
feat: allow Doom be used as a config bootloader This allows users to use Doom core to switch between Emacs configs (they don't have to be Doom configs either). Taking after Chemacs, these configs (called "profiles") can be declared in $EMACSDIR/profiles.el or implicitly as directories under $EMACSDIR/profiles/ (symlinks work too). Launch a profile with `emacs --profile foo` or by setting $DOOMPROFILE: `DOOMPROFILE=foo emacs`. An example profiles.el looks like this: ((doomemacs (user-emacs-directory . "~/.config/emacs") (env ("DOOMDIR" . "~/.config/doom"))) (spacemacs (user-emacs-directory . "~/.config/spacemacs")) (prelude (user-emacs-directory . "~/.config/prelude")) (altdoom (user-emacs-directory . "~/.config/doomemacs") (env ("DOOMDIR" . "~/.config/doomprivate1"))) (altdoom2 (user-emacs-directory . "~/.config/doomemacs") (env ("DOOMDIR" . "~/.config/doomprivate2")))) Chemacs users will find the format of this file familiar; the biggest differences are: - Keys are symbols, not strings - There is no, special "default" profile. The fallback profile is the Doom Emacs config doing the bootloading, living in ~/.config/emacs or ~/.emacs.d. If you don't like that, set $DOOMPROFILE in your dotfiles to the name of another profile. WARNING: bin/doom does not understand --profile or $DOOMPROFILE yet. To sync a particular profile, you'll have to run its bin/doom directly, e.g. To sync the "global" doom: ~/.config/emacs/bin/doom sync To sync your "altdoom" (and "altdoom2") profiles: ~/.config/doomemacs/bin/doom sync
2022-07-27 10:05:56 +00:00
;;
;;; Bootstrap
(or
;; PERF: `file-name-handler-alist' is consulted often. Unsetting it offers a
;; notable saving in startup time. This let-binding is just a stopgap though,
;; a more complete version of this optimization can be found in lisp/doom.el.
(let (file-name-handler-alist)
;; First, we process --init-directory and --profile to detect what
;; `user-emacs-directory' to load from. 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.
(let ((profile (or (cadr (member "--profile" command-line-args))
(getenv-internal "DOOMPROFILE"))))
(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))))
;; FIX: Discard the switch to prevent "invalid option" errors later.
(push (cons "--profile" (lambda (_) (pop argv))) command-switch-alist)
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 16:53:06 +00:00
;; Running 'doom sync' will (re)generate a lightweight profile
;; bootstrapper in $EMACSDIR/profiles/init.el, after reading
;; $EMACSDIR/profiles.el, $DOOMDIR/profiles,
;; $XDG_CONFIG_HOME/doom-profiles.el, and ~/.doom-profiles.el. All it
;; needs is for `$DOOMPROFILE' to be set.
(setenv "DOOMPROFILE" profile)
(or (load (expand-file-name (format "profiles/init.%d.elc" emacs-major-version)
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 16:53:06 +00:00
user-emacs-directory)
'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 16:53:06 +00:00
(user-error "Profiles not initialized yet; run 'doom sync' first"))))
;; PERF: When `load'ing or `require'ing files, each permutation of
;; `load-suffixes' and `load-file-rep-suffixes' (then `load-suffixes' +
;; `load-file-rep-suffixes') is used to locate the file. Each permutation
;; is a file op, which is normally very fast, but they can add up over the
;; hundreds/thousands of files Emacs needs to load.
;;
;; To reduce that burden -- and since Doom doesn't load any dynamic modules
;; -- I remove `.so' from `load-suffixes' and pass the `must-suffix' arg to
;; `load'. See the docs of `load' for details.
(if (let ((load-suffixes '(".elc" ".el")))
;; Load the heart of Doom Emacs.
(load (expand-file-name "lisp/doom" user-emacs-directory)
'noerror (not init-file-debug) nil 'must-suffix))
;; ...and prepare for the rest of the session.
(doom-require (if noninteractive 'doom-cli 'doom-start))
;; Failing that, assume we're loading a non-Doom config and prepare.
(setq user-init-file (expand-file-name "early-init" user-emacs-directory)
;; I make no assumptions about the config we're about to load, so
;; to limit side-effects, undo any leftover optimizations:
load-prefer-newer t)
nil))
;; Then continue on to the config/profile we want to load.
(load early-init-file 'noerror (not init-file-debug) nil 'must-suffix))
;;; early-init.el ends here