Fix Emacs Elpaca bootstrap and startup

This commit is contained in:
2026-04-18 19:03:11 -07:00
parent 403fe0deef
commit 34ecc09def
6 changed files with 201 additions and 79 deletions

View File

@@ -1347,6 +1347,7 @@ Paradox is a package.el extension. I have no use for it now that I use straight.
** load-dir
#+BEGIN_SRC emacs-lisp
(use-package load-dir
:ensure (:host github :repo "emacs-straight/load-dir")
:demand t
:config
(progn
@@ -2670,7 +2671,7 @@ The following is taken from [[https://github.com/syl20bnr/spacemacs/blob/a650877
**** clj-refactor
#+BEGIN_SRC emacs-lisp
;;@WORKAROUND clj-refactor dependency inflections Version metadata
(use-package inflections :ensure (:depth nil :version elpaca-latest-tag :version-regexp "[[:digit:]]\\.[[:digit:]]"))
(use-package inflections)
(use-package clj-refactor
:commands clj-refactor-mode)
#+END_SRC
@@ -4108,8 +4109,19 @@ load-theme hook (See the heading below).
#+END_SRC
** Set Font
#+BEGIN_SRC emacs-lisp
(add-to-list 'default-frame-alist
'(font . "JetBrainsMono Nerd Font-10:weight=medium"))
(defvar imalison:preferred-font-families
'("JetBrainsMono Nerd Font"
"JetBrains Mono"
"JetBrainsMono Nerd Font Mono"))
(defun imalison:default-font-parameter ()
(catch 'font
(dolist (family imalison:preferred-font-families)
(when (find-font (font-spec :family family))
(throw 'font (format "%s-10" family))))))
(when-let ((font (imalison:default-font-parameter)))
(add-to-list 'default-frame-alist `(font . ,font)))
#+END_SRC
** imalison:appearance
#+BEGIN_SRC emacs-lisp

View File

@@ -1 +1,3 @@
;; -*- lexical-binding: t; -*-
(setq package-enable-at-startup nil)

View File

@@ -1,6 +1,23 @@
;; Elpaca Installer -*- lexical-binding: t; -*-
(defvar elpaca-installer-version 0.12)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defun elpaca-installer--state-root ()
"Return a writable root for Elpaca state."
(let* ((preferred user-emacs-directory)
(fallback (expand-file-name
"emacs/"
(or (getenv "XDG_STATE_HOME")
(expand-file-name "~/.local/state/")))))
(condition-case nil
(progn
(make-directory preferred t)
preferred)
(file-error
(make-directory fallback t)
fallback))))
(defvar elpaca-directory
(expand-file-name "elpaca/" (elpaca-installer--state-root)))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-sources-directory (expand-file-name "sources/" elpaca-directory))
(defvar elpaca-legacy-repos-directory (expand-file-name "repos/" elpaca-directory))
@@ -9,6 +26,26 @@
:files (:defaults "elpaca-test.el" (:exclude "extensions"))
:build (:not elpaca-activate)))
(defun elpaca-installer--ensure-symlink (target alias)
"Create symlink from ALIAS to TARGET, ignoring pre-existing paths."
(condition-case nil
(make-symbolic-link target alias)
(file-already-exists nil)))
(defun elpaca-installer--build-stale-p (build)
"Return non-nil when BUILD contains older compiled artifacts than its sources."
(when (file-directory-p build)
(catch 'stale
(dolist (entry (directory-files build t "\\.elc?\\'"))
(when (string-suffix-p ".elc" entry)
(let* ((source (substring entry 0 -1))
(source-truename (and (file-exists-p source)
(ignore-errors (file-truename source)))))
(when (and source-truename
(file-newer-than-file-p source-truename entry))
(throw 'stale t)))))
nil)))
(defun elpaca-installer--repo-installer-version (repo)
"Return the installer version expected by elpaca checkout at REPO."
(let ((elpaca-el (expand-file-name "elpaca.el" repo)))
@@ -34,9 +71,18 @@
(dolist (entry (directory-files build t directory-files-no-dot-files-regexp))
(when-let* ((target (file-symlink-p entry))
(truename (ignore-errors (file-truename entry)))
(source-root (and truename
(directory-file-name
(file-name-directory truename)))))
(source-root
(catch 'source-root
(dolist (root roots)
(when (string-prefix-p root truename)
(let* ((relative (file-relative-name truename root))
(repo-name (car (split-string relative "/" t)))
(repo-root (and repo-name
(expand-file-name repo-name root))))
(when (file-directory-p repo-root)
(throw 'source-root
(directory-file-name repo-root))))))
nil)))
(dolist (root roots)
(when (string-prefix-p root truename)
(when (file-directory-p source-root)
@@ -68,39 +114,21 @@
((file-symlink-p source)
(delete-file source)
(if desired-source
(make-symbolic-link desired-source
(directory-file-name source))
(elpaca-installer--ensure-symlink
desired-source
(directory-file-name source))
(delete-directory build 'recursive)))
((file-exists-p source) nil)
(desired-source
(make-symbolic-link desired-source
(directory-file-name source)))
(elpaca-installer--ensure-symlink
desired-source
(directory-file-name source)))
(t
(delete-directory build 'recursive))))))))
(defun elpaca-installer--repair-source-dir-aliases ()
"Create compatibility symlinks for legacy repos ending in `.el'."
(when (file-directory-p elpaca-sources-directory)
(dolist (entry (directory-files elpaca-sources-directory t directory-files-no-dot-files-regexp))
(when-let* (((file-directory-p entry))
(name (file-name-nondirectory (directory-file-name entry)))
((string-suffix-p ".el" name))
(alias-name (substring name 0 (- (length name) 3)))
(alias (expand-file-name alias-name elpaca-sources-directory))
(target (ignore-errors
(directory-file-name (file-truename entry)))))
(cond
((and (file-symlink-p alias)
(equal (ignore-errors (directory-file-name (file-truename alias)))
target))
nil)
((file-symlink-p alias)
(delete-file alias)
(make-symbolic-link target alias))
((file-exists-p alias)
nil)
(t
(make-symbolic-link target alias)))))))
"Compatibility hook retained for older configs."
nil)
;; Elpaca now expects package sources under `sources/`. Preserve older local
;; installs that still use `repos/` so startup can recover without recloning.
(when (and (file-directory-p elpaca-legacy-repos-directory)
@@ -109,8 +137,9 @@
(directory-file-name elpaca-sources-directory)))
(when (and (file-directory-p elpaca-sources-directory)
(not (file-exists-p elpaca-legacy-repos-directory)))
(make-symbolic-link (directory-file-name elpaca-sources-directory)
(directory-file-name elpaca-legacy-repos-directory)))
(elpaca-installer--ensure-symlink
(directory-file-name elpaca-sources-directory)
(directory-file-name elpaca-legacy-repos-directory)))
(elpaca-installer--repair-source-dir-aliases)
(elpaca-installer--repair-build-source-layout)
(let* ((repo (expand-file-name "elpaca/" elpaca-sources-directory))
@@ -124,13 +153,14 @@
((not (equal repo-version (format "%s" elpaca-installer-version)))))
(when (file-directory-p build)
(delete-directory build 'recursive))
(when (file-directory-p elpaca-cache-directory)
(when (and (boundp 'elpaca-cache-directory)
(file-directory-p elpaca-cache-directory))
(delete-directory elpaca-cache-directory 'recursive))
(when (file-directory-p repo)
(delete-directory repo 'recursive)))
(when (elpaca-installer--build-stale-p build)
(delete-directory build 'recursive))
(add-to-list 'load-path repo)
(when (file-exists-p build)
(add-to-list 'load-path build))
(unless (file-exists-p repo)
(make-directory repo t)
(when (<= emacs-major-version 28) (require 'subr-x))
@@ -154,5 +184,7 @@
(require 'elpaca)
(elpaca-generate-autoloads "elpaca" repo)
(let ((load-source-file-function nil)) (load autoloads))))
(require 'elpaca)
(setq elpaca-log-functions '(elpaca-log-command-query))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))

View File

@@ -8,11 +8,76 @@
(defvar imalison:do-benchmark nil)
(defun emacs-directory-filepath (filename)
(concat (file-name-directory load-file-name) filename))
(expand-file-name filename user-emacs-directory))
(load-file (expand-file-name "elpaca-installer.el" user-emacs-directory))
;; Elpaca's initial queue logger can fire during self-bootstrap before its
;; helper is callable under --debug-init. Keep command logging, but skip the
;; fragile initial-queue logger so startup diagnostics reach the real config.
(setq elpaca-log-functions '(elpaca-log-command-query))
;; Default hosted git clones to SSH (e.g., git@github.com:owner/repo.git).
(setq elpaca-order-defaults (plist-put elpaca-order-defaults :protocol 'ssh))
(defun imalison:existing-executable (&rest candidates)
(seq-find #'file-executable-p (delq nil candidates)))
(defun imalison:emacs-bin-directory ()
(let ((emacsclient (or (executable-find "emacsclient")
(when invocation-directory
(expand-file-name "emacsclient" invocation-directory))
(when invocation-directory
(expand-file-name "../../../../bin/emacsclient"
invocation-directory)))))
(when (and emacsclient (file-executable-p emacsclient))
(directory-file-name (file-name-directory emacsclient)))))
(defun imalison:emacsclient-executable ()
(imalison:existing-executable
(executable-find "emacsclient")
(when invocation-directory
(expand-file-name "emacsclient" invocation-directory))
(when invocation-directory
(expand-file-name "../../../../bin/emacsclient" invocation-directory))))
;; GUI Emacs launched from the app bundle may not inherit a PATH that contains
;; the matching emacsclient binary.
(when-let ((emacs-bin (imalison:emacs-bin-directory)))
(add-to-list 'exec-path emacs-bin)
(setenv "PATH" (concat emacs-bin path-separator (or (getenv "PATH") ""))))
(setq emacsclient-program-name
(imalison:emacsclient-executable))
(setq with-editor-emacsclient-executable
(imalison:emacsclient-executable))
(defun imalison:elpaca-menu-local-repos (request &optional item)
(when (eq request 'index)
(let ((root elpaca-sources-directory))
(cl-labels
((item-info
(pkg)
(let* ((name (symbol-name pkg))
(dir (expand-file-name name root))
(git-dir (expand-file-name ".git" dir)))
(when (file-directory-p git-dir)
(with-temp-buffer
(when (zerop (call-process "git" nil t nil "-C" dir "config" "--get" "remote.origin.url"))
(let ((remote (string-trim (buffer-string))))
(when (not (string-empty-p remote))
(list :source "Local repos"
:recipe (list :package name
:repo remote
:local-repo name))))))))))
(if item
(item-info item)
(cl-loop for path in (directory-files root nil "^[^.]" t)
for pkg = (intern path)
for info = (item-info pkg)
when info
collect (cons pkg info)))))))
(add-to-list 'elpaca-menu-functions #'imalison:elpaca-menu-local-repos t)
(elpaca elpaca-use-package (elpaca-use-package-mode))
(elpaca-wait)
(setq use-package-enable-imenu-support t)
@@ -40,6 +105,15 @@
:config
(progn (dash-enable-font-lock)))
;; Some split packages fall through the active menus in this config. Give
;; Elpaca an explicit source so startup doesn't get stuck on recipe lookup or
;; stale branch-mapped clones.
(elpaca `(queue :host github :repo "emacs-straight/queue"))
(elpaca `(git-commit :host github :repo "magit/magit"
:files ("lisp/git-commit.el" "lisp/git-commit-pkg.el")))
(elpaca `(magit-section :host github :repo "magit/magit"
:files ("lisp/magit-section.el" "lisp/magit-section-pkg.el")))
(use-package gh
:defer t
:ensure (:host github :repo "IvanMalison/gh.el"))
@@ -85,6 +159,22 @@
(elpaca-wait)
(require 'org)
(defun imalison:load-literate-file (org-file)
(let ((el-file (concat (file-name-sans-extension org-file) ".el")))
;; Prefer the tangled file on normal startup and only re-tangle when the
;; Org source changed.
(if (and (file-exists-p el-file)
(not (file-newer-than-file-p org-file el-file)))
(load-file el-file)
(org-babel-load-file org-file))))
(defun imalison:load-kat-mode ()
(let ((debug-on-error t))
(imalison:load-literate-file
(emacs-directory-filepath "kat-mode.org"))))
;; Install transient early to prevent built-in version from loading
;; Workaround: overriding-text-conversion-style is void on pgtk builds (no
;; HAVE_TEXT_CONVERSION) but transient's .elc compiled on X11 has static-if
@@ -99,29 +189,25 @@
;; Magit's split packages are compiled separately; make them available before
;; the larger config queue reaches magit itself.
(use-package git-commit
:ensure (:host github :repo "magit/magit"
:files ("lisp/git-commit.el" "lisp/git-commit-pkg.el")
:wait t)
:ensure nil
:defer t)
(use-package magit-section
:ensure (:host github :repo "magit/magit"
:files ("lisp/magit-section.el" "lisp/magit-section-pkg.el")
:wait t)
:ensure nil
:defer t)
(elpaca-wait)
(when (or (equal (s-trim (shell-command-to-string "whoami")) "kat")
imalison:kat-mode)
(let ((debug-on-error t))
(org-babel-load-file
(concat (file-name-directory load-file-name) "kat-mode.org"))))
(let ((debug-on-error t))
(org-babel-load-file
(imalison:load-literate-file
(expand-file-name "README.org" user-emacs-directory)))
(when (or (equal (s-trim (shell-command-to-string "whoami")) "kat")
imalison:kat-mode)
;; Machine-specific overrides can reuse packages declared in README once
;; Elpaca has activated the main init queue.
(add-hook 'elpaca-after-init-hook #'imalison:load-kat-mode))
;; (when imalison:do-benchmark (benchmark-init/deactivate))
;; Local Variables:

View File

@@ -1,6 +1,7 @@
* evil
#+begin_src emacs-lisp
(use-package evil
:ensure nil
:demand t
:config
(progn
@@ -22,6 +23,7 @@
This makes evil-mode play nice with org-fc
#+begin_src emacs-lisp
(use-package org-fc
:ensure (:host github :repo "l3kn/org-fc")
:demand t
:config
(progn
@@ -49,6 +51,7 @@ This makes evil-mode play nice with org-fc
#+begin_src emacs-lisp
(setq imalison:org-whoami "Kat Huang")
(setq org-directory "~/org/") ; This is the directory where you want to save your Org files. Change as necessary.
(defvar org-capture-templates nil)
(add-to-list 'org-capture-templates
'("j" "Journal" entry (file+datetree "~/org/daily-journal.org")
"* %?\nEntered on %U\n %i\n %a"))
@@ -61,7 +64,7 @@ This makes evil-mode play nice with org-fc
** Journal
#+begin_src emacs-lisp
(setq imalison:journal-template-filepath
(imalison:join-paths org-directory "templates" "daily-journal-template.org"))
(expand-file-name "templates/daily-journal-template.org" org-directory))
#+end_src
** Insert a link to a task selected from agenda
#+begin_src emacs-lisp
@@ -119,6 +122,7 @@ This makes evil-mode play nice with org-fc
* Disable autoflake
#+begin_src emacs-lisp
(use-package apheleia
:ensure nil
:demand t
:config
(progn
@@ -131,11 +135,6 @@ This makes evil-mode play nice with org-fc
* Packages
#+begin_src emacs-lisp
(use-package org-drill)
(require 'package)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
#+end_src
* Disable wild notifactions
@@ -145,26 +144,17 @@ This makes evil-mode play nice with org-fc
* Swift
#+begin_src emacs-lisp
(require 'package)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(use-package swift-mode
:ensure nil
:demand t
:config
(add-to-list 'auto-mode-alist '("\\.swift\\'" . swift-mode)))
(unless (package-installed-p 'swift-mode)
(package-refresh-contents)
(package-install 'swift-mode))
(unless (package-installed-p 'lsp-mode)
(package-refresh-contents)
(package-install 'lsp-mode))
;; Swift Mode
(require 'swift-mode)
(add-to-list 'auto-mode-alist '("\\.swift\\'" . swift-mode))
;; LSP Mode
(require 'lsp-mode)
(add-hook 'swift-mode-hook #'lsp)
(use-package lsp-mode
:ensure nil
:commands lsp
:config
(add-hook 'swift-mode-hook #'lsp))
;; Set the path to SourceKit-LSP if it's not in your PATH
(setq lsp-sourcekit-executable "/path/to/sourcekit-lsp")
@@ -173,4 +163,3 @@ This makes evil-mode play nice with org-fc
(setq lsp-sourcekit-executable-args '("-toolchain" "/path/to/swift-toolchain"))
#+end_src

View File

@@ -1011,6 +1011,7 @@ alphanumeric characters only."
** org-roam
#+begin_src emacs-lisp
(use-package org-roam
:if (file-directory-p (expand-file-name "~/org/roam/"))
:after org
:defer 1
:preface
@@ -1060,7 +1061,7 @@ alphanumeric characters only."
org-roam-buffer-visibility-fn 'imalison:org-roam-frame-based-buffer-visibility-fn)
(emit-make-mode-dependent imalison:org-roam-set-frame-visibility-mode frame-mode)))
:custom
(org-roam-directory (file-truename "~/org/roam/")))
(org-roam-directory (expand-file-name "~/org/roam/")))
#+end_src
***** ui
#+begin_src emacs-lisp