refactor: reformat doom.el and use doom-lib
Move startup optimizations after core globals, so we can employ doom-lib's API.
This commit is contained in:
parent
7a2be67efa
commit
18cd2eb483
2 changed files with 203 additions and 227 deletions
|
@ -2,6 +2,20 @@
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
;;; Custom error types
|
||||||
|
(define-error 'doom-error "An unexpected Doom error")
|
||||||
|
(define-error 'doom-core-error "Unexpected error in Doom's core" 'doom-error)
|
||||||
|
(define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error)
|
||||||
|
(define-error 'doom-autoload-error "Error in Doom's autoloads file" 'doom-error)
|
||||||
|
(define-error 'doom-user-error "Error caused by user's config or system" 'doom-error)
|
||||||
|
(define-error 'doom-module-error "Error in a Doom module" 'doom-error)
|
||||||
|
(define-error 'doom-package-error "Error with packages" 'doom-error)
|
||||||
|
(define-error 'doom-profile-error "Error while processing profiles" 'doom-error)
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;;; Logging
|
||||||
|
|
||||||
(defmacro doom-log (output &rest args)
|
(defmacro doom-log (output &rest args)
|
||||||
"Log a message in *Messages*.
|
"Log a message in *Messages*.
|
||||||
|
|
||||||
|
|
416
lisp/doom.el
416
lisp/doom.el
|
@ -50,6 +50,7 @@
|
||||||
;;
|
;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
;;; Version checks
|
||||||
(eval-and-compile ; Check version at both compile and runtime.
|
(eval-and-compile ; Check version at both compile and runtime.
|
||||||
;; Doom's minimum supported version of Emacs is 27.1. Its my goal to support
|
;; Doom's minimum supported version of Emacs is 27.1. Its my goal to support
|
||||||
;; one major version below the stable release, for about a year or until
|
;; one major version below the stable release, for about a year or until
|
||||||
|
@ -87,143 +88,48 @@
|
||||||
"recompile it.")
|
"recompile it.")
|
||||||
emacs-version old-version)))
|
emacs-version old-version)))
|
||||||
|
|
||||||
;; Remember these variables' initial values, so we can safely reset them at a
|
;;; Custom features
|
||||||
;; later time, or consult them without fear of contamination.
|
;; Since `system-configuration-features's docs state not to rely on it to test
|
||||||
(dolist (var '(exec-path load-path process-environment
|
;; for features, let's give users an easier way to detect them.
|
||||||
load-suffixes load-file-rep-suffixes
|
(if (bound-and-true-p module-file-suffix)
|
||||||
file-name-handler-alist))
|
(push 'dynamic-modules features))
|
||||||
(unless (get var 'initial-value)
|
(if (fboundp #'json-parse-string)
|
||||||
(put var 'initial-value (default-toplevel-value var))))
|
(push 'jansson features))
|
||||||
|
;; `native-compile' exists whether or not it is functional (e.g. libgcc is
|
||||||
|
;; available or not). This seems silly, so pretend it doesn't exist if it
|
||||||
|
;; isn't available.
|
||||||
|
(if (featurep 'native-compile)
|
||||||
|
(if (not (native-comp-available-p))
|
||||||
|
(delq 'native-compile features)))
|
||||||
|
|
||||||
;; Since Emacs 27, package initialization occurs before `user-init-file' is
|
;;; Global constants
|
||||||
;; loaded, but after `early-init-file'. Doom handles package initialization, so
|
;; DEPRECATED remove in v3
|
||||||
;; we must prevent Emacs from doing it again.
|
(defconst IS-MAC (eq system-type 'darwin))
|
||||||
(setq package-enable-at-startup nil)
|
(defconst IS-LINUX (memq system-type '(gnu gnu/linux gnu/kfreebsd berkeley-unix)))
|
||||||
|
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
|
||||||
|
(defconst IS-BSD (memq system-type '(darwin berkeley-unix gnu/kfreebsd)))
|
||||||
|
(defconst EMACS28+ (> emacs-major-version 27))
|
||||||
|
(defconst EMACS29+ (> emacs-major-version 28))
|
||||||
|
(defconst MODULES (featurep 'dynamic-modules))
|
||||||
|
(defconst NATIVECOMP (featurep 'native-compile))
|
||||||
|
|
||||||
|
(make-obsolete-variable 'EMACS28+ "Use (>= emacs-major-version 28) instead" "3.0.0")
|
||||||
|
(make-obsolete-variable 'EMACS29+ "Use (>= emacs-major-version 29) instead" "3.0.0")
|
||||||
|
(make-obsolete-variable 'MODULES "Use (featurep 'dynamic-modules) instead" "3.0.0")
|
||||||
|
(make-obsolete-variable 'NATIVECOMP "Use (featurep 'native-compile) instead" "3.0.0")
|
||||||
|
|
||||||
;;
|
;;; Fix $HOME on Windows
|
||||||
;;; Startup optimizations
|
;; $HOME isn't normally defined on Windows, but many unix tools expect it.
|
||||||
|
(when IS-WINDOWS
|
||||||
|
(when-let (realhome
|
||||||
|
(and (null (getenv-internal "HOME"))
|
||||||
|
(getenv "USERPROFILE")))
|
||||||
|
(setenv "HOME" realhome)
|
||||||
|
(setq abbreviated-home-dir nil)))
|
||||||
|
|
||||||
;; Here are Doom's hackiest (and least offensive) startup optimizations. They
|
;;; Load Doom's stdlib
|
||||||
;; exploit implementation details and unintended side-effects, and will change
|
(add-to-list 'load-path (file-name-directory load-file-name))
|
||||||
;; often between major Emacs releases. I've (roughly) ordered them from most to
|
(require 'doom-lib)
|
||||||
;; least effective (on Linux), and disable them if this is a daemon session
|
|
||||||
;; (where startup time matters less) or in debug-mode (to mitigate interference
|
|
||||||
;; with our debugging).
|
|
||||||
(unless (or (daemonp) init-file-debug)
|
|
||||||
;; PERF: `file-name-handler-alist' is consulted on each call to `require',
|
|
||||||
;; `load', or various file/io functions (like `expand-file-name' or
|
|
||||||
;; `file-remote-p'). You get a noteable boost to startup time by unsetting
|
|
||||||
;; or simplifying its value.
|
|
||||||
(let ((old-value (get 'file-name-handler-alist 'initial-value)))
|
|
||||||
(setq file-name-handler-alist
|
|
||||||
;; HACK: If the bundled elisp for this Emacs install isn't
|
|
||||||
;; byte-compiled (but is compressed), then leave the gzip file
|
|
||||||
;; handler there so Emacs won't forget how to read read them.
|
|
||||||
;;
|
|
||||||
;; calc-loaddefs.el is our heuristic for this because it is built-in
|
|
||||||
;; to all supported versions of Emacs, and calc.el explicitly loads
|
|
||||||
;; it uncompiled. This ensures that the only other, possible
|
|
||||||
;; fallback would be calc-loaddefs.el.gz.
|
|
||||||
(if (eval-when-compile
|
|
||||||
(if (locate-file-internal "calc-loaddefs.el" load-path) t))
|
|
||||||
nil
|
|
||||||
(list (rassq 'jka-compr-handler old-value))))
|
|
||||||
;; Make sure the new value survives any current let-binding.
|
|
||||||
(set-default-toplevel-value 'file-name-handler-alist file-name-handler-alist)
|
|
||||||
;; COMPAT: ...but restore `file-name-handler-alist' later, because it is
|
|
||||||
;; needed for handling encrypted or compressed files, among other things.
|
|
||||||
(defun doom-reset-file-handler-alist-h ()
|
|
||||||
(setq file-name-handler-alist
|
|
||||||
;; Merge instead of overwrite because there may have been changes to
|
|
||||||
;; `file-name-handler-alist' since startup we want to preserve.
|
|
||||||
(delete-dups (append file-name-handler-alist old-value))))
|
|
||||||
(add-hook 'emacs-startup-hook #'doom-reset-file-handler-alist-h 101))
|
|
||||||
|
|
||||||
(unless noninteractive
|
|
||||||
;; PERF: Resizing the Emacs frame (to accommodate fonts that are smaller or
|
|
||||||
;; larger than the system font) appears to impact startup time
|
|
||||||
;; dramatically. The larger the delta in font size, the greater the delay.
|
|
||||||
;; Even trivial deltas can yield a ~1000ms loss, though it varies wildly
|
|
||||||
;; depending on font size.
|
|
||||||
(setq frame-inhibit-implied-resize t)
|
|
||||||
|
|
||||||
;; PERF: Emacs supports a "default init file", which is a library named
|
|
||||||
;; "default.el" living anywhere in your `load-path' (or `$EMACSLOADPATH').
|
|
||||||
;; It's loaded after $EMACSDIR/init.el, but there really is no reason to
|
|
||||||
;; do so. Doom doesn't define one, users shouldn't use one, and it seems
|
|
||||||
;; too magical when an explicit `-l FILE' would do. I do away with it for
|
|
||||||
;; the *miniscule* savings in file IO spent trying to load it.
|
|
||||||
(setq inhibit-default-init t)
|
|
||||||
|
|
||||||
;; PERF,UX: Reduce *Message* noise at startup. An empty scratch buffer (or
|
|
||||||
;; the dashboard) is more than enough, and faster to display.
|
|
||||||
(setq inhibit-startup-screen t
|
|
||||||
inhibit-startup-echo-area-message user-login-name)
|
|
||||||
;; PERF,UX: Remove "For information about GNU Emacs..." message at startup.
|
|
||||||
;; It's redundant with our dashboard and incurs a premature redraw.
|
|
||||||
(advice-add #'display-startup-echo-area-message :override #'ignore)
|
|
||||||
|
|
||||||
;; PERF: Shave seconds off startup time by starting the scratch buffer in
|
|
||||||
;; `fundamental-mode', rather than, say, `org-mode' or `text-mode', which
|
|
||||||
;; pull in a ton of packages. `doom/open-scratch-buffer' provides a better
|
|
||||||
;; scratch buffer anyway.
|
|
||||||
(setq initial-major-mode 'fundamental-mode
|
|
||||||
initial-scratch-message nil)
|
|
||||||
|
|
||||||
;; PERF: Inexplicably, `tty-run-terminal-initialization' can sometimes take
|
|
||||||
;; 2-3s when starting up Emacs in the terminal. Whatever slows it down at
|
|
||||||
;; startup doesn't appear to affect it if it's called a little later in
|
|
||||||
;; the startup process, so that's what I do.
|
|
||||||
;; REVIEW: This optimization is not understood. Investigate this properly!
|
|
||||||
(advice-add #'tty-run-terminal-initialization :override #'ignore)
|
|
||||||
(defun doom-init-tty-h ()
|
|
||||||
(advice-remove #'tty-run-terminal-initialization #'ignore)
|
|
||||||
(tty-run-terminal-initialization (selected-frame) nil t))
|
|
||||||
(add-hook 'window-setup-hook #'doom-init-tty-h)
|
|
||||||
|
|
||||||
;; PERF,UX: Site files tend to use `load-file', which emits "Loading X..."
|
|
||||||
;; messages in the echo area. Writing to the echo-area triggers a
|
|
||||||
;; redisplay, which can be expensive during startup. This may also cause
|
|
||||||
;; an flash of white when creating the first frame.
|
|
||||||
(define-advice load-file (:override (file) silence)
|
|
||||||
(load file nil 'nomessage))
|
|
||||||
;; COMPAT: But undo our `load-file' advice later, as to limit the scope of
|
|
||||||
;; any edge cases it could induce.
|
|
||||||
(define-advice startup--load-user-init-file (:before (&rest _) undo-silence)
|
|
||||||
(advice-remove #'load-file #'load-file@silence))
|
|
||||||
|
|
||||||
;; PERF: `load-suffixes' and `load-file-rep-suffixes' are consulted on each
|
|
||||||
;; `require' and `load'. Doom won't load any dmodules this early, so omit
|
|
||||||
;; .so for a small startup boost. This is later restored in doom-start.
|
|
||||||
(set-default-toplevel-value 'load-suffixes '(".elc" ".el"))
|
|
||||||
(set-default-toplevel-value 'load-file-rep-suffixes '(""))
|
|
||||||
|
|
||||||
;; PERF: The mode-line procs a couple dozen times during startup. This is
|
|
||||||
;; normally quite fast, but disabling the default mode-line and reducing the
|
|
||||||
;; update delay timer seems to stave off ~30-50ms.
|
|
||||||
(setq-default mode-line-format nil)
|
|
||||||
(dolist (buf (buffer-list))
|
|
||||||
(with-current-buffer buf (setq mode-line-format nil)))
|
|
||||||
;; PERF,UX: Premature redisplays can substantially affect startup times and
|
|
||||||
;; produce ugly flashes of unstyled Emacs.
|
|
||||||
(setq-default inhibit-redisplay t
|
|
||||||
inhibit-message t)
|
|
||||||
;; COMPAT: Then reset it with advice, because `startup--load-user-init-file'
|
|
||||||
;; will never be interrupted by errors. And if these settings are left
|
|
||||||
;; set, Emacs could appear frozen or garbled.
|
|
||||||
(define-advice startup--load-user-init-file (:after (&rest _) undo-inhibit-vars)
|
|
||||||
(setq-default inhibit-redisplay nil
|
|
||||||
inhibit-message nil)
|
|
||||||
(unless (default-toplevel-value 'mode-line-format)
|
|
||||||
(setq-default mode-line-format (get 'mode-line-format 'initial-value))))
|
|
||||||
|
|
||||||
;; PERF: Unset a non-trivial list of command line options that aren't
|
|
||||||
;; relevant to our current OS, but `command-line-1' still processes.
|
|
||||||
(unless IS-MAC
|
|
||||||
(setq command-line-ns-option-alist nil))
|
|
||||||
(when (or IS-MAC IS-WINDOWS)
|
|
||||||
(setq command-line-x-option-alist nil))))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
@ -236,87 +142,33 @@
|
||||||
(defconst doom-version "3.0.0-dev"
|
(defconst doom-version "3.0.0-dev"
|
||||||
"Current version of Doom Emacs core.")
|
"Current version of Doom Emacs core.")
|
||||||
|
|
||||||
|
;; DEPRECATED: Remove these when the modules are moved out of core.
|
||||||
(defconst doom-modules-version "22.09.0-dev"
|
(defconst doom-modules-version "22.09.0-dev"
|
||||||
"Current version of Doom Emacs.")
|
"Current version of Doom Emacs.")
|
||||||
|
|
||||||
(defconst doom-profile
|
(defconst doom-profile
|
||||||
(if-let (profile (getenv-internal "DOOMPROFILE"))
|
(if-let (profile (getenv-internal "DOOMPROFILE"))
|
||||||
;; DEPRECATED Use `string-search' once 27 support is dropped
|
(save-match-data
|
||||||
(if (string-match-p "@" profile)
|
(if (string-match "^\\([^@]+\\)@\\(.+\\)$" profile)
|
||||||
profile
|
(cons (match-string 1 profile)
|
||||||
(concat profile "@latest"))
|
(match-string 2 profile))
|
||||||
;; TODO Restore this when profile system is complete
|
(cons profile "0")))
|
||||||
;; "default@latest"
|
;; TODO Restore this in 3.0
|
||||||
|
;; (cons "_" "0")
|
||||||
)
|
)
|
||||||
"The name of the active profile.")
|
"The active profile as a cons cell (NAME . VERSION).")
|
||||||
|
|
||||||
|
;;; Data directory variables
|
||||||
(defconst doom-emacs-dir user-emacs-directory
|
(defconst doom-emacs-dir user-emacs-directory
|
||||||
"The path to the currently loaded .emacs.d directory. Must end with a slash.")
|
"The path to the currently loaded .emacs.d directory. Must end with a slash.")
|
||||||
|
|
||||||
(defconst doom-core-dir (file-name-directory load-file-name)
|
(defconst doom-core-dir (file-name-directory load-file-name)
|
||||||
"The root directory of Doom's core files. Must end with a slash.")
|
"The root directory of Doom's core files. Must end with a slash.")
|
||||||
|
|
||||||
|
|
||||||
;; DEPRECATED
|
|
||||||
(defconst IS-MAC (eq system-type 'darwin))
|
|
||||||
(defconst IS-LINUX (memq system-type '(gnu gnu/linux gnu/kfreebsd berkeley-unix)))
|
|
||||||
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
|
|
||||||
(defconst IS-BSD (memq system-type '(darwin berkeley-unix gnu/kfreebsd)))
|
|
||||||
|
|
||||||
(unless (featurep 'doom)
|
|
||||||
;; Since `system-configuration-features's docs state not to rely on it to test
|
|
||||||
;; for features, let's give users an easier way to detect them.
|
|
||||||
(if (bound-and-true-p module-file-suffix)
|
|
||||||
(push 'dynamic-modules features))
|
|
||||||
(if (fboundp #'json-parse-string)
|
|
||||||
(push 'jansson features))
|
|
||||||
;; `native-compile' exists whether or not it is functional (e.g. libgcc is
|
|
||||||
;; available or not). This seems silly, so pretend it doesn't exist if it
|
|
||||||
;; isn't available.
|
|
||||||
(if (featurep 'native-compile)
|
|
||||||
(if (not (native-comp-available-p))
|
|
||||||
(delq 'native-compile features)))
|
|
||||||
|
|
||||||
;; DEPRECATED remove in v3
|
|
||||||
(defconst EMACS28+ (> emacs-major-version 27))
|
|
||||||
(defconst EMACS29+ (> emacs-major-version 28))
|
|
||||||
;; DEPRECATED remove in v3
|
|
||||||
(defconst MODULES (featurep 'dynamic-modules))
|
|
||||||
(defconst NATIVECOMP (featurep 'native-compile)))
|
|
||||||
|
|
||||||
;;; Custom error types
|
|
||||||
(define-error 'doom-error "An unexpected Doom error")
|
|
||||||
(define-error 'doom-core-error "Unexpected error in Doom's core" 'doom-error)
|
|
||||||
(define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error)
|
|
||||||
(define-error 'doom-autoload-error "Error in Doom's autoloads file" 'doom-error)
|
|
||||||
(define-error 'doom-user-error "Error caused by user's config or system" 'doom-error)
|
|
||||||
(define-error 'doom-module-error "Error in a Doom module" 'doom-error)
|
|
||||||
(define-error 'doom-package-error "Error with packages" 'doom-error)
|
|
||||||
(define-error 'doom-profile-error "Error while processing profiles" 'doom-error)
|
|
||||||
|
|
||||||
;;; Platform-specific fixes
|
|
||||||
;; Fix $HOME on Windows, where it's not normally defined, because many unix
|
|
||||||
;; tools expect it.
|
|
||||||
(when IS-WINDOWS
|
|
||||||
(when-let (realhome
|
|
||||||
(and (null (getenv-internal "HOME"))
|
|
||||||
(getenv "USERPROFILE")))
|
|
||||||
(setenv "HOME" realhome)
|
|
||||||
(setq abbreviated-home-dir nil)))
|
|
||||||
|
|
||||||
;;; Load Doom stdlib
|
|
||||||
;; Ensure Doom's core libraries are visible for loading
|
|
||||||
(add-to-list 'load-path doom-core-dir)
|
|
||||||
;; Load just the... bear necessities~
|
|
||||||
(require 'doom-lib)
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; File/directory variables
|
|
||||||
|
|
||||||
(defconst doom-modules-dir (expand-file-name "modules/" doom-emacs-dir)
|
(defconst doom-modules-dir (expand-file-name "modules/" doom-emacs-dir)
|
||||||
"The root directory for Doom's modules. Must end with a slash.")
|
"The root directory for Doom's modules. Must end with a slash.")
|
||||||
|
|
||||||
|
(define-obsolete-variable-alias 'doom-private-dir 'doom-user-dir "3.0.0")
|
||||||
(defconst doom-user-dir
|
(defconst doom-user-dir
|
||||||
(expand-file-name
|
(expand-file-name
|
||||||
(if-let (doomdir (getenv-internal "DOOMDIR"))
|
(if-let (doomdir (getenv-internal "DOOMDIR"))
|
||||||
|
@ -333,11 +185,6 @@
|
||||||
Defaults to ~/.config/doom, ~/.doom.d or the value of the DOOMDIR envvar;
|
Defaults to ~/.config/doom, ~/.doom.d or the value of the DOOMDIR envvar;
|
||||||
whichever is found first. Must end in a slash.")
|
whichever is found first. Must end in a slash.")
|
||||||
|
|
||||||
;; TODO Use me
|
|
||||||
(defconst doom-profiles-file
|
|
||||||
(expand-file-name "profiles.el" user-emacs-directory)
|
|
||||||
"TODO")
|
|
||||||
|
|
||||||
(defconst doom-profiles-dir
|
(defconst doom-profiles-dir
|
||||||
(if-let (profilesdir (getenv-internal "DOOMPROFILESDIR"))
|
(if-let (profilesdir (getenv-internal "DOOMPROFILESDIR"))
|
||||||
(expand-file-name "./" profilesdir)
|
(expand-file-name "./" profilesdir)
|
||||||
|
@ -393,6 +240,7 @@ Use this as a storage location for this system's installation of Doom Emacs.
|
||||||
These files should not be shared across systems. By default, it is used by
|
These files should not be shared across systems. By default, it is used by
|
||||||
`doom-data-dir' and `doom-cache-dir'. Must end with a slash.")
|
`doom-data-dir' and `doom-cache-dir'. Must end with a slash.")
|
||||||
|
|
||||||
|
(define-obsolete-variable-alias 'doom-etc-dir 'doom-data-dir "3.0.0")
|
||||||
(defconst doom-data-dir
|
(defconst doom-data-dir
|
||||||
(if doom-profile
|
(if doom-profile
|
||||||
doom-profile-data-dir
|
doom-profile-data-dir
|
||||||
|
@ -433,35 +281,135 @@ users).")
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Legacy support
|
;;; Startup optimizations
|
||||||
|
|
||||||
(define-obsolete-variable-alias 'doom-private-dir 'doom-user-dir "3.0.0")
|
;; Here are Doom's hackiest (and least offensive) startup optimizations. They
|
||||||
(define-obsolete-variable-alias 'doom-etc-dir 'doom-data-dir "3.0.0")
|
;; exploit implementation details and unintended side-effects, and will change
|
||||||
|
;; often between major Emacs releases. I've (roughly) ordered them from most to
|
||||||
|
;; least effective (on Linux), and disable them if this is a daemon session
|
||||||
|
;; (where startup time matters less) or in debug-mode (to mitigate interference
|
||||||
|
;; with our debugging).
|
||||||
|
(unless (or (daemonp) init-file-debug)
|
||||||
|
;; PERF: `file-name-handler-alist' is consulted on each call to `require',
|
||||||
|
;; `load', or various file/io functions (like `expand-file-name' or
|
||||||
|
;; `file-remote-p'). You get a noteable boost to startup time by unsetting
|
||||||
|
;; or simplifying its value.
|
||||||
|
(let ((old-value (get 'file-name-handler-alist 'initial-value)))
|
||||||
|
(setq file-name-handler-alist
|
||||||
|
;; HACK: If the bundled elisp for this Emacs install isn't
|
||||||
|
;; byte-compiled (but is compressed), then leave the gzip file
|
||||||
|
;; handler there so Emacs won't forget how to read read them.
|
||||||
|
;;
|
||||||
|
;; calc-loaddefs.el is our heuristic for this because it is built-in
|
||||||
|
;; to all supported versions of Emacs, and calc.el explicitly loads
|
||||||
|
;; it uncompiled. This ensures that the only other, possible
|
||||||
|
;; fallback would be calc-loaddefs.el.gz.
|
||||||
|
(if (eval-when-compile
|
||||||
|
(locate-file-internal "calc-loaddefs.el" load-path))
|
||||||
|
nil
|
||||||
|
(list (rassq 'jka-compr-handler old-value))))
|
||||||
|
;; Make sure the new value survives any current let-binding.
|
||||||
|
(set-default-toplevel-value 'file-name-handler-alist file-name-handler-alist)
|
||||||
|
;; COMPAT: ...but restore `file-name-handler-alist' later, because it is
|
||||||
|
;; needed for handling encrypted or compressed files, among other things.
|
||||||
|
(add-hook! 'emacs-startup-hook :depth 101
|
||||||
|
(defun doom--reset-file-handler-alist-h ()
|
||||||
|
(setq file-name-handler-alist
|
||||||
|
;; Merge instead of overwrite because there may have been changes to
|
||||||
|
;; `file-name-handler-alist' since startup we want to preserve.
|
||||||
|
(delete-dups (append file-name-handler-alist old-value))))))
|
||||||
|
|
||||||
|
(unless noninteractive
|
||||||
|
;; PERF: Resizing the Emacs frame (to accommodate fonts that are smaller or
|
||||||
|
;; larger than the system font) appears to impact startup time
|
||||||
|
;; dramatically. The larger the delta in font size, the greater the delay.
|
||||||
|
;; Even trivial deltas can yield a ~1000ms loss, though it varies wildly
|
||||||
|
;; depending on font size.
|
||||||
|
(setq frame-inhibit-implied-resize t)
|
||||||
|
|
||||||
|
;; PERF: Emacs supports a "default init file", which is a library named
|
||||||
|
;; "default.el" living anywhere in your `load-path' (or `$EMACSLOADPATH').
|
||||||
|
;; It's loaded after $EMACSDIR/init.el, but there really is no reason to
|
||||||
|
;; do so. Doom doesn't define one, users shouldn't use one, and it seems
|
||||||
|
;; too magical when an explicit `-l FILE' would do. I do away with it for
|
||||||
|
;; the *miniscule* savings in file IO spent trying to load it.
|
||||||
|
(setq inhibit-default-init t)
|
||||||
|
|
||||||
|
;; PERF,UX: Reduce *Message* noise at startup. An empty scratch buffer (or
|
||||||
|
;; the dashboard) is more than enough, and faster to display.
|
||||||
|
(setq inhibit-startup-screen t
|
||||||
|
inhibit-startup-echo-area-message user-login-name)
|
||||||
|
;; PERF,UX: Remove "For information about GNU Emacs..." message at startup.
|
||||||
|
;; It's redundant with our dashboard and incurs a premature redraw.
|
||||||
|
(advice-add #'display-startup-echo-area-message :override #'ignore)
|
||||||
|
|
||||||
|
;; PERF: Shave seconds off startup time by starting the scratch buffer in
|
||||||
|
;; `fundamental-mode', rather than, say, `org-mode' or `text-mode', which
|
||||||
|
;; pull in a ton of packages. `doom/open-scratch-buffer' provides a better
|
||||||
|
;; scratch buffer anyway.
|
||||||
|
(setq initial-major-mode 'fundamental-mode
|
||||||
|
initial-scratch-message nil)
|
||||||
|
|
||||||
|
;; PERF: Inexplicably, `tty-run-terminal-initialization' can sometimes take
|
||||||
|
;; 2-3s when starting up Emacs in the terminal. Whatever slows it down at
|
||||||
|
;; startup doesn't appear to affect it if it's called a little later in
|
||||||
|
;; the startup process, so that's what I do.
|
||||||
|
;; REVIEW: This optimization is not understood. Investigate this properly!
|
||||||
|
(advice-add #'tty-run-terminal-initialization :override #'ignore)
|
||||||
|
(add-hook! 'window-setup-hook
|
||||||
|
(defun doom--reset-tty-run-terminal-initialization-h ()
|
||||||
|
(advice-remove #'tty-run-terminal-initialization #'ignore)
|
||||||
|
(tty-run-terminal-initialization (selected-frame) nil t)))
|
||||||
|
|
||||||
|
;; PERF,UX: Site files tend to use `load-file', which emits "Loading X..."
|
||||||
|
;; messages in the echo area. Writing to the echo-area triggers a
|
||||||
|
;; redisplay, which can be expensive during startup. This may also cause
|
||||||
|
;; an flash of white when creating the first frame.
|
||||||
|
(define-advice load-file (:override (file) silence)
|
||||||
|
(load file nil 'nomessage))
|
||||||
|
;; COMPAT: But undo our `load-file' advice later, as to limit the scope of
|
||||||
|
;; any edge cases it could induce.
|
||||||
|
(define-advice startup--load-user-init-file (:before (&rest _) undo-silence)
|
||||||
|
(advice-remove #'load-file #'load-file@silence))
|
||||||
|
|
||||||
|
;; PERF: `load-suffixes' and `load-file-rep-suffixes' are consulted on each
|
||||||
|
;; `require' and `load'. Doom won't load any dmodules this early, so omit
|
||||||
|
;; .so for a small startup boost. This is later restored in doom-start.
|
||||||
|
(set-default-toplevel-value 'load-suffixes '(".elc" ".el"))
|
||||||
|
(set-default-toplevel-value 'load-file-rep-suffixes '(""))
|
||||||
|
|
||||||
|
;; PERF: The mode-line procs a couple dozen times during startup. This is
|
||||||
|
;; normally quite fast, but disabling the default mode-line and reducing the
|
||||||
|
;; update delay timer seems to stave off ~30-50ms.
|
||||||
|
(setq-default mode-line-format nil)
|
||||||
|
(dolist (buf (buffer-list))
|
||||||
|
(with-current-buffer buf (setq mode-line-format nil)))
|
||||||
|
;; PERF,UX: Premature redisplays can substantially affect startup times and
|
||||||
|
;; produce ugly flashes of unstyled Emacs.
|
||||||
|
(setq-default inhibit-redisplay t
|
||||||
|
inhibit-message t)
|
||||||
|
;; COMPAT: Then reset it with advice, because `startup--load-user-init-file'
|
||||||
|
;; will never be interrupted by errors. And if these settings are left
|
||||||
|
;; set, Emacs could appear frozen or garbled.
|
||||||
|
(define-advice startup--load-user-init-file (:after (&rest _) undo-inhibit-vars)
|
||||||
|
(setq-default inhibit-redisplay nil
|
||||||
|
inhibit-message nil)
|
||||||
|
(unless (default-toplevel-value 'mode-line-format)
|
||||||
|
(setq-default mode-line-format (get 'mode-line-format 'initial-value))))
|
||||||
|
|
||||||
|
;; PERF: Unset a non-trivial list of command line options that aren't
|
||||||
|
;; relevant to our current OS, but `command-line-1' still processes.
|
||||||
|
(unless IS-MAC
|
||||||
|
(setq command-line-ns-option-alist nil))
|
||||||
|
(when (or IS-MAC IS-WINDOWS)
|
||||||
|
(setq command-line-x-option-alist nil))))
|
||||||
|
|
||||||
(make-obsolete-variable 'EMACS28+ "Use (>= emacs-major-version 28) instead" "3.0.0")
|
|
||||||
(make-obsolete-variable 'EMACS29+ "Use (>= emacs-major-version 29) instead" "3.0.0")
|
|
||||||
(make-obsolete-variable 'MODULES "Use (featurep 'dynamic-modules) instead" "3.0.0")
|
|
||||||
(make-obsolete-variable 'NATIVECOMP "Use (featurep 'native-compile) instead" "3.0.0")
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Native Compilation support (http://akrl.sdf.org/gccemacs.html)
|
;;; Reasonable, global defaults
|
||||||
|
|
||||||
(when (boundp 'native-comp-eln-load-path)
|
|
||||||
;; Don't store eln files in ~/.emacs.d/eln-cache (where they can easily be
|
|
||||||
;; deleted by 'doom upgrade').
|
|
||||||
;; REVIEW Use `startup-redirect-eln-cache' when 28 support is dropped
|
|
||||||
(add-to-list 'native-comp-eln-load-path (expand-file-name "eln/" doom-cache-dir))
|
|
||||||
|
|
||||||
;; UX: Suppress compiler warnings and don't inundate users with their popups.
|
|
||||||
;; They are rarely more than warnings, so are safe to ignore.
|
|
||||||
(setq native-comp-async-report-warnings-errors init-file-debug
|
|
||||||
native-comp-warning-on-missing-source init-file-debug))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Don't litter `doom-emacs-dir'/$HOME
|
;;; Don't litter `doom-emacs-dir'/$HOME
|
||||||
|
|
||||||
;; HACK: I change `user-emacs-directory' because many packages (even built-in
|
;; HACK: I change `user-emacs-directory' because many packages (even built-in
|
||||||
;; ones) abuse it to build paths for storage/cache files (instead of correctly
|
;; ones) abuse it to build paths for storage/cache files (instead of correctly
|
||||||
;; using `locate-user-emacs-file'). This change ensures that said data files
|
;; using `locate-user-emacs-file'). This change ensures that said data files
|
||||||
|
@ -499,9 +447,23 @@ Otherwise, `en/disable-command' (in novice.el.gz) is hardcoded to write them to
|
||||||
(let ((user-init-file custom-file))
|
(let ((user-init-file custom-file))
|
||||||
(apply fn args)))
|
(apply fn args)))
|
||||||
|
|
||||||
|
;;; Native compilation support (see http://akrl.sdf.org/gccemacs.html)
|
||||||
|
(when (boundp 'native-comp-eln-load-path)
|
||||||
|
;; Don't store eln files in ~/.emacs.d/eln-cache (where they can easily be
|
||||||
|
;; deleted by 'doom upgrade').
|
||||||
|
;; REVIEW Use `startup-redirect-eln-cache' when 28 support is dropped
|
||||||
|
(add-to-list 'native-comp-eln-load-path (expand-file-name "eln/" doom-cache-dir))
|
||||||
|
|
||||||
;;
|
;; UX: Suppress compiler warnings and don't inundate users with their popups.
|
||||||
;;; Reasonable, global defaults
|
;; They are rarely more than warnings, so are safe to ignore.
|
||||||
|
(setq native-comp-async-report-warnings-errors init-file-debug
|
||||||
|
native-comp-warning-on-missing-source init-file-debug))
|
||||||
|
|
||||||
|
;;; Suppress package.el
|
||||||
|
;; Since Emacs 27, package initialization occurs before `user-init-file' is
|
||||||
|
;; loaded, but after `early-init-file'. Doom handles package initialization, so
|
||||||
|
;; we must prevent Emacs from doing it again.
|
||||||
|
(setq package-enable-at-startup nil)
|
||||||
|
|
||||||
;;; Reduce unnecessary/unactionable warnings/logs
|
;;; Reduce unnecessary/unactionable warnings/logs
|
||||||
;; Disable warnings from the legacy advice API. They aren't actionable or
|
;; Disable warnings from the legacy advice API. They aren't actionable or
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue