;;; 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