syscfg/emacs/module/module-pkg.el

96 lines
3.4 KiB
EmacsLisp

;;; 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."
(let ((feature-sym (if (and (listp feature) (eq (car feature) 'quote))
(cadr feature)
feature)))
`(progn
(pkg/ensure-installed ',feature-sym)
(unless (featurep ',feature-sym)
(autoload #',(intern (format "%s-autoloaded" feature-sym))
,(or filename (symbol-name feature-sym))
nil t)
(defalias ',feature-sym #',(intern (format "%s-autoloaded" feature-sym))))
',feature-sym)))
(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.