From 9b49c3278ad938c2da555dfc0e2159ac5c9b7b37 Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Sat, 11 Oct 2025 17:14:24 -0600 Subject: [PATCH 01/10] chg: Move Emacs Lisp files into lisp/ --- early-init.el | 135 ------------------ ensure.el => lisp/ensure.el | 0 .../gears}/checkers/spellchecking.el | 0 .../gears}/completion/marginalia.el | 0 .../completion/nerd-icons-completion.el | 0 {gears => lisp/gears}/completion/orderless.el | 0 {gears => lisp/gears}/completion/vertico.el | 0 {gears => lisp/gears}/config/default.el | 0 {gears => lisp/gears}/editing/emacs-lisp.el | 0 {gears => lisp/gears}/editing/go.el | 0 {gears => lisp/gears}/editing/hyprland.el | 0 {gears => lisp/gears}/editing/org.el | 0 {gears => lisp/gears}/email/mu4e.el | 0 {gears => lisp/gears}/tools/magit.el | 0 {gears => lisp/gears}/tools/whitespaces.el | 0 {gears => lisp/gears}/ui/theme.el | 0 {gears => lisp/gears}/ui/treesit.el | 0 {pouch => lisp/pouch}/backpack-email-utils.el | 0 {pouch => lisp/pouch}/backpack-pouch.el | 0 {pouch => lisp/pouch}/backpack-user.el | 0 20 files changed, 135 deletions(-) rename ensure.el => lisp/ensure.el (100%) rename {gears => lisp/gears}/checkers/spellchecking.el (100%) rename {gears => lisp/gears}/completion/marginalia.el (100%) rename {gears => lisp/gears}/completion/nerd-icons-completion.el (100%) rename {gears => lisp/gears}/completion/orderless.el (100%) rename {gears => lisp/gears}/completion/vertico.el (100%) rename {gears => lisp/gears}/config/default.el (100%) rename {gears => lisp/gears}/editing/emacs-lisp.el (100%) rename {gears => lisp/gears}/editing/go.el (100%) rename {gears => lisp/gears}/editing/hyprland.el (100%) rename {gears => lisp/gears}/editing/org.el (100%) rename {gears => lisp/gears}/email/mu4e.el (100%) rename {gears => lisp/gears}/tools/magit.el (100%) rename {gears => lisp/gears}/tools/whitespaces.el (100%) rename {gears => lisp/gears}/ui/theme.el (100%) rename {gears => lisp/gears}/ui/treesit.el (100%) rename {pouch => lisp/pouch}/backpack-email-utils.el (100%) rename {pouch => lisp/pouch}/backpack-pouch.el (100%) rename {pouch => lisp/pouch}/backpack-user.el (100%) diff --git a/early-init.el b/early-init.el index c7555cb..ac40870 100644 --- a/early-init.el +++ b/early-init.el @@ -1,137 +1,2 @@ ;; -*- no-byte-compile: t; -*- -(when (version< emacs-version "29.1") - (error "Backpack is only compatible with Emacs version 29.1 and up")) - -(setq package-enable-at-startup nil) -(setq load-prefer-newer t) -(setq native-comp-deferred-compilation nil) - -;; directories -(defvar backpack--base-packages-dir (expand-file-name "base-packages" user-emacs-directory)) -(defvar backpack--leaf (expand-file-name "leaf.el" backpack--base-packages-dir)) -(defvar backpack--leaf-keywords (expand-file-name "leaf-keywords.el" backpack--base-packages-dir)) -(defvar backpack--cache-emacs (expand-file-name ".cache/emacs" user-emacs-directory)) - -(let ((colors-file (expand-file-name "default-colors.el" backpack--cache-emacs))) - (when (file-exists-p colors-file) - (load colors-file))) - -(add-to-list 'load-path backpack--leaf) -(add-to-list 'load-path backpack--leaf-keywords) -(add-to-list 'load-path (expand-file-name "pouch" user-emacs-directory)) - -;; shamelessly copied from Emacs Bedrock -(setq backpack--initial-gc-threshold gc-cons-threshold) -(setq gc-cons-threshold 10000000) - -(setq byte-compile-warnings '(not obsolete)) -(setq warning-suppress-log-types '((comp) (bytecomp))) -(setq native-comp-async-report-warnings-errors 'silent) - -(setq inhibit-startup-echo-area-message (user-login-name)) - -;; move auto-save-list to another location -(setq auto-save-list-directory (expand-file-name "auto-save-list/" backpack--cache-emacs)) - -(unless (file-directory-p auto-save-list-directory) - (make-directory auto-save-list-directory t)) - -(setq auto-save-list-file-prefix - (expand-file-name ".saves-" auto-save-list-directory)) - -;; move eln-cache to another location -(setq backpack--eln-cache-dir (expand-file-name "eln-cache/" backpack--cache-emacs)) - -(unless (file-directory-p backpack--eln-cache-dir) - (make-directory backpack--eln-cache-dir t)) - -(setq native-comp-eln-load-path (list backpack--eln-cache-dir)) - -;; configuration variables for elpaca -(defvar elpaca-installer-version 0.11) -(defvar elpaca-directory (expand-file-name ".cache/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 :inherit ignore - :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) - (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) -(add-hook 'after-init-hook #'elpaca-process-queues -100) -(elpaca `(,@elpaca-order)) - -(require 'leaf) -(require 'leaf-keywords) -(leaf-keywords-init) - -;;; add additional keywords to leaf block -;; :doctor defines binaries to check on the user's system -;; :fonts check what if the fonts needed by a package are installed -(plist-put leaf-keywords :doctor '`(,@leaf--body)) -(plist-put leaf-keywords :fonts '`(,@leaf--body)) - -;; alias :ensure to :elpaca -(setq leaf-alias-keyword-alist '((:ensure . :elpaca))) - -(defun save-default-bg-fg-colors () - "Save the current theme's foreground and background colors into a file." - (let ((bg (face-attribute 'default :background)) - (fg (face-attribute 'default :foreground))) - (with-temp-file (expand-file-name "default-colors.el" backpack--cache-emacs) - (insert (format "(setq default-frame-alist '((background-color . \"%s\") (foreground-color . \"%s\")))" - bg fg))))) - -(leaf benchmark-init - :ensure t - :config - (add-hook 'after-init-hook #'benchmark-init/deactivate 100) - (benchmark-init/activate)) - -(leaf no-littering - :ensure t - :pre-setq - `(no-littering-etc-directory . ,(expand-file-name "etc" backpack--cache-emacs)) - `(no-littering-var-directory . ,(expand-file-name "var" backpack--cache-emacs)) - :config - (with-eval-after-load "recentf" - (add-to-list 'recentf-exclude - (recentf-expand-file-name no-littering-var-directory)) - (add-to-list 'recentf-exclude - (recentf-expand-file-name no-littering-etc-directory))) - - (no-littering-theme-backups) - - (defvar backpack-tree-sitter-installation-directory - (no-littering-expand-var-file-name "tree-sitter") - "Directory for installing tree-sitter grammars") - - (unless (file-exists-p backpack-tree-sitter-installation-directory) - (make-directory backpack-tree-sitter-installation-directory t))) diff --git a/ensure.el b/lisp/ensure.el similarity index 100% rename from ensure.el rename to lisp/ensure.el diff --git a/gears/checkers/spellchecking.el b/lisp/gears/checkers/spellchecking.el similarity index 100% rename from gears/checkers/spellchecking.el rename to lisp/gears/checkers/spellchecking.el diff --git a/gears/completion/marginalia.el b/lisp/gears/completion/marginalia.el similarity index 100% rename from gears/completion/marginalia.el rename to lisp/gears/completion/marginalia.el diff --git a/gears/completion/nerd-icons-completion.el b/lisp/gears/completion/nerd-icons-completion.el similarity index 100% rename from gears/completion/nerd-icons-completion.el rename to lisp/gears/completion/nerd-icons-completion.el diff --git a/gears/completion/orderless.el b/lisp/gears/completion/orderless.el similarity index 100% rename from gears/completion/orderless.el rename to lisp/gears/completion/orderless.el diff --git a/gears/completion/vertico.el b/lisp/gears/completion/vertico.el similarity index 100% rename from gears/completion/vertico.el rename to lisp/gears/completion/vertico.el diff --git a/gears/config/default.el b/lisp/gears/config/default.el similarity index 100% rename from gears/config/default.el rename to lisp/gears/config/default.el diff --git a/gears/editing/emacs-lisp.el b/lisp/gears/editing/emacs-lisp.el similarity index 100% rename from gears/editing/emacs-lisp.el rename to lisp/gears/editing/emacs-lisp.el diff --git a/gears/editing/go.el b/lisp/gears/editing/go.el similarity index 100% rename from gears/editing/go.el rename to lisp/gears/editing/go.el diff --git a/gears/editing/hyprland.el b/lisp/gears/editing/hyprland.el similarity index 100% rename from gears/editing/hyprland.el rename to lisp/gears/editing/hyprland.el diff --git a/gears/editing/org.el b/lisp/gears/editing/org.el similarity index 100% rename from gears/editing/org.el rename to lisp/gears/editing/org.el diff --git a/gears/email/mu4e.el b/lisp/gears/email/mu4e.el similarity index 100% rename from gears/email/mu4e.el rename to lisp/gears/email/mu4e.el diff --git a/gears/tools/magit.el b/lisp/gears/tools/magit.el similarity index 100% rename from gears/tools/magit.el rename to lisp/gears/tools/magit.el diff --git a/gears/tools/whitespaces.el b/lisp/gears/tools/whitespaces.el similarity index 100% rename from gears/tools/whitespaces.el rename to lisp/gears/tools/whitespaces.el diff --git a/gears/ui/theme.el b/lisp/gears/ui/theme.el similarity index 100% rename from gears/ui/theme.el rename to lisp/gears/ui/theme.el diff --git a/gears/ui/treesit.el b/lisp/gears/ui/treesit.el similarity index 100% rename from gears/ui/treesit.el rename to lisp/gears/ui/treesit.el diff --git a/pouch/backpack-email-utils.el b/lisp/pouch/backpack-email-utils.el similarity index 100% rename from pouch/backpack-email-utils.el rename to lisp/pouch/backpack-email-utils.el diff --git a/pouch/backpack-pouch.el b/lisp/pouch/backpack-pouch.el similarity index 100% rename from pouch/backpack-pouch.el rename to lisp/pouch/backpack-pouch.el diff --git a/pouch/backpack-user.el b/lisp/pouch/backpack-user.el similarity index 100% rename from pouch/backpack-user.el rename to lisp/pouch/backpack-user.el From 17cc8564635e2edcdd97c53eea207291efbeeb3c Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Sat, 11 Oct 2025 17:38:29 -0600 Subject: [PATCH 02/10] chg: Move init.el into lisp/ --- init.el => lisp/init.el | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename init.el => lisp/init.el (100%) diff --git a/init.el b/lisp/init.el similarity index 100% rename from init.el rename to lisp/init.el From 8ef85033013981c75bc7e6a85d1b99db937c42a0 Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Sat, 11 Oct 2025 22:22:49 -0600 Subject: [PATCH 03/10] chg: Shamelessly copy the startup optimizations of Doom --- early-init.el | 20 ++ lisp/ensure.el => ensure.el | 2 +- lisp/{pouch => }/backpack-email-utils.el | 0 lisp/{pouch => }/backpack-pouch.el | 0 lisp/backpack.el | 402 +++++++++++++++++++++++ lisp/pouch/backpack-user.el | 27 -- 6 files changed, 423 insertions(+), 28 deletions(-) rename lisp/ensure.el => ensure.el (81%) rename lisp/{pouch => }/backpack-email-utils.el (100%) rename lisp/{pouch => }/backpack-pouch.el (100%) create mode 100644 lisp/backpack.el delete mode 100644 lisp/pouch/backpack-user.el diff --git a/early-init.el b/early-init.el index ac40870..573b118 100644 --- a/early-init.el +++ b/early-init.el @@ -1,2 +1,22 @@ ;; -*- no-byte-compile: t; -*- +(let (file-name-handler-alist) + (if noninteractive + (setq gc-cons-threshold (* 128 1024 1024) + gc-cons-percentage 1.0) + (setq gc-cons-threshold most-positive-fixnum)) + + (setq load-prefer-newer noninteractive) + + (if (let ((load-suffixes '(".elc" ".el")) + (backpack (expand-file-name "lisp/backpack" user-emacs-directory))) + (if (file-exists-p (concat backpack ".el")) + ;; load backpack + (load backpack nil nil nil t) + (warn "no file lisp/backpack.el found")) + (setq user-init-file (expand-file-name "early-init" user-emacs-directory)) + (setq load-prefer-newer t) + (setq gc-cons-threshold (* 16 1024 1024)) + nil) + ;; (doom-initialize (not noninteractive)) + (load user-init-file 'noerror nil nil 'must-suffix))) diff --git a/lisp/ensure.el b/ensure.el similarity index 81% rename from lisp/ensure.el rename to ensure.el index 73ccb01..693619b 100644 --- a/lisp/ensure.el +++ b/ensure.el @@ -1,6 +1,6 @@ (progn (elpaca-wait) - (save-default-bg-fg-colors) + ;; (save-default-bg-fg-colors) (unless (gearp! :ui -treesit) (let ((treesit-auto-install t)) (treesit-auto-install-all))) diff --git a/lisp/pouch/backpack-email-utils.el b/lisp/backpack-email-utils.el similarity index 100% rename from lisp/pouch/backpack-email-utils.el rename to lisp/backpack-email-utils.el diff --git a/lisp/pouch/backpack-pouch.el b/lisp/backpack-pouch.el similarity index 100% rename from lisp/pouch/backpack-pouch.el rename to lisp/backpack-pouch.el diff --git a/lisp/backpack.el b/lisp/backpack.el new file mode 100644 index 0000000..a01ff35 --- /dev/null +++ b/lisp/backpack.el @@ -0,0 +1,402 @@ +(eval-and-compile + (when (version< emacs-version "29.1") + (error "Backpack is only compatible with Emacs version 29.1 and up"))) + +(let ((old-version (eval-when-compile emacs-version))) + (unless (string= emacs-version old-version) + (user-error (format "Backpack was compiled with Emacs %s, but was loaded with %s" emacs-version old-version)))) + +;; Copy the consistency imposed by Doom Emacs +(when (bound-and-true-p module-file-suffix) + (push 'dynamic-modules features)) +(when (fboundp #'json-parse-string) + (push 'jansson features)) +(when (string-match-p "HARFBUZZ" system-configuration-features) + (push 'harfbuzz features)) + +;; don't bother with native compilation if it's not functional +(when (and (featurep 'native-compile) + (not (native-comp-available-p))) + (delq 'native-compile features)) + +;; don't worry the user about obsolete macros +(put 'if-let 'byte-obsolete-info nil) +(put 'when-let 'byte-obsolete-info nil) + +;; backpack standard library +(add-to-list 'load-path (file-name-directory load-file-name)) + +(defconst backpack-system + (pcase system-type + ('darwin '(macos bsd)) + ((or 'cygwin 'windows-nt 'ms-dos) '(windows)) + ((or 'gnu 'gnu/linux) '(gnu)) + ((or 'gnu/kfreebsd 'berkeley-unix) '(gnu bsd)) + ('android '(android))) + "The operating system Emacs is running on.") + +(defconst backpack--system-windows-p (eq 'windows (car backpack-system))) +(defconst backpack--system-macos-p (eq 'macos (car backpack-system))) +(defconst backpack--system-gnu-p (eq 'gnu (car backpack-system))) + +(when (and backpack--system-gnu-p + (getenv-internal "WSLENV")) + (add-to-list backpack-system 'wsl 'append)) + +(push :system features) +(put :system 'subfeatures backpack-system) + +(when backpack--system-windows-p + (when-let* ((realhome + (and (null (getenv-internal "HOME")) + (getenv "USERPROFILE")))) + (setenv "HOME" realhome) + (setq abbreviated-home-dir nil))) + +;;; Globals + +(defgroup backpack nil + "A self-documenting GNU Emacs starter kit inspired after Bedrock and Doom." + :link '(url-link "https://github.com/shackra/backpack")) + +(defvar backpack-emacs-dir user-emacs-directory + "The path of the currently loaded Emacs configuration.") + +(defconst backpack-core-dir (file-name-directory load-file-name) + "The directory of Backpack files.") + +(defvar backpack-user-dir + (let ((in-xdg-config (expand-file-name "backpack/" (getenv-internal "XDG_CONFIG_HOME"))) + (in-user-home "~/.backpack.d/")) + (if (file-exists-p in-user-home) + in-user-home + in-xdg-config)) + "Location of the user's private configuration. + +Either ~/.config/backpack or ~/.backpack.d/.") + +(defvar backpack-cache-dir (expand-file-name ".cache/" backpack-emacs-dir) + "Location for local storage") + +(defvar backpack-data-dir + (expand-file-name "etc" backpack-cache-dir) + "Location use by Backpack to store important files. + +Delete this directory entails user intervention to make things work +again.") + +(defvar backpack-nonessential-dir + (expand-file-name "nonessentials" backpack-cache-dir) + "Location where Backpack stores nonessential files. + +If anything is missing here, Backpack Emacs will work as normal.") + +(defvar backpack-state-dir + (expand-file-name "state" backpack-cache-dir) + "Location for files that carry state for some functionalities or packages.") + +;; +;;; Startup optimizations + +(unless (daemonp) + ;; PERF: `file-name-handler-alist' is consulted on each call to `require', + ;; `load', or various file/io functions (like `expand-file-name' or + ;; `file-remote-p'). You get a noteable boost to startup time by unsetting + ;; or simplifying its value. + (let ((old-value (default-toplevel-value 'file-name-handler-alist))) + (set-default-toplevel-value + 'file-name-handler-alist + ;; HACK: The elisp libraries bundled with Emacs are either compressed or + ;; not, never both. So if calc-loaddefs.el.gz exists, calc-loaddefs.el + ;; won't, and vice versa. This heuristic is used to guess the state of + ;; all other built-in (or site); if they're compressed, we must leave the + ;; gzip file handler in `file-name-handler-alist' so Emacs knows how to + ;; load them. Otherwise, we can omit it (at least during startup) for a + ;; boost in package load time. + (if (eval-when-compile + (locate-file-internal "calc-loaddefs.el" load-path)) + nil + (list (rassq 'jka-compr-handler old-value)))) + ;; Remember it so it can be reset where needed. + (put 'file-name-handler-alist 'initial-value old-value) + ;; COMPAT: Eventually, Emacs will process any files passed to it via the + ;; command line, and will do so *really* early in the startup process. + ;; These might contain special file paths like TRAMP paths, so restore + ;; `file-name-handler-alist' just for this portion of startup. + (define-advice command-line-1 (:around (fn args-left) respect-file-handlers) + (let ((file-name-handler-alist (if args-left old-value file-name-handler-alist))) + (funcall fn args-left))) + ;; COMPAT: ...but restore `file-name-handler-alist' later, because it is + ;; needed for handling encrypted or compressed files, among other things. + (add-hook 'emacs-startup-hook :depth 101 + (defun backpack--reset-file-handler-alist-h () + (set-default-toplevel-value + 'file-name-handler-alist + ;; Merge instead of overwrite because there may have been changes to + ;; `file-name-handler-alist' since startup we want to preserve. + (delete-dups (append file-name-handler-alist old-value)))))) + + (unless noninteractive + ;; PERF: Resizing the Emacs frame (to accommodate fonts that are smaller or + ;; larger than the default system font) can impact startup time + ;; dramatically. The larger the delta, the greater the delay. Even trivial + ;; deltas can yield up to a ~1000ms loss, depending also on + ;; `window-system' (PGTK builds seem least affected and NS/MAC the most). + (setq frame-inhibit-implied-resize t) + + ;; PERF: A fair bit of startup time goes into initializing the splash and + ;; scratch buffers in the typical Emacs session (b/c they activate a + ;; non-trivial major mode, generate the splash buffer, and trigger + ;; premature frame redraws by writing to *Messages*). These hacks prevent + ;; most of this work from happening for some decent savings in startup + ;; time. Our dashboard and `doom/open-scratch-buffer' provide a faster + ;; (and more useful) alternative anyway. + (setq inhibit-startup-screen t + inhibit-startup-echo-area-message user-login-name + initial-major-mode 'fundamental-mode + initial-scratch-message nil) + ;; PERF,UX: Prevent "For information about GNU Emacs..." line in *Messages*. + (advice-add #'display-startup-echo-area-message :override #'ignore) + ;; PERF: Suppress the vanilla startup screen completely. We've disabled it + ;; with `inhibit-startup-screen', but it would still initialize anyway. + ;; This involves file IO and/or bitmap work (depending on the frame type) + ;; that we can no-op for a free 50-100ms saving in startup time. + (advice-add #'display-startup-screen :override #'ignore) + + (unless initial-window-system + ;; PERF: `tty-run-terminal-initialization' can take 2-3s when starting up + ;; TTY Emacs (non-daemon sessions), depending on your TERM, TERMINFO, + ;; and TERMCAP, but this work isn't very useful on modern systems (the + ;; type I expect Doom's users to be using). The function seems less + ;; expensive if run later in the startup process, so I defer it. + ;; REVIEW: This may no longer be needed in 29+. Needs testing! + (define-advice tty-run-terminal-initialization (:override (&rest _) defer) + (advice-remove #'tty-run-terminal-initialization #'tty-run-terminal-initialization@defer) + (add-hook 'window-setup-hook + (apply-partially #'tty-run-terminal-initialization + (selected-frame) nil t)))) + + ;; These optimizations are brittle, difficult to debug, and obscure other + ;; issues, so bow out when debug mode is on. + (unless init-file-debug + ;; PERF: The mode-line procs a couple dozen times during startup, before + ;; the user even sees the first mode-line. This is normally fast, but we + ;; can't predict what the user (or packages) will put into the + ;; mode-line. Also, mode-line packages have a bad habit of throwing + ;; performance to the wind, so best we just disable the mode-line until + ;; we can see one. + (put 'mode-line-format 'initial-value (default-toplevel-value 'mode-line-format)) + (setq-default mode-line-format nil) + (dolist (buf (buffer-list)) + (with-current-buffer buf (setq mode-line-format nil))) + ;; PERF,UX: Premature redisplays/redraws can substantially affect startup + ;; times and/or flash a white/unstyled Emacs frame during startup, so I + ;; try real hard to suppress them until we're sure the session is ready. + (setq-default inhibit-redisplay t + inhibit-message t) + ;; COMPAT: If the above vars aren't reset, Emacs could appear frozen or + ;; garbled after startup (or in case of an startup error). + (defun backpack--reset-inhibited-vars-h () + (setq-default inhibit-redisplay nil + inhibit-message nil) + (remove-hook 'post-command-hook #'backpack--reset-inhibited-vars-h)) + (add-hook 'post-command-hook #'backpack--reset-inhibited-vars-h -100)) + + ;; PERF: Doom disables the UI elements by default, so that there's less for + ;; the frame to initialize. However, `tool-bar-setup' is still called and + ;; it does some non-trivial work to set up the toolbar before we can + ;; disable it. To side-step this work, I disable the function and call it + ;; later (see `startup--load-user-init-file@undo-hacks'). + (advice-add #'tool-bar-setup :override #'ignore) + + ;; PERF,UX: site-lisp files are often obnoxiously noisy (emitting output + ;; that isn't useful to end-users, like load messages, deprecation + ;; notices, and linter warnings). Displaying these in the minibuffer + ;; causes unnecessary redraws at startup which can impact startup time + ;; drastically and cause flashes of white. It also pollutes the logs. I + ;; suppress it here and load it myself, later, in a more controlled way + ;; (see `doom-initialize'). + (put 'site-run-file 'initial-value site-run-file) + (setq site-run-file nil) + + (define-advice startup--load-user-init-file (:around (fn &rest args) undo-hacks 95) + "Undo Doom's startup optimizations to prep for the user's session." + (unwind-protect (apply fn args) + ;; Now it's safe to be verbose. + (setq-default inhibit-message nil) + ;; COMPAT: Once startup is sufficiently complete, undo our earlier + ;; optimizations to reduce the scope of potential edge cases. + (advice-remove #'tool-bar-setup #'ignore) + + (add-hook 'tool-bar-mode-hook (defun --tool-bar-setup () + (tool-bar-setup) + (remove-hook 'tool-bar-mode-hook --tool-bar-setup))) + (unless (default-toplevel-value 'mode-line-format) + (setq-default mode-line-format (get 'mode-line-format 'initial-value))))) + + ;; PERF: Unset a non-trivial list of command line options that aren't + ;; relevant to this session, but `command-line-1' still processes. + (unless backpack--system-macos-p + (setq command-line-ns-option-alist nil)) + (unless (memq initial-window-system '(x pgtk)) + (setq command-line-x-option-alist nil)))) + +;; +;;; Reasonable, global defaults + +;;; CLI settings +(when noninteractive + ;; Don't generate superfluous files when writing temp buffers. + (setq make-backup-files nil) + ;; Stop user config from interfering with elisp shell scripts. + (setq enable-dir-local-variables nil) + ;; Reduce ambiguity, embrace specificity, enjoy predictability. + (setq case-fold-search nil) + ;; Don't clog the user's trash with our CLI refuse. + (setq delete-by-moving-to-trash nil)) + +;;; Don't litter `doom-emacs-dir'/$HOME +;; HACK: I change `user-emacs-directory' because many packages (even built-in +;; ones) abuse it to build paths for storage/cache files (instead of correctly +;; using `locate-user-emacs-file'). This change ensures that said data files +;; are never saved to the root of your emacs directory *and* saves us the +;; trouble of setting a million directory/file variables. +(setq user-emacs-directory backpack-cache-dir) + +;; ...However, this may surprise packages (and users) that read +;; `user-emacs-directory' expecting to find the location of your Emacs config, +;; such as server.el! +(setq server-auth-dir (file-name-concat backpack-emacs-dir "server/")) + +;; Packages with file/dir settings that don't use `user-emacs-directory' or +;; `locate-user-emacs-file' to initialize will need to set explicitly, to stop +;; them from littering in ~/.emacs.d/. +(setq desktop-dirname (file-name-concat backpack-state-dir "desktop") + pcache-directory (file-name-concat backpack-cache-dir "pcache/")) + +;; Allow the user to store custom.el-saved settings and themes in their Doom +;; config (e.g. ~/.doom.d/). +(setq custom-file (file-name-concat backpack-user-dir "custom.el")) + +(define-advice en/disable-command (:around (fn &rest args) write-to-data-dir) + "Save safe-local-variables to `custom-file' instead of `user-init-file'. + +Otherwise, `en/disable-command' (in novice.el.gz) is hardcoded to write them to +`user-init-file')." + (let ((user-init-file custom-file)) + (apply fn args))) + +;;; Native compilation support (see http://akrl.sdf.org/gccemacs.html) +(when (boundp 'native-comp-eln-load-path) + ;; Don't store eln files in ~/.emacs.d/eln-cache (where they can easily be + ;; deleted by 'doom upgrade'). + ;; REVIEW: Advise `startup-redirect-eln-cache' when 28 support is dropped. + (add-to-list 'native-comp-eln-load-path (expand-file-name "eln/" backpack-cache-dir)) + + ;; UX: Suppress compiler warnings and don't inundate users with their popups. + ;; They are rarely more than warnings, so are safe to ignore. + (setq native-comp-async-report-warnings-errors init-file-debug + native-comp-warning-on-missing-source init-file-debug) + + ;; HACK: `native-comp-deferred-compilation-deny-list' is replaced in later + ;; versions of Emacs 29, and with no deprecation warning. I alias them to + ;; ensure backwards compatibility for packages downstream that may have not + ;; caught up yet. I avoid marking it obsolete because obsolete warnings are + ;; unimportant to end-users. It's the package devs that should be informed. + (unless (boundp 'native-comp-deferred-compilation-deny-list) + (defvaralias 'native-comp-deferred-compilation-deny-list 'native-comp-jit-compilation-deny-list)) + + ;; UX: By default, native-comp uses 100% of half your cores. If you're + ;; expecting this this should be no issue, but the sudden (and silent) spike + ;; of CPU and memory utilization can alarm folks, overheat laptops, or + ;; overwhelm less performant systems. + (define-advice comp-effective-async-max-jobs (:before (&rest _) set-default-cpus) + "Default to 1/4 of cores in interactive sessions and all of them otherwise." + (and (null comp-num-cpus) + (zerop native-comp-async-jobs-number) + (setq comp-num-cpus + (max 1 (/ (num-processors) (if noninteractive 1 4)))))) + + (define-advice comp-run-async-workers (:around (fn &rest args) dont-litter-tmpdir) + "Normally, native-comp writes a ton to /tmp. This advice forces it to write +to `doom-profile-cache-dir' instead, so it can be safely cleaned up as part of +'doom sync' or 'doom gc'." + (let ((temporary-file-directory (expand-file-name "comp/" backpack-cache-dir))) + (make-directory temporary-file-directory t) + (apply fn args))) + + (with-eval-after-load 'comp + ;; HACK: On Emacs 30.0.92, `native-comp-jit-compilation-deny-list' was moved + ;; to comp-run. See emacsmirror/emacs@e6a955d24268. Doom forces straight + ;; to consult this variable when building packages. + (require 'comp-run nil t) + ;; HACK: Disable native-compilation for some troublesome packages + (mapc (apply-partially #'add-to-list 'native-comp-deferred-compilation-deny-list) + (list "/seq-tests\\.el\\'" + "/emacs-jupyter.*\\.el\\'" + "/evil-collection-vterm\\.el\\'" + "/vterm\\.el\\'" + "/with-editor\\.el\\'")))) + + +;;; Reduce unnecessary/unactionable warnings/logs +;; Disable warnings from the legacy advice API. They aren't actionable or +;; useful, and often come from third party packages. +(setq ad-redefinition-action 'accept) + +;; Ignore warnings about "existing variables being aliased". Otherwise the user +;; gets very intrusive popup warnings about our (intentional) uses of +;; defvaralias, which are done because ensuring aliases are created before +;; packages are loaded is an unneeded and unhelpful maintenance burden. Emacs +;; still aliases them fine regardless. +(setq warning-suppress-types '((defvaralias) (lexical-binding))) + +;; As some point in 31+, Emacs began spamming the user with warnings about +;; missing `lexical-binding' cookies in elisp files that you are unlikely to +;; have any direct control over (e.g. package files, data lisp files, and elisp +;; shell scripts). This shuts it up. +(setq warning-inhibit-types '((files missing-lexbind-cookie))) + +;; Reduce debug output unless we've asked for it. +(setq debug-on-error init-file-debug + jka-compr-verbose init-file-debug) + +;;; Stricter security defaults +;; Emacs is essentially one huge security vulnerability, what with all the +;; dependencies it pulls in from all corners of the globe. Let's try to be a +;; *little* more discerning. +(setq gnutls-verify-error noninteractive + gnutls-algorithm-priority + (when (boundp 'libgnutls-version) + (concat "SECURE128:+SECURE192:-VERS-ALL" + (if (and (not backpack--system-windows-p) + (>= libgnutls-version 30605)) + ":+VERS-TLS1.3") + ":+VERS-TLS1.2")) + ;; `gnutls-min-prime-bits' is set based on recommendations from + ;; https://www.keylength.com/en/4/ + gnutls-min-prime-bits 3072 + tls-checktrust gnutls-verify-error + ;; Emacs is built with gnutls.el by default, so `tls-program' won't + ;; typically be used, but in the odd case that it does, we ensure a more + ;; secure default for it (falling back to `openssl' if absolutely + ;; necessary). See https://redd.it/8sykl1 for details. + tls-program '("openssl s_client -connect %h:%p -CAfile %t -nbio -no_ssl3 -no_tls1 -no_tls1_1 -ign_eof" + "gnutls-cli -p %p --dh-bits=3072 --ocsp --x509cafile=%t \ +--strict-tofu --priority='SECURE192:+SECURE128:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3' %h" + ;; compatibility fallbacks + "gnutls-cli -p %p %h")) + + +;;; Package managers +;; Since Emacs 27, package initialization occurs before `user-init-file' is +;; loaded, but after `early-init-file'. Doom handles package initialization, so +;; we must prevent Emacs from doing it again. +(setq package-enable-at-startup nil) + +;; +;;; Initializers + +;; TODO(shackra): implement this + +(provide 'backpack) diff --git a/lisp/pouch/backpack-user.el b/lisp/pouch/backpack-user.el deleted file mode 100644 index f4fcba6..0000000 --- a/lisp/pouch/backpack-user.el +++ /dev/null @@ -1,27 +0,0 @@ -(require 'xdg) -(require 'backpack-pouch) - -(defvar backpack-user-directory "" - "Location of the user configuration.") - -(defvar backpack-user-directory-exists - (or - (when (file-exists-p (expand-file-name "backpack/init.el" (xdg-config-home))) - (setq backpack-user-directory (expand-file-name "backpack/init.el" (xdg-config-home)))) - (when (file-exists-p "~/.backpack.d/init.el") - (setq backpack-user-directory "~/.backpack.d/"))) - "Tell if there is a user configuration.") - -(defun backpack-load-user-configuration () - "Load the user configuration. - -This should set `backpack--gear'" - (unless backpack-user-directory-exists - (error "no user configuration exists, please create one")) - (load (expand-file-name "init.el" backpack-user-directory) nil backpack-log-loading) - (unless backpack--gear - (warn "no configuration defined, was gear! even used?")) - (setq custom-file (expand-file-name "customs.el" backpack-user-directory)) - (add-hook 'elpaca-after-init-hook (lambda () (load custom-file 'noerror)))) - -(provide 'backpack-user) From 1010ca8291dbaaa62906d93150bc57196a45cd53 Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Sun, 12 Oct 2025 02:18:25 -0600 Subject: [PATCH 04/10] chg: Make elpaca download all enabled packages --- bin/backpack | 2 +- early-init.el | 22 ++++--- ensure.el | 52 ++++++++++++++-- lisp/backpack.el | 125 ++++++++++++++++++++++++++++++++++++--- lisp/gears/email/mu4e.el | 2 +- lisp/gears/ui/treesit.el | 11 ++-- lisp/init.el | 17 +----- 7 files changed, 181 insertions(+), 50 deletions(-) diff --git a/bin/backpack b/bin/backpack index fdf034a..221f758 100755 --- a/bin/backpack +++ b/bin/backpack @@ -22,7 +22,7 @@ fi if [ "$ACTION" = "ensure" ]; then echo "✅ Running Emacs in batch mode..." - emacs -nw --eval '(load (expand-file-name "ensure.el" user-emacs-directory))' + emacs -nw --eval '(load (expand-file-name "ensure.el" backpack-emacs-dir))' exit $? else echo "❌ Error: unknown action '$ACTION'" >&2 diff --git a/early-init.el b/early-init.el index 573b118..8652dfc 100644 --- a/early-init.el +++ b/early-init.el @@ -8,15 +8,13 @@ (setq load-prefer-newer noninteractive) - (if (let ((load-suffixes '(".elc" ".el")) - (backpack (expand-file-name "lisp/backpack" user-emacs-directory))) - (if (file-exists-p (concat backpack ".el")) - ;; load backpack - (load backpack nil nil nil t) - (warn "no file lisp/backpack.el found")) - (setq user-init-file (expand-file-name "early-init" user-emacs-directory)) - (setq load-prefer-newer t) - (setq gc-cons-threshold (* 16 1024 1024)) - nil) - ;; (doom-initialize (not noninteractive)) - (load user-init-file 'noerror nil nil 'must-suffix))) + (let ((load-suffixes '(".elc" ".el")) + (backpack (expand-file-name "lisp/backpack" user-emacs-directory))) + (when (file-exists-p (concat backpack ".el")) + ;; load backpack + (load backpack nil nil nil t)) + (setq user-init-file (expand-file-name "early-init" user-emacs-directory)) + (setq load-prefer-newer t) + (setq gc-cons-threshold (* 16 1024 1024)))) + +(backpack-start (not noninteractive)) diff --git a/ensure.el b/ensure.el index 693619b..cb78a19 100644 --- a/ensure.el +++ b/ensure.el @@ -1,7 +1,47 @@ +(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" + :ref nil :depth 1 :inherit ignore + :files (:defaults "elpaca-test.el" (:exclude "extensions")) + :build (:not elpaca--activate-package))) + (progn - (elpaca-wait) - ;; (save-default-bg-fg-colors) - (unless (gearp! :ui -treesit) - (let ((treesit-auto-install t)) - (treesit-auto-install-all))) - (kill-emacs 0)) + (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) + (build (expand-file-name "elpaca/" elpaca-builds-directory)) + (order (cdr elpaca-order)) + (default-directory repo)) + (unless (file-exists-p repo) + (make-directory repo t) + (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) + (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) + + (backpack-load-gear-files) + + (add-hook 'elpaca-post-queue-hook + (lambda () + ;; (save-default-bg-fg-colors) + (unless (gearp! :ui -treesit) + (when (fboundp 'treesit-auto-install-all) + (message "compiling tree-sitter grammars") + (let ((treesit-auto-install t)) + (treesit-auto-install-all)))) + (kill-emacs 0))) + + (elpaca-wait)) diff --git a/lisp/backpack.el b/lisp/backpack.el index a01ff35..20bdf36 100644 --- a/lisp/backpack.el +++ b/lisp/backpack.el @@ -1,3 +1,5 @@ +;; -*- lexical-binding: t; -*- + (eval-and-compile (when (version< emacs-version "29.1") (error "Backpack is only compatible with Emacs version 29.1 and up"))) @@ -24,7 +26,24 @@ (put 'when-let 'byte-obsolete-info nil) ;; backpack standard library +(add-to-list 'load-path (expand-file-name "base-packages/leaf.el" user-emacs-directory)) +(add-to-list 'load-path (expand-file-name "base-packages/leaf-keywords.el" user-emacs-directory)) (add-to-list 'load-path (file-name-directory load-file-name)) +(require 'leaf) +(require 'leaf-keywords) +(require 'backpack-pouch) +(require 'backpack-email-utils) + +(leaf-keywords-init) + +;;; add additional keywords to leaf block +;; :doctor defines binaries to check on the user's system +;; :fonts check what if the fonts needed by a package are installed +(plist-put leaf-keywords :doctor '`(,@leaf--body)) +(plist-put leaf-keywords :fonts '`(,@leaf--body)) + +;; alias :ensure to :elpaca +(setq leaf-alias-keyword-alist '((:ensure . :elpaca))) (defconst backpack-system (pcase system-type @@ -95,8 +114,13 @@ If anything is missing here, Backpack Emacs will work as normal.") (expand-file-name "state" backpack-cache-dir) "Location for files that carry state for some functionalities or packages.") +(defvar backpack-tree-sitter-installation-dir + (expand-file-name "tree-sitter" backpack-nonessential-dir) + "Location for treesit to install compiled grammar.") + ;; ;;; Startup optimizations +;;; copied straight from Doom Emacs 👀 (unless (daemonp) ;; PERF: `file-name-handler-alist' is consulted on each call to `require', @@ -129,12 +153,12 @@ If anything is missing here, Backpack Emacs will work as normal.") ;; COMPAT: ...but restore `file-name-handler-alist' later, because it is ;; needed for handling encrypted or compressed files, among other things. (add-hook 'emacs-startup-hook :depth 101 - (defun backpack--reset-file-handler-alist-h () - (set-default-toplevel-value - 'file-name-handler-alist - ;; Merge instead of overwrite because there may have been changes to - ;; `file-name-handler-alist' since startup we want to preserve. - (delete-dups (append file-name-handler-alist old-value)))))) + (defun backpack--reset-file-handler-alist-h () + (set-default-toplevel-value + 'file-name-handler-alist + ;; Merge instead of overwrite because there may have been changes to + ;; `file-name-handler-alist' since startup we want to preserve. + (delete-dups (append file-name-handler-alist old-value)))))) (unless noninteractive ;; PERF: Resizing the Emacs frame (to accommodate fonts that are smaller or @@ -174,7 +198,7 @@ If anything is missing here, Backpack Emacs will work as normal.") (advice-remove #'tty-run-terminal-initialization #'tty-run-terminal-initialization@defer) (add-hook 'window-setup-hook (apply-partially #'tty-run-terminal-initialization - (selected-frame) nil t)))) + (selected-frame) nil t)))) ;; These optimizations are brittle, difficult to debug, and obscure other ;; issues, so bow out when debug mode is on. @@ -230,7 +254,7 @@ If anything is missing here, Backpack Emacs will work as normal.") (add-hook 'tool-bar-mode-hook (defun --tool-bar-setup () (tool-bar-setup) - (remove-hook 'tool-bar-mode-hook --tool-bar-setup))) + (remove-hook 'tool-bar-mode-hook '--tool-bar-setup))) (unless (default-toplevel-value 'mode-line-format) (setq-default mode-line-format (get 'mode-line-format 'initial-value))))) @@ -397,6 +421,91 @@ to `doom-profile-cache-dir' instead, so it can be safely cleaned up as part of ;; ;;; Initializers +(defvar elpaca-installer-version 0.11) +(defvar elpaca-directory (expand-file-name "elpaca/" backpack-nonessential-dir)) +(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) +(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) + +(let ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) + (build (expand-file-name "elpaca/" elpaca-builds-directory))) + + (add-to-list 'load-path (if (file-exists-p build) build repo)) + + (unless (require 'elpaca-autoloads nil t) + (when (file-exists-p (expand-file-name "elpaca-autoloads.el" repo)) + (load (expand-file-name "elpaca-autoloads.el" repo))))) + +(defun backpack-start (&optional interactive?) + "Start the Backpack session." + (when (daemonp) + (message "Starting in daemon mode...") + (add-hook 'kill-emacs-hook :depth 100 + (lambda () + (message "Killing Emacs. ¡Adiós!")))) + (if interactive? + (progn + ;; TODO(shackra): incremental loading of packages + + ;; last hook to run in Emacs' startup process. + (advice-add #'command-line-1 :after #'backpack-finalize) + + ;; load user's private configuration + (let ((init-file (expand-file-name "init.el" backpack-user-dir))) + (load init-file t)) + + (backpack-load-gear-files)) + (progn ;; CLI stuff I still don't have any use for, yet + (with-file-modes 448 + (mapc (apply-partially #'make-directory 'parents) + (list backpack-cache-dir + backpack-nonessential-dir + backpack-state-dir + backpack-data-dir + backpack-tree-sitter-installation-dir))))) + + ;; load site files + (let ((site-loader + (lambda () + (unless site-run-file + (when-let* ((site-file (get 'site-run-file 'initial-value))) + (let ((inhibit-startup-screen inhibit-startup-screen)) + (setq site-run-file site-file) + (load site-run-file t))))))) + + (if interactive? + (define-advice startup--load-user-init-file (:before (&rest _) load-site-files 100) + (funcall site-loader)) + (funcall site-loader))) + t) + +(defun backpack-finalize (&rest _) + "After the startup process finalizes." + (setq backpack-init-time (float-time (time-subtract (current-time) before-init-time))) + + ;; TODO: run hooks? + + (when (eq (default-value 'gc-cons-threshold) most-positive-fixnum) + (setq-default gc-cons-threshold (* 16 1024 1024))) + t) + +(defun backpack-load-gear-files () + "Load all gears available." + (load (expand-file-name "gears/config/default" backpack-core-dir)) + (load (expand-file-name "gears/ui/treesit" backpack-core-dir)) + (load (expand-file-name "gears/ui/theme" backpack-core-dir)) + (load (expand-file-name "gears/completion/vertico" backpack-core-dir)) + (load (expand-file-name "gears/completion/orderless" backpack-core-dir)) + (load (expand-file-name "gears/completion/marginalia" backpack-core-dir)) + (load (expand-file-name "gears/completion/nerd-icons-completion" backpack-core-dir)) + (load (expand-file-name "gears/tools/magit" backpack-core-dir)) + (load (expand-file-name "gears/tools/whitespaces" backpack-core-dir)) + (load (expand-file-name "gears/checkers/spellchecking" backpack-core-dir)) + (load (expand-file-name "gears/email/mu4e" backpack-core-dir)) + (load (expand-file-name "gears/editing/emacs-lisp" backpack-core-dir)) + (load (expand-file-name "gears/editing/go" backpack-core-dir)) + (load (expand-file-name "gears/editing/org" backpack-core-dir)) + (load (expand-file-name "gears/editing/hyprland" backpack-core-dir))) + ;; TODO(shackra): implement this (provide 'backpack) diff --git a/lisp/gears/email/mu4e.el b/lisp/gears/email/mu4e.el index f023b76..fdfec0f 100644 --- a/lisp/gears/email/mu4e.el +++ b/lisp/gears/email/mu4e.el @@ -1,4 +1,4 @@ -(require 'backpack-pouch) +(require 'xdg) (leaf mu4e-query :when (gearp! :email mu4e) diff --git a/lisp/gears/ui/treesit.el b/lisp/gears/ui/treesit.el index 4ddf516..71012fa 100644 --- a/lisp/gears/ui/treesit.el +++ b/lisp/gears/ui/treesit.el @@ -5,14 +5,13 @@ :unless (gearp! :ui -treesit) :ensure (treesit-auto :ref "016bd286a1ba4628f833a626f8b9d497882ecdf3") :global-minor-mode global-treesit-auto-mode - :init - (defun backpack--treesit-install-language-grammar-around (orig-fun lang &optional out-dir) - "Ensure that all grammars are compiled and put on `backpack-tree-sitter-installation-directory`." - (apply orig-fun lang (list (or out-dir backpack-tree-sitter-installation-directory)))) :advice - (:around treesit-install-language-grammar backpack--treesit-install-language-grammar-around) + (:around treesit-install-language-grammar + (lambda (orig-fun lang &optional out-dir) + "Ensure that all grammars are compiled and put on `backpack-tree-sitter-installation-dir'." + (apply orig-fun lang (list (or out-dir backpack-tree-sitter-installation-dir))))) :custom (treesit-auto-install . 'prompt) (treesit-auto-langs . '()) ;; start fresh :config - (add-to-list 'treesit-extra-load-path backpack-tree-sitter-installation-directory)) + (add-to-list 'treesit-extra-load-path backpack-tree-sitter-installation-dir)) diff --git a/lisp/init.el b/lisp/init.el index 6ba8cda..6731914 100644 --- a/lisp/init.el +++ b/lisp/init.el @@ -1,26 +1,11 @@ ;; -*- no-byte-compile: t; -*- (require 'backpack-pouch) -(require 'backpack-user) (require 'backpack-email-utils) (backpack-load-user-configuration) -(load (expand-file-name "gears/config/default.el" user-emacs-directory)) -(load (expand-file-name "gears/ui/treesit.el" user-emacs-directory)) -(load (expand-file-name "gears/ui/theme.el" user-emacs-directory)) -(load (expand-file-name "gears/completion/vertico.el" user-emacs-directory)) -(load (expand-file-name "gears/completion/orderless.el" user-emacs-directory)) -(load (expand-file-name "gears/completion/marginalia.el" user-emacs-directory)) -(load (expand-file-name "gears/completion/nerd-icons-completion.el" user-emacs-directory)) -(load (expand-file-name "gears/tools/magit.el" user-emacs-directory)) -(load (expand-file-name "gears/tools/whitespaces.el" user-emacs-directory)) -(load (expand-file-name "gears/checkers/spellchecking.el" user-emacs-directory)) -(load (expand-file-name "gears/email/mu4e.el" user-emacs-directory)) -(load (expand-file-name "gears/editing/emacs-lisp.el" user-emacs-directory)) -(load (expand-file-name "gears/editing/go.el" user-emacs-directory)) -(load (expand-file-name "gears/editing/org.el" user-emacs-directory)) -(load (expand-file-name "gears/editing/hyprland.el" user-emacs-directory)) + ;; shamelessly copied from Emacs Bedrock (leave this at the end of the file, always) (setq gc-cons-threshold (or backpack--initial-gc-threshold 800000)) From 04f26bec27b2568be5d1fe5d1aee5771b68b0b24 Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Sun, 12 Oct 2025 02:41:45 -0600 Subject: [PATCH 05/10] fix: Resolve errors with --batch execution --- bin/backpack | 2 +- lisp/backpack.el | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/bin/backpack b/bin/backpack index 221f758..297466f 100755 --- a/bin/backpack +++ b/bin/backpack @@ -22,7 +22,7 @@ fi if [ "$ACTION" = "ensure" ]; then echo "✅ Running Emacs in batch mode..." - emacs -nw --eval '(load (expand-file-name "ensure.el" backpack-emacs-dir))' + emacs --batch -l $INIT_DIR/early-init.el -l $INIT_DIR/ensure.el exit $? else echo "❌ Error: unknown action '$ACTION'" >&2 diff --git a/lisp/backpack.el b/lisp/backpack.el index 20bdf36..9b7fda5 100644 --- a/lisp/backpack.el +++ b/lisp/backpack.el @@ -152,13 +152,14 @@ If anything is missing here, Backpack Emacs will work as normal.") (funcall fn args-left))) ;; COMPAT: ...but restore `file-name-handler-alist' later, because it is ;; needed for handling encrypted or compressed files, among other things. - (add-hook 'emacs-startup-hook :depth 101 + (add-hook 'emacs-startup-hook (defun backpack--reset-file-handler-alist-h () (set-default-toplevel-value 'file-name-handler-alist ;; Merge instead of overwrite because there may have been changes to ;; `file-name-handler-alist' since startup we want to preserve. - (delete-dups (append file-name-handler-alist old-value)))))) + (delete-dups (append file-name-handler-alist old-value)))) + 100)) (unless noninteractive ;; PERF: Resizing the Emacs frame (to accommodate fonts that are smaller or @@ -433,15 +434,18 @@ to `doom-profile-cache-dir' instead, so it can be safely cleaned up as part of (unless (require 'elpaca-autoloads nil t) (when (file-exists-p (expand-file-name "elpaca-autoloads.el" repo)) - (load (expand-file-name "elpaca-autoloads.el" repo))))) + (load (expand-file-name "elpaca-autoloads.el" repo)))) + ;; TODO(shackra): append every package's build to load-path + ) (defun backpack-start (&optional interactive?) "Start the Backpack session." (when (daemonp) (message "Starting in daemon mode...") - (add-hook 'kill-emacs-hook :depth 100 + (add-hook 'kill-emacs-hook (lambda () - (message "Killing Emacs. ¡Adiós!")))) + (message "Killing Emacs. ¡Adiós!")) + 100)) (if interactive? (progn ;; TODO(shackra): incremental loading of packages @@ -451,12 +455,12 @@ to `doom-profile-cache-dir' instead, so it can be safely cleaned up as part of ;; load user's private configuration (let ((init-file (expand-file-name "init.el" backpack-user-dir))) - (load init-file t)) - - (backpack-load-gear-files)) + (load init-file t) + (backpack-load-gear-files))) (progn ;; CLI stuff I still don't have any use for, yet (with-file-modes 448 - (mapc (apply-partially #'make-directory 'parents) + (mapc (lambda (dir) + (make-directory dir t)) (list backpack-cache-dir backpack-nonessential-dir backpack-state-dir From c90e23088c0d4f6a1d5a820b196400678ea2cf8a Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Sun, 12 Oct 2025 02:42:12 -0600 Subject: [PATCH 06/10] chg: Place function call closer to elpaca-wait --- ensure.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ensure.el b/ensure.el index cb78a19..44e0309 100644 --- a/ensure.el +++ b/ensure.el @@ -32,8 +32,6 @@ (elpaca-generate-autoloads "elpaca" repo) (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) - (backpack-load-gear-files) - (add-hook 'elpaca-post-queue-hook (lambda () ;; (save-default-bg-fg-colors) @@ -44,4 +42,5 @@ (treesit-auto-install-all)))) (kill-emacs 0))) + (backpack-load-gear-files) (elpaca-wait)) From 8ccf8f06067018223267cf7946553ff81025b69b Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Mon, 13 Oct 2025 14:57:48 -0600 Subject: [PATCH 07/10] chg: Run elpaca-process-queues after Backpack finished starting I can't tame elpaca --- lisp/backpack.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/backpack.el b/lisp/backpack.el index 9b7fda5..c0375ed 100644 --- a/lisp/backpack.el +++ b/lisp/backpack.el @@ -434,9 +434,10 @@ to `doom-profile-cache-dir' instead, so it can be safely cleaned up as part of (unless (require 'elpaca-autoloads nil t) (when (file-exists-p (expand-file-name "elpaca-autoloads.el" repo)) - (load (expand-file-name "elpaca-autoloads.el" repo)))) - ;; TODO(shackra): append every package's build to load-path - ) + (load (expand-file-name "elpaca-autoloads.el" repo))))) + +(defvar backpack-after-init-hook '(elpaca-process-queues) + "Abnormal hook for functions to be run after Backpack was initialize.") (defun backpack-start (&optional interactive?) "Start the Backpack session." @@ -487,6 +488,7 @@ to `doom-profile-cache-dir' instead, so it can be safely cleaned up as part of (setq backpack-init-time (float-time (time-subtract (current-time) before-init-time))) ;; TODO: run hooks? + (run-hooks 'backpack-after-init-hook) (when (eq (default-value 'gc-cons-threshold) most-positive-fixnum) (setq-default gc-cons-threshold (* 16 1024 1024))) From a27a4d17ae60d4e2ba12ca3a5474908d54e1ed75 Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Mon, 13 Oct 2025 14:58:29 -0600 Subject: [PATCH 08/10] fix: Backpack ensure should ensure that elpaca is installed --- ensure.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ensure.el b/ensure.el index 44e0309..48be5c2 100644 --- a/ensure.el +++ b/ensure.el @@ -32,6 +32,8 @@ (elpaca-generate-autoloads "elpaca" repo) (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) + (elpaca `(,@elpaca-order)) + (add-hook 'elpaca-post-queue-hook (lambda () ;; (save-default-bg-fg-colors) From 75f55a32a162b3b6c104e886d15d35eafdc059b5 Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Mon, 13 Oct 2025 14:58:51 -0600 Subject: [PATCH 09/10] chg: Go back to running `backpack ensure` in text mode --- bin/backpack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/backpack b/bin/backpack index 297466f..428e069 100755 --- a/bin/backpack +++ b/bin/backpack @@ -22,7 +22,7 @@ fi if [ "$ACTION" = "ensure" ]; then echo "✅ Running Emacs in batch mode..." - emacs --batch -l $INIT_DIR/early-init.el -l $INIT_DIR/ensure.el + emacs -nw -l $INIT_DIR/ensure.el exit $? else echo "❌ Error: unknown action '$ACTION'" >&2 From b5c743f79ac7fe23cf023638bbff687f9f866dd2 Mon Sep 17 00:00:00 2001 From: Jorge Javier Araya Navarro Date: Mon, 13 Oct 2025 15:12:02 -0600 Subject: [PATCH 10/10] fix: Fix test runner --- devenv.nix | 1 - etc/scripts/prepare-and-run.sh | 2 +- test/all-tests.el | 10 +--------- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/devenv.nix b/devenv.nix index 1b0a853..e41e28a 100644 --- a/devenv.nix +++ b/devenv.nix @@ -58,7 +58,6 @@ in pkgs.enchant.dev # for jinx ]; enterTest = '' - mkdir -p $DEVENV_ROOT/artifacts for-each-emacs $DEVENV_ROOT/. exit $? ''; diff --git a/etc/scripts/prepare-and-run.sh b/etc/scripts/prepare-and-run.sh index f9999e2..6ae3679 100644 --- a/etc/scripts/prepare-and-run.sh +++ b/etc/scripts/prepare-and-run.sh @@ -16,6 +16,6 @@ rsync -a --filter=':- .gitignore' --filter='- .git/' --filter='- .github/' $2 "$ $1 --version | head -n 1 -$1 --init-directory $TEST_HOME/.emacs.d -batch -l ert -l $TEST_HOME/.emacs.d/test/all-tests.el -f ert-run-tests-batch-and-exit +$1 --init-directory $TEST_HOME/.emacs.d -batch -l $TEST_HOME/.emacs.d/early-init.el -l ert -l $TEST_HOME/.emacs.d/test/all-tests.el -f ert-run-tests-batch-and-exit rm -rf $TEST_HOME diff --git a/test/all-tests.el b/test/all-tests.el index 241a6fc..c8cff2b 100644 --- a/test/all-tests.el +++ b/test/all-tests.el @@ -1,13 +1,5 @@ (require 'ert) -(defvar backpack--base-packages-dir (expand-file-name "base-packages" user-emacs-directory)) -(defvar backpack--leaf (expand-file-name "leaf.el" backpack--base-packages-dir)) -(defvar backpack--leaf-keywords (expand-file-name "leaf-keywords.el" backpack--base-packages-dir)) - -(add-to-list 'load-path backpack--leaf) -(add-to-list 'load-path backpack--leaf-keywords) -(add-to-list 'load-path (expand-file-name "pouch" user-emacs-directory)) - -(load-file (expand-file-name "test/pouch/backpack-pouch.el" user-emacs-directory)) +(load-file (expand-file-name "test/pouch/backpack-pouch.el" backpack-emacs-dir)) (provide 'all-tests)