;;; feature-pkg.el --- Brief description -*- lexical-binding: t; -*- ;;; Commentary: ;;; ;;; This feature provides a simple and predictable package management ;;; framework building upon built-in Emacs package management ;;; features. Frameworks like use-package and leaf are nice, but ;;; become difficult to manage and debug over time . feature-pkg.el ;;; is the foundation for adding and removing features in this Emacs ;;; configuration. ;;; ;;; Note that feature-pkg does not explicitly need to be required in ;;; the main Emacs config, as it will be loaded as a dependency by ;;; each feature. ;;; Code: (require 'package) (with-eval-after-load 'package (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") '("nongnu" . "https://elpa.nongnu.org/nongnu/"))) (package-initialize) ;; install straight.el (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) (defun pkg/ensure-installed (package) "Ensure that PACKAGE is installed." (unless (package-installed-p package) (package-refresh-contents) (package-install package))) (defmacro pkg/require (feature &optional filename noerror) "Ensure FEATURE is installed, then require it. FILENAME and NOERROR are passed to `require'." `(progn (pkg/ensure-installed ,feature) (require ,feature ,filename ,noerror))) (defmacro pkg/require-defer (feature &optional filename noerror) "Defer loading of FEATURE until it's actually needed. Ensure FEATURE is installed first. FILENAME, if non-nil, is the file to load to provide FEATURE. If NOERROR is non-nil, don't signal an error if the file is not found." `(progn (pkg/ensure-installed ,feature) (unless (featurep ',feature) (autoload #',(intern (format "%s-autoloaded" feature)) ,(or filename (symbol-name feature)) nil t) (defalias ',feature #',(intern (format "%s-autoloaded" feature)))) ',feature)) (defun pkg/require-defer-load (feature) "Check if a deferred FEATURE is already loaded." (unless (featurep feature) (unload-feature feature t) (require feature) (fmakunbound (intern (format "%s-autoloaded" feature)))) feature) (defmacro pkg/require-defer-timer (feature seconds) "Ensure FEATURE is installed, then defer its loading by SECONDS idle time." `(progn (pkg/ensure-installed ,feature) (run-with-idle-timer ,seconds nil #'require ',feature))) (defun pkg/packages-loaded-p (&rest packages) "Return t if all PACKAGES are loaded." (cl-every #'featurep packages)) (defmacro pkg/with-eval-after-load (packages &rest body) "Run BODY after all PACKAGES are loaded." `(if (apply #'pkg/packages-loaded-p ',packages) (progn ,@body) (eval-after-load (car (last ',packages)) '(pkg/run-after-packages-load ',packages ,@body)))) (provide 'module-pkg) ;;; module-pkg.el ends here.