2022-07-30 21:49:00 +02:00
|
|
|
;;; lisp/doom-start.el --- bootstrapper for interactive sessions -*- lexical-binding: t; -*-
|
2022-06-18 15:04:12 +02:00
|
|
|
;;; Commentary:
|
|
|
|
;;; Code:
|
|
|
|
|
2022-07-30 21:49:00 +02:00
|
|
|
(require 'doom-modules)
|
2022-06-18 15:04:12 +02:00
|
|
|
|
|
|
|
|
2022-09-06 19:58:33 +02:00
|
|
|
;;
|
|
|
|
;;; doom-first-*-hook
|
|
|
|
|
|
|
|
(defvar doom-first-input-hook nil
|
|
|
|
"Transient hooks run before the first user input.")
|
|
|
|
(put 'doom-first-input-hook 'permanent-local t)
|
|
|
|
|
|
|
|
(defvar doom-first-file-hook nil
|
|
|
|
"Transient hooks run before the first interactively opened file.")
|
|
|
|
(put 'doom-first-file-hook 'permanent-local t)
|
|
|
|
|
|
|
|
(defvar doom-first-buffer-hook nil
|
|
|
|
"Transient hooks run before the first interactively opened buffer.")
|
|
|
|
(put 'doom-first-buffer-hook 'permanent-local t)
|
|
|
|
|
|
|
|
|
2022-06-18 15:04:12 +02:00
|
|
|
;;
|
|
|
|
;;; Reasonable defaults for interactive sessions
|
|
|
|
|
|
|
|
;; GUIs are inconsistent across systems, will rarely match our active Emacs
|
|
|
|
;; theme, and impose their shortcut key paradigms suddenly. Let's just avoid
|
|
|
|
;; them altogether and have Emacs handle the prompting.
|
|
|
|
(setq use-dialog-box nil)
|
|
|
|
(when (bound-and-true-p tooltip-mode)
|
|
|
|
(tooltip-mode -1))
|
|
|
|
(when IS-LINUX
|
|
|
|
(setq x-gtk-use-system-tooltips nil))
|
|
|
|
|
|
|
|
;; Favor vertical splits over horizontal ones, since monitors are trending
|
|
|
|
;; toward wide rather than tall.
|
|
|
|
(setq split-width-threshold 160
|
|
|
|
split-height-threshold nil)
|
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;;; MODE-local-vars-hook
|
|
|
|
|
|
|
|
;; File+dir local variables are initialized after the major mode and its hooks
|
|
|
|
;; have run. If you want hook functions to be aware of these customizations, add
|
|
|
|
;; them to MODE-local-vars-hook instead.
|
|
|
|
(defvar doom-inhibit-local-var-hooks nil)
|
|
|
|
|
|
|
|
(defun doom-run-local-var-hooks-h ()
|
|
|
|
"Run MODE-local-vars-hook after local variables are initialized."
|
|
|
|
(unless (or doom-inhibit-local-var-hooks delay-mode-hooks)
|
|
|
|
(setq-local doom-inhibit-local-var-hooks t)
|
|
|
|
(doom-run-hooks (intern (format "%s-local-vars-hook" major-mode)))))
|
|
|
|
|
|
|
|
;; If the user has disabled `enable-local-variables', then
|
|
|
|
;; `hack-local-variables-hook' is never triggered, so we trigger it at the end
|
|
|
|
;; of `after-change-major-mode-hook':
|
|
|
|
(defun doom-run-local-var-hooks-maybe-h ()
|
|
|
|
"Run `doom-run-local-var-hooks-h' if `enable-local-variables' is disabled."
|
|
|
|
(unless enable-local-variables
|
|
|
|
(doom-run-local-var-hooks-h)))
|
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;;; Incremental lazy-loading
|
|
|
|
|
|
|
|
(defvar doom-incremental-packages '(t)
|
|
|
|
"A list of packages to load incrementally after startup. Any large packages
|
|
|
|
here may cause noticeable pauses, so it's recommended you break them up into
|
|
|
|
sub-packages. For example, `org' is comprised of many packages, and can be
|
|
|
|
broken up into:
|
|
|
|
|
|
|
|
(doom-load-packages-incrementally
|
|
|
|
'(calendar find-func format-spec org-macs org-compat
|
|
|
|
org-faces org-entities org-list org-pcomplete org-src
|
|
|
|
org-footnote org-macro ob org org-clock org-agenda
|
|
|
|
org-capture))
|
|
|
|
|
|
|
|
This is already done by the lang/org module, however.
|
|
|
|
|
|
|
|
If you want to disable incremental loading altogether, either remove
|
|
|
|
`doom-load-packages-incrementally-h' from `emacs-startup-hook' or set
|
|
|
|
`doom-incremental-first-idle-timer' to nil. Incremental loading does not occur
|
|
|
|
in daemon sessions (they are loaded immediately at startup).")
|
|
|
|
|
2022-09-06 19:22:43 +02:00
|
|
|
(defvar doom-incremental-first-idle-timer (if (featurep 'native-compile) 3.0 2.0)
|
2022-06-18 15:04:12 +02:00
|
|
|
"How long (in idle seconds) until incremental loading starts.
|
|
|
|
|
|
|
|
Set this to nil to disable incremental loading.")
|
|
|
|
|
|
|
|
(defvar doom-incremental-idle-timer 0.75
|
|
|
|
"How long (in idle seconds) in between incrementally loading packages.")
|
|
|
|
|
|
|
|
(defvar doom-incremental-load-immediately (daemonp)
|
|
|
|
"If non-nil, load all incrementally deferred packages immediately at startup.")
|
|
|
|
|
|
|
|
(defun doom-load-packages-incrementally (packages &optional now)
|
|
|
|
"Registers PACKAGES to be loaded incrementally.
|
|
|
|
|
|
|
|
If NOW is non-nil, load PACKAGES incrementally, in `doom-incremental-idle-timer'
|
|
|
|
intervals."
|
|
|
|
(if (not now)
|
|
|
|
(appendq! doom-incremental-packages packages)
|
2022-09-06 19:22:43 +02:00
|
|
|
(if (and packages (bound-and-true-p comp-files-queue))
|
|
|
|
(run-with-idle-timer doom-incremental-idle-timer
|
|
|
|
nil #'doom-load-packages-incrementally
|
|
|
|
packages t)
|
|
|
|
(while packages
|
|
|
|
(let* ((gc-cons-threshold most-positive-fixnum)
|
|
|
|
(req (pop packages)))
|
|
|
|
(unless (featurep req)
|
|
|
|
(doom-log "Incrementally loading %s" req)
|
|
|
|
(condition-case-unless-debug e
|
|
|
|
(or (while-no-input
|
|
|
|
;; If `default-directory' is a directory that doesn't exist
|
|
|
|
;; or is unreadable, Emacs throws up file-missing errors, so
|
|
|
|
;; we set it to a directory we know exists and is readable.
|
|
|
|
(let ((default-directory doom-emacs-dir)
|
|
|
|
(inhibit-message t)
|
|
|
|
file-name-handler-alist)
|
|
|
|
(require req nil t))
|
|
|
|
t)
|
|
|
|
(push req packages))
|
|
|
|
(error
|
|
|
|
(message "Failed to load %S package incrementally, because: %s"
|
|
|
|
req e)))
|
|
|
|
(if (not packages)
|
|
|
|
(doom-log "Finished incremental loading")
|
|
|
|
(run-with-idle-timer doom-incremental-idle-timer
|
|
|
|
nil #'doom-load-packages-incrementally
|
|
|
|
packages t)
|
|
|
|
(setq packages nil))))))))
|
2022-06-18 15:04:12 +02:00
|
|
|
|
|
|
|
(defun doom-load-packages-incrementally-h ()
|
|
|
|
"Begin incrementally loading packages in `doom-incremental-packages'.
|
|
|
|
|
|
|
|
If this is a daemon session, load them all immediately instead."
|
|
|
|
(if doom-incremental-load-immediately
|
|
|
|
(mapc #'require (cdr doom-incremental-packages))
|
|
|
|
(when (numberp doom-incremental-first-idle-timer)
|
|
|
|
(run-with-idle-timer doom-incremental-first-idle-timer
|
|
|
|
nil #'doom-load-packages-incrementally
|
|
|
|
(cdr doom-incremental-packages) t))))
|
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;;; Let 'er rip
|
|
|
|
|
|
|
|
(defvar doom-init-time nil
|
|
|
|
"The time it took, in seconds, for Doom Emacs to initialize.")
|
|
|
|
|
|
|
|
(defun doom-display-benchmark-h (&optional return-p)
|
|
|
|
"Display a benchmark including number of packages and modules loaded.
|
|
|
|
|
|
|
|
If RETURN-P, return the message as a string instead of displaying it."
|
|
|
|
(funcall (if return-p #'format #'message)
|
|
|
|
"Doom loaded %d packages across %d modules in %.03fs"
|
|
|
|
(- (length load-path) (length (get 'load-path 'initial-value)))
|
|
|
|
(hash-table-count doom-modules)
|
|
|
|
(or doom-init-time
|
|
|
|
(setq doom-init-time
|
|
|
|
(float-time (time-subtract (current-time) before-init-time))))))
|
|
|
|
|
|
|
|
;; Add support for additional file extensions.
|
2022-09-06 20:00:31 +02:00
|
|
|
(dolist (entry '(("/\\.doom\\(?:rc\\|project\\|module\\|profile\\)\\'" . emacs-lisp-mode)
|
2022-08-07 18:54:48 +02:00
|
|
|
("/LICENSE\\'" . text-mode)
|
2022-06-18 15:04:12 +02:00
|
|
|
("\\.log\\'" . text-mode)
|
|
|
|
("rc\\'" . conf-mode)
|
|
|
|
("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode)))
|
|
|
|
(push entry auto-mode-alist))
|
|
|
|
|
|
|
|
;; Doom caches a lot of information in `doom-autoloads-file'. Module and package
|
|
|
|
;; autoloads, autodefs like `set-company-backend!', and variables like
|
|
|
|
;; `doom-modules', `doom-disabled-packages', `load-path', `auto-mode-alist', and
|
|
|
|
;; `Info-directory-list'. etc. Compiling them into one place is a big reduction
|
|
|
|
;; in startup time.
|
|
|
|
(condition-case-unless-debug e
|
|
|
|
;; Avoid `file-name-sans-extension' for premature optimization reasons.
|
|
|
|
;; `string-remove-suffix' is cheaper because it performs no file sanity
|
|
|
|
;; checks; just plain ol' string manipulation.
|
|
|
|
(load (string-remove-suffix ".el" doom-autoloads-file) nil 'nomessage)
|
|
|
|
(file-missing
|
|
|
|
;; If the autoloads file fails to load then the user forgot to sync, or
|
|
|
|
;; aborted a doom command midway!
|
|
|
|
(if (locate-file doom-autoloads-file load-path)
|
|
|
|
;; Something inside the autoloads file is triggering this error;
|
|
|
|
;; forward it to the caller!
|
|
|
|
(signal 'doom-autoload-error e)
|
|
|
|
(signal 'doom-error
|
|
|
|
(list "Doom is in an incomplete state"
|
|
|
|
"run 'doom sync' on the command line to repair it")))))
|
|
|
|
|
|
|
|
(when (and (or (display-graphic-p)
|
|
|
|
(daemonp))
|
|
|
|
doom-env-file)
|
|
|
|
(setq-default process-environment (get 'process-environment 'initial-value))
|
|
|
|
(doom-load-envvars-file doom-env-file 'noerror))
|
|
|
|
|
|
|
|
;; Bootstrap the interactive session
|
|
|
|
(add-hook 'after-change-major-mode-hook #'doom-run-local-var-hooks-h 100)
|
|
|
|
(add-hook 'hack-local-variables-hook #'doom-run-local-var-hooks-h)
|
|
|
|
(add-hook 'emacs-startup-hook #'doom-load-packages-incrementally-h)
|
|
|
|
(add-hook 'window-setup-hook #'doom-display-benchmark-h 105)
|
|
|
|
(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))
|
|
|
|
(doom-run-hook-on 'doom-first-input-hook '(pre-command-hook))
|
|
|
|
|
2022-09-06 20:01:50 +02:00
|
|
|
;; The GC introduces annoying pauses and stuttering into our Emacs experience,
|
|
|
|
;; so we use `gcmh' to stave off the GC while we're using Emacs, and provoke it
|
|
|
|
;; when it's idle. However, if the idle delay is too long, we run the risk of
|
|
|
|
;; runaway memory usage in busy sessions. If it's too low, then we may as well
|
|
|
|
;; not be using gcmh at all.
|
|
|
|
(setq gcmh-idle-delay 'auto ; default is 15s
|
|
|
|
gcmh-auto-idle-delay-factor 10
|
|
|
|
gcmh-high-cons-threshold (* 16 1024 1024)) ; 16mb
|
2022-06-18 15:04:12 +02:00
|
|
|
(add-hook 'doom-first-buffer-hook #'gcmh-mode)
|
|
|
|
|
|
|
|
;; There's a chance the user will later use package.el or straight in this
|
|
|
|
;; interactive session. If they do, make sure they're properly initialized
|
|
|
|
;; when they do.
|
2022-07-30 21:49:00 +02:00
|
|
|
(autoload 'doom-initialize-packages "doom-packages")
|
|
|
|
(eval-after-load 'package '(require 'doom-packages))
|
2022-06-18 15:04:12 +02:00
|
|
|
(eval-after-load 'straight '(doom-initialize-packages))
|
|
|
|
|
|
|
|
;; Load all things.
|
|
|
|
(doom-initialize-modules)
|
|
|
|
|
2022-07-30 21:49:00 +02:00
|
|
|
(provide 'doom-start)
|
|
|
|
;;; doom-start.el ends here
|