Major refactor of Doom bootstrap process

+ New `input` and `buffer` support for :defer in def-package! can now
  defer packages until the first command invoked after startup or first
  interactive buffer switch, respectively
+ Exploit these new :defer techniques to lazy-load many core packages,
  netting Doom a 20-30% decrease in startup time
+ Various userland macros (like package!, def-package-hook!, packages!,
  and disable-packages!) will now throw an error if used incorrectly
  (i.e. outside of their intended files; e.g. package! should be used in
  packages.el files)
+ Removed support for multiple/nested doom! calls. There should only be
  THE ONE in ~/.doom.d/init.el (or ~/.config/doom/init.el)
+ Fix an issue where load-path and auto-mode-list modifications would
  not persist because doom-packages-file was cached too late.
+ Added package-activated-list to cached variables in
  doom-packages-file, thus we no longer need custom-file.
+ Load Doom core files from doom-initialize. Now doom-initialize can be
  called from state-dependent non-interactive functions, instead of
  reloading core/core.el, which was clumsy
+ Removed the doom-post-init-hook hook. There was no reason for it to
  exist when doom-init-hook can simply be appended to
This commit is contained in:
Henrik Lissner 2018-05-14 18:40:35 +02:00
parent bb4a8e98e6
commit bec79a3d4c
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
6 changed files with 268 additions and 229 deletions

View file

@ -59,37 +59,48 @@ fundamental-mode) for performance sake."
(fundamental-mode))))
(add-hook 'find-file-hook #'doom|check-large-file)
(push '("/LICENSE$" . text-mode) auto-mode-alist)
;;
;; Built-in plugins
;;
(electric-indent-mode -1) ; enabled by default in Emacs 25+. No thanks.
(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)
;; revert buffers for changed files
(global-auto-revert-mode 1)
(def-package! autorevert
:defer buffer
:config
(setq auto-revert-verbose nil)
(global-auto-revert-mode +1))
;; enabled by default in Emacs 25+. No thanks.
(electric-indent-mode -1)
;; savehist / saveplace
;; persist variables across sessions
(def-package! savehist
:defer (input . 1)
:config
(setq savehist-file (concat doom-cache-dir "savehist")
savehist-save-minibuffer-history t
savehist-autosave-interval nil ; save on kill only
savehist-additional-variables '(kill-ring search-ring regexp-search-ring)
save-place-file (concat doom-cache-dir "saveplace"))
(add-hook! 'doom-init-hook #'(savehist-mode save-place-mode))
savehist-additional-variables '(kill-ring search-ring regexp-search-ring))
(savehist-mode +1))
;; persistent point location in buffers
(def-package! saveplace
:defer buffer
:config
(setq save-place-file (concat doom-cache-dir "saveplace"))
(defun doom*recenter-on-load-saveplace (&rest _)
"Recenter on cursor when loading a saved place."
(if buffer-file-name (ignore-errors (recenter))))
(advice-add #'save-place-find-file-hook :after-while #'doom*recenter-on-load-saveplace)
(advice-add #'save-place-find-file-hook
:after-while #'doom*recenter-on-load-saveplace)
(save-place-mode +1))
;; Keep track of recently opened files
(def-package! recentf
:hook (doom-init . recentf-mode)
:defer (input . 1)
:commands recentf-open-files
:config
(setq recentf-save-file (concat doom-cache-dir "recentf")
recentf-auto-cleanup 60
@ -101,7 +112,15 @@ fundamental-mode) for performance sake."
"^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$"
"^/var/folders/.+$"
;; ignore private DOOM temp files (but not all of them)
(concat "^" (file-truename doom-local-dir)))))
(concat "^" (file-truename doom-local-dir))))
(recentf-mode +1))
(def-package! server
:when (display-graphic-p)
:defer 2
:config
(unless (server-running-p)
(server-start)))
;;
@ -110,10 +129,9 @@ fundamental-mode) for performance sake."
;; Auto-close delimiters and blocks as you type
(def-package! smartparens
:defer (buffer . 2)
:config
(smartparens-global-mode +1)
(require 'smartparens-config)
(setq sp-highlight-pair-overlay nil
sp-cancel-autoskip-on-backward-movement nil
sp-show-pair-delay 0
@ -124,12 +142,15 @@ fundamental-mode) for performance sake."
(add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode)
(sp-local-pair '(xml-mode nxml-mode php-mode) "<!--" "-->"
:post-handlers '(("| " "SPC"))))
:post-handlers '(("| " "SPC")))
(smartparens-global-mode +1))
;; Branching undo
(def-package! undo-tree
:hook (doom-init . global-undo-tree-mode)
:defer input
:config
(global-undo-tree-mode +1)
;; persistent undo history is known to cause undo history corruption, which
;; can be very destructive! So disable it!
(setq undo-tree-auto-save-history nil

View file

@ -60,6 +60,7 @@ If any hook returns non-nil, all hooks after it are ignored.")
(def-package! hydra
:commands (defhydra defhydradio)
:init
;; In case I later need to wrap defhydra in any special functionality.
(defalias 'def-hydra! 'defhydra)

View file

@ -73,6 +73,17 @@ missing) and shouldn't be deleted.")
(defvar doom-disabled-packages ()
"A list of packages that should be ignored by `def-package!'.")
(defvar doom-deferred-packages
'((input)
(buffer))
"A alist of packages that have been deferred. The CAR is the type of deferral
for the package, the CDR is the list of packages.
input will be loaded on the first action the user invokes
after startup.
buffer will be loaded on the first new buffer to be opened
interactively.")
(defvar doom-reload-hook nil
"A list of hooks to run when `doom/reload-load-path' is called.")
@ -87,10 +98,8 @@ missing) and shouldn't be deleted.")
and `auto-mode-alist'.")
(defvar doom--current-module nil)
(defvar doom--init-cache-p nil)
(defvar doom--initializing nil)
(defvar doom--refreshed-p nil)
(defvar generated-autoload-load-name)
(defvar doom--stage nil)
;;
(setq autoload-compute-prefixes nil
@ -134,11 +143,41 @@ and `auto-mode-alist'.")
;;
;; Startup benchmark
;; Helpers 'n hooks
;;
(defun doom-packages--benchmark ()
(format "Doom loaded %s packages across %d modules in %.03fs"
(defun doom--assert-stage-p (stage macro)
(cl-assert (eq stage doom--stage)
nil
"Found %s call in non-%s.el file (%s)"
macro (symbol-name stage)
(if (file-in-directory-p load-file-name doom-emacs-dir)
(file-relative-name load-file-name doom-emacs-dir)
(abbreviate-file-name load-file-name))))
(defun doom|refresh-cache ()
"Refresh `doom-packages-file', which caches `load-path',
`Info-directory-list', `doom-disabled-packages', `auto-mode-alist' and
`package-activated-list'."
(doom-initialize-packages 'internal)
(let ((coding-system-for-write 'emacs-internal))
(with-temp-file doom-packages-file
(insert ";;; -*- lexical-binding:t -*-\n"
";; This file was autogenerated by `doom|refresh-cache', DO NOT EDIT!\n")
(prin1 `(setq load-path ',load-path
Info-directory-list ',Info-directory-list
auto-mode-alist ',auto-mode-alist
doom-disabled-packages ',doom-disabled-packages
package-activated-list ',package-activated-list)
(current-buffer)))))
(defun doom|display-benchmark (&optional return-p)
"Display a benchmark, showing number of packages and modules, and how quickly
they were loaded at startup.
If RETURN-P, return the message as a string instead of displaying it."
(funcall (if return-p #'format #'message)
"Doom loaded %s packages across %d modules in %.03fs"
;; Certainly imprecise, especially where custom additions to
;; load-path are concerned, but I don't mind a [small] margin of
;; error in the plugin count in exchange for faster startup.
@ -147,24 +186,14 @@ and `auto-mode-alist'.")
(or doom-init-time
(setq doom-init-time (float-time (time-subtract (current-time) before-init-time))))))
(add-hook 'emacs-startup-hook #'doom|display-benchmark)
(add-hook 'doom-reload-hook #'doom|display-benchmark)
;;
;; Bootstrap API
;;
(defun doom--refresh-cache ()
"TODO"
(when doom--init-cache-p
(doom-initialize-packages 'internal)
(unless noninteractive
(with-temp-buffer
(prin1 `(setq load-path ',load-path
Info-directory-list ',Info-directory-list
doom-disabled-packages ',doom-disabled-packages)
(current-buffer))
(write-file doom-packages-file))
(setq doom--init-cache-p nil))))
(defun doom-initialize (&optional force-p)
"Bootstrap the bare essentials to get Doom running, if it hasn't already. If
FORCE-P is non-nil, do it anyway.
@ -180,12 +209,14 @@ FORCE-P is non-nil, do it anyway.
(require 'cl-lib)
(require 'map))
(when (or force-p (not doom-init-p))
(unless (load doom-autoload-file t t t)
;; autoloads file
(unless (load doom-autoload-file 'noerror 'nomessage 'nosuffix)
(unless noninteractive
(error "No autoloads file! Run make autoloads")))
(when (and noninteractive (file-exists-p doom-packages-file))
;; packages.el cache
(when (and force-p (file-exists-p doom-packages-file))
(delete-file doom-packages-file))
(when (or force-p (not (load doom-packages-file t t t)))
(unless (load doom-packages-file 'noerror 'nomessage 'nosuffix)
;; Ensure core folders exist, otherwise we get errors
(dolist (dir (list doom-local-dir doom-etc-dir doom-cache-dir doom-packages-dir))
(unless (file-directory-p dir)
@ -195,7 +226,8 @@ FORCE-P is non-nil, do it anyway.
(setq package-activated-list nil
package--initialized nil)
(let (byte-compile-warnings)
(condition-case _ (package-initialize)
(condition-case _
(package-initialize)
('error (package-refresh-contents)
(setq doom--refreshed-p t)
(package-initialize))))
@ -213,8 +245,23 @@ FORCE-P is non-nil, do it anyway.
(error "✕ Couldn't install %s" package)))
(message "Installing core packages...done")))
(cl-pushnew doom-core-dir load-path :test #'string=)
(setq doom--init-cache-p t))
(setq doom-init-p t)))
(add-hook 'doom-internal-init-hook #'doom|refresh-cache))
(when doom-debug-mode
(message "Doom initialized")))
;; initialize Doom core
(require 'core-lib)
(require 'core-os)
(unless noninteractive
(require 'core-ui)
(require 'core-editor)
(require 'core-projects)
(require 'core-keybinds))
;; load input-deferred packages on first `pre-command-hook'
(add-transient-hook! 'pre-command-hook
(mapc #'require (cdr (assq 'input doom-deferred-packages))))
(add-transient-hook! 'doom-after-switch-buffer-hook
(when (get-buffer-window)
(mapc #'require (cdr (assq 'buffer doom-deferred-packages))))))
(defun doom-initialize-autoloads ()
"Ensures that `doom-autoload-file' exists and is loaded. Otherwise run
@ -222,14 +269,6 @@ FORCE-P is non-nil, do it anyway.
(unless (file-exists-p doom-autoload-file)
(quiet! (doom//reload-autoloads))))
(defun doom-initialize-modules ()
"Bootstraps all enabled modules by loading their config.el files."
(maphash (lambda (key plist)
(let ((doom--current-module key))
(load (expand-file-name "config" (plist-get plist :path))
'noerror (not doom-debug-mode))))
doom-modules))
(defun doom-initialize-packages (&optional force-p)
"Ensures that `doom-packages', `packages-alist' and `quelpa-cache' are
populated.
@ -242,12 +281,40 @@ Use this before any of package.el, quelpa or Doom's package management's API to
ensure all the necessary package metadata is initialized and available for
them."
(with-temp-buffer ; prevent buffer-local settings from propagating
(let ((load-prefer-newer t))
;; package.el and quelpa handle themselves if their state changes during
;; the current session, but if you change an packages.el file in a module,
;; there's no non-trivial way to detect that, so we give you a way to
;; reload only doom-packages (by passing 'internal as FORCE-P).
;; `doom-packages'
(when (or force-p (not doom-packages))
(unless (eq force-p 'internal)
;; `package-alist'
(when (or force-p (not (bound-and-true-p package-alist)))
(setq load-path doom-site-load-path)
(require 'package)
(setq package-activated-list nil
package--initialized nil)
(let (byte-compile-warnings)
(condition-case _
(package-initialize)
('error (package-refresh-contents)
(setq doom--refreshed-p t)
(package-initialize)))))
;; `quelpa-cache'
(when (or force-p (not (bound-and-true-p quelpa-cache)))
(require 'quelpa)
(setq quelpa-initialized-p nil)
(or (quelpa-setup-p)
(error "Could not initialize quelpa"))))
(setq doom-packages nil)
(cl-flet
((_load
(file &optional noerror interactive)
(condition-case-unless-debug ex
(let ((load-prefer-newer t)
(noninteractive (not interactive)))
(let ((noninteractive (not interactive)))
(load file noerror 'nomessage 'nosuffix))
('error
(lwarn 'doom-initialize-packages :warning
@ -255,13 +322,7 @@ them."
(car ex)
(file-relative-name file doom-emacs-dir)
(error-message-string ex))))))
;; package.el and quelpa handle themselves if their state changes during
;; the current session, but if you change an packages.el file in a module,
;; there's no non-trivial way to detect that, so we give you a way to
;; reload only doom-packages.
;; `doom-packages'
(when (or force-p (not doom-packages))
(setq doom-packages nil)
(let ((doom--stage 'packages))
(_load (expand-file-name "packages.el" doom-core-dir))
(cl-loop for key being the hash-keys of doom-modules
for path = (doom-module-expand-file (car key) (cdr key) "packages.el")
@ -270,23 +331,7 @@ them."
(cl-loop for dir in doom-psuedo-module-dirs
for path = (expand-file-name "packages.el" dir)
if (file-exists-p path)
do (_load path)))
(unless (eq force-p 'internal)
;; `package-alist'
(when (or force-p (not (bound-and-true-p package-alist)))
(setq load-path doom-site-load-path)
(require 'package)
(setq package-activated-list nil)
(let (byte-compile-warnings)
(package-initialize)))
;; `quelpa-cache'
(when (or force-p (not (bound-and-true-p quelpa-cache)))
(require 'quelpa)
(setq quelpa-initialized-p nil)
(or (quelpa-setup-p)
(error "Could not initialize quelpa")))))))
do (_load path))))))))
;;
@ -387,7 +432,8 @@ added, if the file exists."
"Bootstraps DOOM Emacs and its modules.
MODULES is an malformed plist of modules to load."
(let (load-forms module file-name-handler-alist)
(let (init-forms config-forms file-name-handler-alist)
(let (module)
(dolist (m modules)
(cond ((keywordp m) (setq module m))
((not module) (error "No namespace specified in `doom!' for %s" m))
@ -400,15 +446,20 @@ MODULES is an malformed plist of modules to load."
(doom-module-set module submodule :flags flags :path path)
(push `(let ((doom--current-module ',(cons module submodule)))
(load! init ,path t))
load-forms)))))))
init-forms)
(push `(let ((doom--current-module ',(cons module submodule)))
(load! config ,path t))
config-forms))))))))
`(let (file-name-handler-alist)
(setq doom-modules ',doom-modules)
(let ((doom--initializing t))
,@(nreverse load-forms))
,(unless doom--initializing
'(unless noninteractive
(doom--refresh-cache)
(doom-initialize-modules))))))
(let ((doom--stage 'init))
,@(nreverse init-forms))
(unless noninteractive
(run-hooks 'doom-internal-init-hook)
(let ((doom--stage 'config))
,@(nreverse config-forms)
(when doom-private-dir
(load ,(concat doom-private-dir "config") t t)))))))
(defmacro def-package! (name &rest plist)
"A thin wrapper around `use-package'."
@ -419,10 +470,17 @@ MODULES is an malformed plist of modules to load."
;; If byte-compiling, ignore this package if it doesn't meet the condition.
;; This avoids false-positive load errors.
(unless (and (bound-and-true-p byte-compile-current-file)
(or (and (plist-member plist :if) (not (eval (plist-get plist :if))))
(and (plist-member plist :when) (not (eval (plist-get plist :when))))
(and (plist-member plist :unless) (eval (plist-get plist :unless)))))
`(use-package ,name ,@plist)))
(or (and (plist-member plist :if) (not (eval (plist-get plist :if) t)))
(and (plist-member plist :when) (not (eval (plist-get plist :when) t)))
(and (plist-member plist :unless) (eval (plist-get plist :unless) t))))
`(progn
,(when-let* ((defer (plist-get plist :defer))
(type (or (car-safe defer) defer)))
(setq plist (plist-put plist :defer (or (cdr-safe defer) t)))
(when (and (not doom-init-p)
(assq type doom-deferred-packages))
`(push ',name (cdr (assq ',type doom-deferred-packages)))))
(use-package ,name ,@plist))))
(defmacro def-package-hook! (package when &rest body)
"Reconfigures a package's `def-package!' block.
@ -439,6 +497,7 @@ WARNING: If :pre-init or :pre-config hooks return nil, the original
`def-package!''s :init/:config block (respectively) is overwritten, so remember
to have them return non-nil (or exploit that to overwrite Doom's config)."
(declare (indent defun))
(doom--assert-stage-p 'init #'package!)
(cond ((eq when :disable)
(message "Using :disable with `def-package-hook!' is deprecated. Use :disable in `package!' instead.")
(ignore (push package doom-disabled-packages)))
@ -533,16 +592,6 @@ omitted. eg. (featurep! +flag1)"
;; Module package macros
;;
(defun doom--assert-file-p (file-name macro)
(cl-assert (string= (file-name-nondirectory load-file-name) file-name)
nil
"Found %s call in non-%s file (%s)"
macro
file-name
(if (file-in-directory-p load-file-name doom-emacs-dir)
(file-relative-name load-file-name doom-emacs-dir)
(abbreviate-file-name load-file-name))))
(defmacro package! (name &rest plist)
"Declares a package and how to install it (if applicable).
@ -568,7 +617,7 @@ Accepts the following properties:
:freeze FORM
Do not update this package if FORM is non-nil."
(declare (indent defun))
(doom--assert-file-p "packages.el" #'package!)
(doom--assert-stage-p 'packages #'package!)
(cond ((memq name doom-disabled-packages) nil)
((let ((disable (plist-get plist :disable)))
(and disable (eval disable)))
@ -599,7 +648,7 @@ Accepts the following properties:
packages at once.
Only use this macro in a module's packages.el file."
(doom--assert-file-p "packages.el" #'packages!)
(doom--assert-stage-p 'packages #'packages!)
`(progn ,@(cl-loop for desc in packages collect `(package! ,@desc))))
(defmacro disable-packages! (&rest packages)
@ -607,7 +656,7 @@ Only use this macro in a module's packages.el file."
packages at once.
Only use this macro in a module's packages.el file."
(doom--assert-file-p "packages.el" #'disable-packages!)
(doom--assert-stage-p 'packages #'disable-packages!)
`(setq doom-disabled-packages (append ',packages doom-disabled-packages)))
(defmacro depends-on! (module submodule &optional flags)
@ -617,7 +666,7 @@ Only use this macro in a module's packages.el file.
MODULE is a keyword, and SUBMODULE is a symbol. Under the hood, this simply
loads MODULE SUBMODULE's packages.el file."
(doom--assert-file-p "packages.el" #'depends-on!)
(doom--assert-stage-p 'packages #'depends-on!)
`(let ((doom-modules ,doom-modules)
(flags ,flags))
(when flags
@ -680,6 +729,7 @@ call `doom//reload-load-path' remotely (through emacsclient)."
(message "%d packages reloaded" (length package-alist))
(run-hooks 'doom-reload-hook))))
(defvar generated-autoload-load-name)
(defun doom//reload-autoloads ()
"Refreshes the autoloads.el file, specified by `doom-autoload-file'.
@ -805,12 +855,11 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
;; pertinent to files compiled later.
(let (noninteractive)
;; Core libraries aren't fully loaded in a noninteractive session, so
;; we reload it with `noninteractive' set to nil to force them to.
(load (expand-file-name "core.el" doom-core-dir) nil t t)
;; we pretend to be interactive and reinitialize
(doom-initialize)
;; In case autoloads.el hasn't been properly generated at this point.
(dolist (file (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir)))
(load file t t t)))
(doom-initialize-modules)
(unless (file-exists-p doom-autoload-file)
(mapc #'load (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir)))))
;; Assemble el files we want to compile; taking into account that
;; MODULES may be a list of MODULE/SUBMODULE strings from the command
;; line.
@ -819,6 +868,7 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
in (or modules (append (list doom-core-dir) (doom-module-load-path)))
if (equal target "core")
nconc (nreverse (doom-packages--files doom-core-dir "\\.el$"))
and collect (expand-file-name "init.el" doom-private-dir)
else if (file-directory-p target)
nconc (nreverse (doom-packages--files target "\\.el$"))
else if (cl-member target doom-psuedo-module-dirs :test #'file-in-directory-p)

View file

@ -12,9 +12,9 @@
projectile-ignored-projects '("~/" "/tmp"))
:config
(projectile-mode +1)
(add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
(add-hook 'find-file-hook #'doom|autoload-project-mode)
(projectile-mode +1)
;; a more generic project root file
(push ".project" projectile-project-root-files-bottom-up)

View file

@ -280,15 +280,19 @@ DEFAULT is non-nil, set the default mode-line for all buffers."
(add-hook 'isearch-mode-end-hook #'doom|enable-ui-keystrokes)
;; undo/redo changes to Emacs' window layout
(defvar winner-dont-bind-my-keys t) ; I'll bind keys myself
(autoload 'winner-mode "winner" nil t)
(add-hook 'doom-init-ui-hook #'winner-mode)
(def-package! winner
:defer buffer
:preface (defvar winner-dont-bind-my-keys t) ; I'll bind keys myself
:config (winner-mode +1))
;; highlight matching delimiters
(def-package! paren
:defer input
:config
(setq show-paren-delay 0.1
show-paren-highlight-openparen t
show-paren-when-point-inside-paren t)
(add-hook 'doom-init-ui-hook #'show-paren-mode)
(show-paren-mode +1))
;;; More reliable inter-window border
;; The native border "consumes" a pixel of the fringe on righter-most splits,
@ -352,10 +356,12 @@ from the default."
(prog1 (apply orig-fn args)
(run-hooks 'doom-after-switch-buffer-hook)))
(defun doom|init-custom-hooks ()
(advice-add #'select-frame :around #'doom*switch-frame-hooks)
(advice-add #'select-window :around #'doom*switch-window-hooks)
(advice-add #'switch-to-buffer :around #'doom*switch-buffer-hooks)
(advice-add #'display-buffer :around #'doom*switch-buffer-hooks)
(advice-add #'display-buffer :around #'doom*switch-buffer-hooks))
(add-hook 'doom-init-hook #'doom|init-custom-hooks)
(defun doom*load-theme-hooks (theme &rest _)
(setq doom-theme theme)

View file

@ -82,6 +82,7 @@ XDG directory conventions if ~/.config/doom exists.")
abbrev-file-name (concat doom-local-dir "abbrev.el")
auto-save-list-file-name (concat doom-cache-dir "autosave")
backup-directory-alist (list (cons "." (concat doom-cache-dir "backup/")))
custom-file (concat doom-etc-dir "custom.el")
pcache-directory (concat doom-cache-dir "pcache/")
mc/list-file (concat doom-etc-dir "mc-lists.el")
server-auth-dir (concat doom-cache-dir "server/")
@ -92,10 +93,6 @@ XDG directory conventions if ~/.config/doom exists.")
url-cache-directory (concat doom-cache-dir "url/")
url-configuration-directory (concat doom-etc-dir "url/"))
;; move custom defs out of init.el
(setq custom-file (concat doom-etc-dir "custom.el"))
(load custom-file t t t)
;; be quiet at startup; don't load or display anything unnecessary
(unless noninteractive
(advice-add #'display-startup-echo-area-message :override #'ignore)
@ -108,56 +105,17 @@ XDG directory conventions if ~/.config/doom exists.")
;; Custom init hooks; clearer than `after-init-hook', `emacs-startup-hook', and
;; `window-setup-hook'.
(defvar doom-init-hook nil
"A list of hooks run when DOOM is initialized, before `doom-post-init-hook'.
Use this for essential functionality.")
"A list of hooks run when DOOM is initialized.")
(defvar doom-post-init-hook nil
"A list of hooks run after DOOM initialization is complete, and after
`doom-init-hook'. Use this for extra, non-essential functionality.")
(defun doom-try-run-hook (fn hook)
"Runs a hook wrapped in a `condition-case-unless-debug' block; its objective
is to include more information in the error message, without sacrificing your
ability to invoke the debugger in debug mode."
(condition-case-unless-debug ex
(if noninteractive
(quiet! (funcall fn))
(funcall fn))
('error
(lwarn hook :error
"%s in '%s' -> %s"
(car ex) fn (error-message-string ex))))
nil)
(defun doom|after-init ()
"Run `doom-init-hook' and `doom-post-init-hook', start the Emacs server, and
display the loading benchmark."
(unless noninteractive
(load (concat doom-private-dir "config") t t))
(dolist (hook '(doom-init-hook doom-post-init-hook))
(run-hook-wrapped hook #'doom-try-run-hook hook))
(unless noninteractive
(when (display-graphic-p)
(require 'server)
(unless (server-running-p)
(server-start)))
(message "%s" (doom-packages--benchmark))))
(defun doom|finalize ()
"Resets garbage collection settings to reasonable defaults (if you don't do
this, you'll get stuttering and random freezes), and resets
`file-name-handler-alist'."
(setq gc-cons-threshold 16777216
gc-cons-percentage 0.1
file-name-handler-alist doom--file-name-handler-alist)
t)
(defvar doom-internal-init-hook nil
"Hooks run after Doom has loaded all init.el files, and is ready to load
modules.")
;;
;; Emacs fixes/hacks
;;
;; Automatic minor modes
(defvar doom-auto-minor-mode-alist '()
"Alist mapping filename patterns to corresponding minor mode functions, like
`auto-mode-alist'. All elements of this alist are checked, meaning you can
@ -195,36 +153,39 @@ with functions that require it (like modeline segments)."
(advice-add #'make-indirect-buffer :around #'doom*set-indirect-buffer-filename)
;;;
;; Initialize
(eval-and-compile
;;
;; Bootstrap
;;
(defvar doom--file-name-handler-alist file-name-handler-alist)
(unless (or after-init-time noninteractive)
;; A big contributor to long startup times is the garbage collector, so we
;; up its memory threshold, temporarily and reset it later in
;; `doom|finalize'.
;; A big contributor to long startup times is the garbage collector, so we up
;; its memory threshold, temporarily and reset it later in `doom|finalize'.
(setq gc-cons-threshold 402653184
gc-cons-percentage 0.6
gc-cons-percentage 1.0
;; consulted on every `require', `load' and various file reading
;; functions. You get a minor speed up by nooping this.
file-name-handler-alist nil))
(when doom-private-dir
(load (concat doom-private-dir "early-init") t t))
(defun doom|finalize ()
"Resets garbage collection settings to reasonable defaults (if you don't do
this, you'll get stuttering and random freezes) and resets
`file-name-handler-alist'."
(unless noninteractive
(run-hooks 'doom-init-hook))
(setq doom-init-p t
file-name-handler-alist doom--file-name-handler-alist
gc-cons-threshold 16777216
gc-cons-percentage 0.15))
;;
(require 'core-packages (concat doom-core-dir "core-packages"))
(doom-initialize noninteractive)
(load! core-lib)
(load! core-os) ; consistent behavior across OSes
(unless noninteractive
(load! core-ui) ; draw me like one of your French editors
(load! core-editor) ; baseline configuration for text editing
(load! core-projects) ; making Emacs project-aware
(load! core-keybinds)) ; centralized keybind system + which-key
(add-hook! '(emacs-startup-hook doom-reload-hook) #'doom|finalize)
(add-hook 'emacs-startup-hook #'doom|after-init)
(add-hook! '(emacs-startup-hook doom-reload-hook)
#'doom|finalize)
(when doom-private-dir
(load (concat doom-private-dir "init") t t)))
(load (concat doom-private-dir "init") t t))
(provide 'core)
;;; core.el ends here