123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- ;;; init-packages.el --- Package Configuration File -*- lexical-binding: t -*-
- ;;; Commentary:
- ;;; Code:
- ;; Elpaca installer block
- (defvar elpaca-installer-version 0.8)
- (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
- (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
- (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
- (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
- :ref nil :depth 1
- :files (:defaults "elpaca-test.el" (:exclude "extensions"))
- :build (:not elpaca--activate-package)))
- (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory))
- (build (expand-file-name "elpaca/" elpaca-builds-directory))
- (order (cdr elpaca-order))
- (default-directory repo))
- (add-to-list 'load-path (if (file-exists-p build) build repo))
- (unless (file-exists-p repo)
- (make-directory repo t)
- (when (< emacs-major-version 28) (require 'subr-x))
- (condition-case-unless-debug err
- (if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
- ((zerop (apply #'call-process `("git" nil ,buffer t "clone"
- ,@(when-let* ((depth (plist-get order :depth)))
- (list (format "--depth=%d" depth) "--no-single-branch"))
- ,(plist-get order :repo) ,repo))))
- ((zerop (call-process "git" nil buffer t "checkout"
- (or (plist-get order :ref) "--"))))
- (emacs (concat invocation-directory invocation-name))
- ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
- "--eval" "(byte-recompile-directory \".\" 0 'force)")))
- ((require 'elpaca))
- ((elpaca-generate-autoloads "elpaca" repo)))
- (progn (message "%s" (buffer-string)) (kill-buffer buffer))
- (error "%s" (with-current-buffer buffer (buffer-string))))
- ((error) (warn "%s" err) (delete-directory repo 'recursive))))
- (unless (require 'elpaca-autoloads nil t)
- (require 'elpaca)
- (elpaca-generate-autoloads "elpaca" repo)
- (load "./elpaca-autoloads")))
- (add-hook 'after-init-hook #'elpaca-process-queues)
- (elpaca `(,@elpaca-order))
- ;; End of elpaca installer block
- ;; Install use-package support
- (elpaca elpaca-use-package
- ;; Enable use-package :ensure support for Elpaca.
- (elpaca-use-package-mode)
- (setq use-package-always-ensure t
- use-package-always-defer t
- package-native-compile t
- elpaca-queue-limit 10)
- (setq use-package-verbose init-file-debug
- use-package-expand-minimally (not init-file-debug)
- use-package-compute-statistics nil
- debug-on-error init-file-debug)
- (bind-key "C-c e u" 'elpaca-fetch-all)
- (bind-key "C-c e m" 'elpaca-manager)
- (bind-key "C-c e r" 'elpaca-update-menus)
- (bind-key "C-c e t" 'elpaca-try)
- (bind-key "C-c e b" 'elpaca-rebuild)
- (bind-key "C-c e d" 'elpaca-delete))
- (elpaca diminish)
- ;; Temporary workaround for packages needing newer version of seq (https://github.com/progfolio/elpaca/issues/216#issuecomment-1868444883))
- (defun +elpaca-unload-seq (e)
- (and (featurep 'seq) (unload-feature 'seq t))
- (elpaca--continue-build e))
- (defun +elpaca-seq-build-steps ()
- (append (butlast (if (file-exists-p (expand-file-name "seq" elpaca-builds-directory))
- elpaca--pre-built-steps elpaca-build-steps))
- (list '+elpaca-unload-seq 'elpaca--activate-package)))
- (elpaca `(seq :build ,(+elpaca-seq-build-steps)))
- (defun +elpaca-unload-transient (e)
- (and (featurep 'transient) (unload-feature 'transient t))
- (elpaca--continue-build e))
- (defun +elpaca-transient-build-steps ()
- (append (butlast (if (file-exists-p (expand-file-name "transient" elpaca-builds-directory))
- elpaca--pre-built-steps elpaca-build-steps))
- (list '+elpaca-unload-transient 'elpaca--activate-package)))
- (elpaca `(transient :build ,(+elpaca-transient-build-steps)))
- ;; Block until current queue processed.
- (elpaca-wait)
- (add-to-list 'elpaca-ignored-dependencies 'project)
- (add-to-list 'elpaca-ignored-dependencies 'xref)
- ;; https://github.com/progfolio/elpaca/wiki/Logging#auto-hiding-the-elpaca-log-buffer
- (defvar +elpaca-hide-log-commands '(eval-buffer eval-region eval-defun eval-last-sexp org-ctrl-c-ctrl-c eros-eval-defun eros-eval-last-sexp elisp-eval-region-or-buffer)
- "List of commands for which a successfully processed log is auto hidden.")
- (defun +elpaca-hide-successful-log ()
- "Hide Elpaca log buffer if queues processed successfully."
- (message "this: %S last: %S" this-command last-command)
- (if-let ((incomplete (cl-find 'incomplete elpaca--queues :key #'elpaca-q<-status))
- ((elpaca-q<-elpacas incomplete)))
- nil
- (when-let ((log (bound-and-true-p elpaca-log-buffer))
- (window (get-buffer-window log t)) ;; log buffer visible
- ((or (member last-command +elpaca-hide-log-commands)
- (member this-command +elpaca-hide-log-commands))))
- (with-selected-window window (quit-window 'kill window)))))
- (add-hook 'elpaca-post-queue-hook #'+elpaca-hide-successful-log)
- ;; https://github.com/progfolio/elpaca/wiki/Logging#how-to-change-a-commands-log-query
- (with-eval-after-load 'elpaca-log
- (setf (alist-get +elpaca-hide-log-commands
- elpaca-log-command-queries nil nil #'equal)
- "#unique | !finished"))
- ;; https://github.com/progfolio/elpaca/wiki/Logging#customizing-the-position-of-the-elpaca-log-buffer
- (add-to-list 'display-buffer-alist '("\\*elpaca-log\\*" (display-buffer-reuse-window display-buffer-at-bottom)))
- ;; https://github.com/progfolio/elpaca/wiki/Reloading-a-package%E2%80%99s-features-after-updating-a-package
- (defun +elpaca-reload-package (package &optional allp)
- "Reload PACKAGE's features.
- If ALLP is non-nil (interactively, with prefix), load all of its
- features; otherwise only load ones that were already loaded.
- This is useful to reload a package after upgrading it. Since a
- package may provide multiple features, to reload it properly
- would require either restarting Emacs or manually unloading and
- reloading each loaded feature. This automates that process.
- Note that this unloads all of the package's symbols before
- reloading. Any data stored in those symbols will be lost, so if
- the package would normally save that data, e.g. when a mode is
- deactivated or when Emacs exits, the user should do so before
- using this command."
- (interactive
- (list (let ((elpaca-overriding-prompt "Reload package: "))
- (elpaca--read-queued))
- current-prefix-arg))
- ;; This finds features in the currently installed version of PACKAGE, so if
- ;; it provided other features in an older version, those are not unloaded.
- (when (yes-or-no-p (format "Unload all of %s's symbols and reload its features? " package))
- (let* ((package-name (symbol-name package))
- (package-dir (file-name-directory
- (locate-file package-name load-path (get-load-suffixes))))
- (package-files (directory-files package-dir 'full (rx ".el" eos)))
- (package-features
- (cl-loop for file in package-files
- when (with-temp-buffer
- (insert-file-contents file)
- (when (re-search-forward (rx bol "(provide" (1+ space)) nil t)
- (goto-char (match-beginning 0))
- (cadadr (read (current-buffer)))))
- collect it)))
- (unless allp
- (setf package-features (seq-intersection package-features features)))
- (dolist (feature package-features)
- (ignore-errors
- ;; Ignore error in case it's not loaded.
- (unload-feature feature 'force)))
- (dolist (feature package-features)
- (require feature))
- (when package-features
- (message "Reloaded: %s" (mapconcat #'symbol-name package-features " "))))))
- (define-advice elpaca-merge (:after (id &optional _fetch _interactive) elpaca-merge-reload)
- "Automically reload packages after they have been updated."
- (cl-letf (((symbol-function 'yes-or-no-p) (cl-constantly t)))
- (when (not (or (memq id elpaca-ignored-dependencies)
- ;; TODO why aren't xref and project already in the list?
- (memq id '(xref project perspective))))
- (+elpaca-reload-package id))))
- ;; https://github.com/radian-software/radian/blob/e3aad124c8e0cc870ed09da8b3a4905d01e49769/emacs/radian.el#L352
- (defmacro use-feature (name &rest args)
- "Like `use-package', but without elpaca integration.
- `NAME' and `ARGS' are as with `use-package'"
- (declare (indent defun))
- `(use-package ,name
- :ensure nil
- ,@args))
- ;; useful for corfu and vertico extensions
- (defmacro use-extension (pkg name &rest args)
- "Like `use-package', but for a package extension.
- `PKG' is the name of the package, `NAME' and `ARGS' are as with `use-package'"
- (declare (indent defun))
- `(use-package ,name
- :ensure nil
- :after ,pkg
- :demand t
- ,@args))
- (defun add-to-list* (list-var &rest elts)
- "Add `ELTS' to `LIST-VAR'."
- (dolist (elt elts)
- (add-to-list list-var elt)))
- (defun append-to-list* (list-var &rest elts)
- "Append `ELTS' to `LIST-VAR'."
- (dolist (elt elts)
- (add-to-list list-var elt t)))
- (provide 'init-packages)
- ;;; init-packages.el ends here
|