Files
sydnix/users/crumb/programs/emacs/modules/syd-use-package.el
Madeleine Sydney 3ecff5e898 feat: Add :defer-incrementally
Adds org-mode module for the sake of testing it.
2025-01-17 16:28:45 -07:00

106 lines
4.5 KiB
EmacsLisp

;;; syd-use-package.el -*- lexical-binding: t; -*-
(defvar syd-incremental-idle-timer 0.75
"How long (in idle seconds) in between incrementally loading packages.")
(defvar syd-incremental-first-idle-timer (if (daemonp) 0 2.0)
"How long (in idle seconds) until incremental loading starts.
Set this to nil to disable incremental loading at startup.
Set this to 0 to load all incrementally deferred packages immediately at
`after-init-hook'.")
(defvar syd-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 might be
broken up into:
(syd-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
`syd-load-packages-incrementally-h' from `after-init-hook' or set
`syd-incremental-first-idle-timer' to nil. Incremental loading does not occur
in daemon sessions (they are loaded immediately at startup).")
(defun syd-load-packages-incrementally (packages &optional now)
"Registers PACKAGES to be loaded incrementally.
If NOW is non-nil, PACKAGES will be marked for incremental loading next time
Emacs is idle for `syd-incremental-first-idle-timer' seconds (falls back to
`syd-incremental-idle-timer'), then in `syd-incremental-idle-timer' intervals
afterwards."
(let* ((gc-cons-threshold most-positive-fixnum)
(first-idle-timer (or syd-incremental-first-idle-timer
syd-incremental-idle-timer)))
(if (not now)
(cl-callf append syd-incremental-packages packages)
(while packages
(let ((req (pop packages))
idle-time)
(unless (featurep req)
(condition-case-unless-debug e
(and
(or (null (setq idle-time (current-idle-time)))
(< (float-time idle-time) first-idle-timer)
(not
(while-no-input
;; If `default-directory' doesn't exist or is
;; unreadable, Emacs throws file errors.
(let ((default-directory user-emacs-directory)
(inhibit-message t)
(file-name-handler-alist
(list (rassq 'jka-compr-handler file-name-handler-alist))))
(message "loading %s" req)
(require req nil t)
t))))
(push req packages))
(error
(message "Error: failed to incrementally load %S because: %s" req e)
(setq packages nil)))
(unless (null packages)
(run-at-time (if idle-time
syd-incremental-idle-timer
first-idle-timer)
nil #'syd-load-packages-incrementally
packages t)
(setq packages nil))))))))
(defun syd-load-packages-incrementally-h ()
"Begin incrementally loading packages in `syd-incremental-packages'.
If this is a daemon session, load them all immediately instead."
(when (numberp syd-incremental-first-idle-timer)
(if (zerop syd-incremental-first-idle-timer)
(mapc #'require (cdr syd-incremental-packages))
(run-with-idle-timer syd-incremental-first-idle-timer
nil #'syd-load-packages-incrementally
(cdr syd-incremental-packages) t))))
(unless noninteractive
(add-hook 'after-init-hook #'syd-load-packages-incrementally-h 100))
(with-eval-after-load 'use-package-core
(push :defer-incrementally use-package-deferring-keywords)
(setq use-package-keywords (use-package-list-insert
:defer-incrementally use-package-keywords :after))
(defalias 'use-package-normalize/:defer-incrementally
#'use-package-normalize-symlist)
(defun use-package-handler/:defer-incrementally
(name _keyword targets rest state)
(use-package-concat
`((syd-load-packages-incrementally
',(if (equal targets '(t))
(list name)
(append targets (list name)))))
(use-package-process-keywords name rest state))))
(provide 'syd-use-package)
;;; syd-use-package.el ends here