about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.emacs.d/.gitignore2
-rw-r--r--.emacs.d/early-init.el7
-rw-r--r--.emacs.d/lisp/init-clojure.el16
-rw-r--r--.emacs.d/lisp/init-completion.el33
-rw-r--r--.emacs.d/lisp/init-crux.el1
-rw-r--r--.emacs.d/lisp/init-editor.el19
-rw-r--r--.emacs.d/lisp/init-git.el5
-rw-r--r--.emacs.d/lisp/init-lsp.el33
-rw-r--r--.emacs.d/lisp/init-minibuffer.el25
-rw-r--r--.emacs.d/lisp/init-navigation.el9
-rw-r--r--.emacs.d/lisp/init-packages.el16
-rw-r--r--.emacs.d/lisp/init-project.el1
-rw-r--r--.emacs.d/lisp/init-shell.el36
-rw-r--r--.emacs.d/lisp/init-sql.el1
-rw-r--r--.emacs.d/lisp/init-ui.el2
-rw-r--r--.emacs.d/themes/non-modo-theme.el2
-rw-r--r--nix-conf/home/includes/clojure.nix1
-rw-r--r--nix-conf/home/includes/common.nix25
-rw-r--r--nix-conf/home/includes/darwin.nix71
-rw-r--r--nix-conf/home/includes/linux-dev.nix1
-rw-r--r--nix-conf/home/includes/linux-server.nix3
-rw-r--r--nix-conf/home/includes/secrets.yaml13
-rw-r--r--nix-conf/home/includes/zsh.nix343
-rw-r--r--nix-conf/home/otm.nix11
-rw-r--r--nix-conf/machines/djmuk1/configuration.nix12
-rw-r--r--nix-conf/machines/djmuk2/configuration.nix12
-rw-r--r--nix-conf/machines/edrahil/configuration.nix11
-rw-r--r--nix-conf/machines/egalmoth/configuration.nix22
28 files changed, 423 insertions, 310 deletions
diff --git a/.emacs.d/.gitignore b/.emacs.d/.gitignore
index 11659a7..2ce66c1 100644
--- a/.emacs.d/.gitignore
+++ b/.emacs.d/.gitignore
@@ -36,7 +36,7 @@ site-lisp
 straight
 !straight/versions
 elpaca
-elpa
+elpaca.lock
 eln-cache
 forge-database.sqlite
 sql
diff --git a/.emacs.d/early-init.el b/.emacs.d/early-init.el
index 1dd7a01..e55becc 100644
--- a/.emacs.d/early-init.el
+++ b/.emacs.d/early-init.el
@@ -2,6 +2,10 @@
 ;;; Commentary:
 ;;; Code:
 
+
+(when (eq system-type 'darwin)
+  (setq frame-resize-pixelwise t))
+
 (setq gc-cons-threshold most-positive-fixnum
       gc-cons-percentage 0.6)
 
@@ -21,7 +25,8 @@
 
 (setq frame-inhibit-implied-resize t)
 
-(unless (eq system-type 'darwin)
+(if (eq system-type 'darwin)
+    (add-to-list 'default-frame-alist '(undecorated-round . t))
   (toggle-frame-maximized)
   (add-to-list 'default-frame-alist '(fullscreen . maximized)))
 
diff --git a/.emacs.d/lisp/init-clojure.el b/.emacs.d/lisp/init-clojure.el
index c479836..7673565 100644
--- a/.emacs.d/lisp/init-clojure.el
+++ b/.emacs.d/lisp/init-clojure.el
@@ -102,12 +102,12 @@
   :init
   ;; Always show more of the path in clj buffer names.
   ;; Using setq-local in clojure-mode-hook is not enough, as it runs too late
-  (defun clj-uniquify-get-proposed-name (orig base dirname &optional depth original-dirname)
+  (defun clj-uniquify-get-proposed-name (orig base dirname &optional depth)
     (when (and (> (length base) 4)
                (string= ".clj" (substring base -4))
                (not (string= "project.clj" base)))
       (setq-local uniquify-min-dir-content 3))
-    (funcall orig base dirname depth original-dirname))
+    (funcall orig base dirname depth))
   (advice-add 'uniquify-get-proposed-name :around 'clj-uniquify-get-proposed-name)
   :hook
   (clojure-mode . clojure-mode-hook-fn))
@@ -152,10 +152,10 @@
     (cider-jack-in params))
   (defun load-debug-namespaces ()
     (interactive)
-    (cider-interactive-eval "(require 'snitch.core)" nil nil (cider--nrepl-pr-request-map))
-    (cider-interactive-eval "(require 'miracle.save)" nil nil (cider--nrepl-pr-request-map))
-    (cider-interactive-eval "(require 'sc.api)" nil nil (cider--nrepl-pr-request-map))
-    (cider-interactive-eval "(require '[debux.cs.core :refer [dbg dbgn dbgt]])" nil nil (cider--nrepl-pr-request-map)))
+    (cider-interactive-eval "(require 'snitch.core)" nil nil (cider--nrepl-pr-request-plist))
+    (cider-interactive-eval "(require 'miracle.save)" nil nil (cider--nrepl-pr-request-plist))
+    (cider-interactive-eval "(require 'sc.api)" nil nil (cider--nrepl-pr-request-plist))
+    (cider-interactive-eval "(require '[debux.cs.core :refer [dbg dbgn dbgt]])" nil nil (cider--nrepl-pr-request-plist)))
   (defun cider-toggle-boolean ()
     (interactive)
     (let ((opposite (pcase (cider-symbol-at-point)
@@ -196,12 +196,14 @@
         cider-connection-message-fn nil
         cider-show-error-buffer 'except-in-repl
         cider-test-fail-fast nil
+        cider-download-java-sources t
         clojure-toplevel-inside-comment-form t)
   (setq cider-clojure-compilation-error-phases nil)
   (setq-default cider-use-overlays t)
   (unbind-key "C-c C-l" cider-mode-map)
   (unbind-key "C-c C-b" cider-mode-map)
   (unbind-key "C-c C-b" cider-repl-mode-map)
+  (unbind-key "M-." cider-repl-mode-map)
 
   (defun fix-duplicate-windows ()
     "When all windows are the same, delete all of them except the current one."
@@ -213,6 +215,8 @@
   (:map cider-mode-map
         ("C-c M-l" . cider-load-file)
         ("C-c M-b" . cider-interrupt)
+        ("C-c C-j C-;" . cider-pprint-eval-last-sexp-to-comment)
+        ("C-c C-M-p" . cider-pprint-eval-last-sexp-to-repl)
         ("C-x M-i e" . cider-inspect-last-sexp)
         ("C-x M-i f" . cider-inspect-defun-at-point)
         ("C-x M-i l" . cider-inspect-last-result)
diff --git a/.emacs.d/lisp/init-completion.el b/.emacs.d/lisp/init-completion.el
index f7e07de..16eca6b 100644
--- a/.emacs.d/lisp/init-completion.el
+++ b/.emacs.d/lisp/init-completion.el
@@ -14,17 +14,10 @@
           (list '+elpaca-unload-dabbrev 'elpaca--activate-package)))
 
 (use-feature dabbrev
-  ;; Load newer version until 30.1 is released
-  ;; https://mail.gnu.org/archive/html/bug-gnu-emacs/2024-05/msg00422.html
-  ;; Relies on the fact that the emacs repo is checked out to elpaca/repos/project
-  :ensure `(dabbrev :build ,(+elpaca-dabbrev-build-steps) :repo "~/.emacs.d/elpaca/repos/project/" :files ("lisp/dabbrev.el"))
   :custom
   (dabbrev-case-distinction nil)
   (dabbrev-case-fold-search t)
-  (dabbrev-case-replace nil)
-  ;; TODO remove this after 30.1
-  :bind
-  ("C-M-/" . hippie-expand))
+  (dabbrev-case-replace nil))
 
 (use-package mono-complete
   :config
@@ -56,12 +49,12 @@
                                       try-expand-line
                                       try-complete-lisp-symbol-partially
                                       try-complete-lisp-symbol))
-  :config
-  ;; Modified from https://www.emacswiki.org/emacs/HippieExpand#h5o-9
-  (define-advice he-substitute-string (:after (str &optional trans-case) he-paredit-fix)
-    "Remove extra bracket when expanding line in paredit/smartparents mode."
-    (if (and (or smartparens-mode paredit-mode) (string-match "[]})]$" str))
-        (progn (backward-delete-char 1) (forward-char))))
+  :hook (elpaca-after-init . (lambda ()
+                               ;; Modified from https://www.emacswiki.org/emacs/HippieExpand#h5o-9
+                               (define-advice he-substitute-string (:after (str &optional trans-case) he-paredit-fix)
+                                 "Remove extra bracket when expanding line in paredit/smartparents mode."
+                                 (if (and (or smartparens-mode paredit-mode) (string-match "[]})]$" str))
+                                     (progn (backward-delete-char 1) (forward-char))))))
   :bind
   ("C-M-/" . hippie-expand))
 
@@ -83,10 +76,6 @@
   (orderless-component-separator 'orderless-escapable-split-on-space)
   (completion-styles '(orderless partial-completion basic))
   (completion-category-defaults nil)
-  (completion-category-overrides '((file (styles partial-completion orderless))
-                                   (command (styles +orderless-with-strict-leading-initialism))
-                                   (variable (styles +orderless-with-strict-leading-initialism))
-                                   (symbol (styles +orderless-with-strict-leading-initialism))))
   (orderless-matching-styles '(orderless-literal orderless-regexp orderless-strict-initialism))
   (orderless-style-dispatchers (list #'+orderless-consult-dispatch
                                      #'orderless-affix-dispatch))
@@ -127,6 +116,7 @@ candidate, in that order, at the beginning of words, with
 no words in between, beginning with the first word."
     (orderless-strict-initialism component t))
 
+  ;; Replace initialism (,) with strict-leading-initialism, and also add strict initialism
   (setf (alist-get ?, orderless-affix-dispatch-alist) #'orderless-strict-leading-initialism)
   (add-to-list 'orderless-affix-dispatch-alist '(?` . orderless-strict-initialism) t)
 
@@ -156,7 +146,12 @@ no words in between, beginning with the first word."
 
   ;; Based on https://github.com/minad/consult/wiki#minads-orderless-configuration
   (orderless-define-completion-style +orderless-with-strict-leading-initialism
-    (orderless-matching-styles '(orderless-literal orderless-regexp orderless-strict-leading-initialism))))
+    (orderless-matching-styles '(orderless-literal orderless-regexp orderless-strict-leading-initialism)))
+
+  (setopt completion-category-overrides '((file (styles partial-completion orderless))
+                                          (command (styles +orderless-with-strict-leading-initialism))
+                                          (variable (styles +orderless-with-strict-leading-initialism))
+                                          (symbol (styles +orderless-with-strict-leading-initialism)))))
 
 ;; code completion - corfu
 (use-package corfu
diff --git a/.emacs.d/lisp/init-crux.el b/.emacs.d/lisp/init-crux.el
index 9d00417..5f7b836 100644
--- a/.emacs.d/lisp/init-crux.el
+++ b/.emacs.d/lisp/init-crux.el
@@ -15,6 +15,7 @@
   ("C-^" . crux-top-join-line)
   ("C-<backspace>" . crux-kill-line-backwards)
   ([remap kill-whole-line] . crux-kill-whole-line)
+  ([remap keyboard-quit] . crux-keyboard-quit-dwim)
   ;; TODO don't need all of these
   ("C-<return>" . crux-smart-open-line)
   ("S-<return>" . crux-smart-open-line)
diff --git a/.emacs.d/lisp/init-editor.el b/.emacs.d/lisp/init-editor.el
index 1143b59..fc575c4 100644
--- a/.emacs.d/lisp/init-editor.el
+++ b/.emacs.d/lisp/init-editor.el
@@ -116,6 +116,13 @@
   :config
   (when (string-suffix-p "aspell" ispell-program-name)
     (setq ispell-extra-args '("--sug-mode=ultra")))
+  (unbind-key "C-," flyspell-mode-map)
+  (unbind-key "C-." flyspell-mode-map)
+  ;;(unbind-key "C-;" flyspell-mode-map)
+  :custom (flyspell-auto-correct-binding (kbd "C-x C-M-;"))
+  :bind (:map flyspell-mode-map
+              ("C-x C-," . flyspell-goto-next-error)
+              ("C-x C-." . flyspell-correct-word))
   :hook
   (text-mode . flyspell-mode)
   (prog-mode . flyspell-prog-mode))
@@ -162,8 +169,6 @@
 
 (defun +elpaca-unload-xref (e)
   (and (featurep 'xref) (unload-feature 'xref t))
-  ;; Make sure xref-find-definitions doesn't override this embark binding (unless https://github.com/oantolin/embark/issues/732 can be fixed)
-  (bind-key "M-." 'embark-dwim)
   ;; Make sure these aren't overwritten
   (setq xref-search-program 'ripgrep
         xref-show-xrefs-function #'consult-xref
@@ -176,7 +181,7 @@
           (list '+elpaca-unload-xref 'elpaca--activate-package)))
 
 (use-package xref
-  :ensure `(xref :build ,(+elpaca-xref-build-steps))
+  :ensure `(xref :build ,(+elpaca-xref-build-steps) :ref "87db670d045bea2d90139b1f741eea8db7c193ea" :pin t)
   :custom
   (xref-search-program 'ripgrep)
   (xref-show-xrefs-function #'consult-xref)
@@ -214,9 +219,7 @@ With a prefix argument, moves up `current-prefix-arg' sexps first."
   (add-to-list 'xref-prompt-for-identifier 'xref-find-references-other-frame t)
   :bind
   ("C-c q" . xref-find-references-current-defun)
-  ("C-c C-M-." . xref-find-definitions-current-list-function)
-  ;; Make sure xref-find-definitions doesn't override this embark binding (unless https://github.com/oantolin/embark/issues/732 can be fixed)
-  ("M-." . embark-dwim))
+  ("C-c C-M-." . xref-find-definitions-current-list-function))
 
 (use-package ws-butler
   :diminish
@@ -306,5 +309,9 @@ With a prefix argument, moves up `current-prefix-arg' sexps first."
               ("x" . cider-eval-region)
               ("r" . cider-insert-region-in-repl)))
 
+(use-package repeat-fu
+  :bind ("M-+" . repeat-fu-execute)
+  :hook ((prog-mode text-mode) . repeat-fu-mode))
+
 (provide 'init-editor)
 ;;; init-editor.el ends here
diff --git a/.emacs.d/lisp/init-git.el b/.emacs.d/lisp/init-git.el
index 759c36c..10c9c78 100644
--- a/.emacs.d/lisp/init-git.el
+++ b/.emacs.d/lisp/init-git.el
@@ -77,6 +77,8 @@
   ("C-c g r" . my/magit-refresh-state)
   ("C-c g m" . my/magit-update-master)
   ("C-c g C-c" . my/magit-stage-and-commit-file)
+  ;; Used by eshell-prompt-function (see init-shell.el)
+  :commands (magit-get-shortname magit-file-status)
   :config
   ;; Requires the following gitconfig:
   ;; [alias]
@@ -338,6 +340,9 @@ GitHub/Bitbucket/GitLab/... The URL will be added to the kill ring.  If
   ("C-c g c" . git-link-commit)
   ("C-c g b" . git-link-branch))
 
+(use-feature git-link-transient
+  :bind ("C-c g d" . git-link-dispatch))
+
 (use-feature git-related
   :bind
   ("C-c g #" . git-related-find-file)
diff --git a/.emacs.d/lisp/init-lsp.el b/.emacs.d/lisp/init-lsp.el
index 49ff138..9a0b4d5 100644
--- a/.emacs.d/lisp/init-lsp.el
+++ b/.emacs.d/lisp/init-lsp.el
@@ -56,7 +56,38 @@
         lsp-references-exclude-definition t
         ;; user cider for indendation and eldoc
         lsp-enable-indentation nil
-        lsp-eldoc-enable-hover nil))
+        lsp-eldoc-enable-hover nil)
+
+  ;; Copied from https://github.com/blahgeek/emacs-lsp-booster/blob/4200ed6ae0cd83b8e3fd1dbefb09121480951a22/README.md#configure-lsp-mode
+  (defun lsp-booster--advice-json-parse (old-fn &rest args)
+    "Try to parse bytecode instead of json."
+    (or
+     (when (equal (following-char) ?#)
+       (let ((bytecode (read (current-buffer))))
+         (when (byte-code-function-p bytecode)
+           (funcall bytecode))))
+     (apply old-fn args)))
+  (advice-add (if (progn (require 'json)
+                         (fboundp 'json-parse-buffer))
+                  'json-parse-buffer
+                'json-read)
+              :around
+              #'lsp-booster--advice-json-parse)
+  (defun lsp-booster--advice-final-command (old-fn cmd &optional test?)
+    "Prepend emacs-lsp-booster command to lsp CMD."
+    (let ((orig-result (funcall old-fn cmd test?)))
+      (if (and (not test?)                             ;; for check lsp-server-present?
+               (not (file-remote-p default-directory)) ;; see lsp-resolve-final-command, it would add extra shell wrapper
+               lsp-use-plists
+               (not (functionp 'json-rpc-connection))  ;; native json-rpc
+               (executable-find "emacs-lsp-booster"))
+          (progn
+            (when-let ((command-from-exec-path (executable-find (car orig-result))))  ;; resolve command from exec-path (in case not found in $PATH)
+              (setcar orig-result command-from-exec-path))
+            (message "Using emacs-lsp-booster for %s!" orig-result)
+            (cons "emacs-lsp-booster" orig-result))
+        orig-result)))
+  (advice-add 'lsp-resolve-final-command :around #'lsp-booster--advice-final-command))
 
 (provide 'init-lsp)
 ;;; init-lsp.el ends here
diff --git a/.emacs.d/lisp/init-minibuffer.el b/.emacs.d/lisp/init-minibuffer.el
index 93c18dd..118f730 100644
--- a/.emacs.d/lisp/init-minibuffer.el
+++ b/.emacs.d/lisp/init-minibuffer.el
@@ -82,18 +82,11 @@
              (eq 'file (vertico--metadata-get 'category)))
         (add-to-history minibuffer-history-variable (minibuffer-contents))))
 
-  ;; https://github.com/minad/vertico/wiki#customize-sorting-based-on-completion-category
-  (defun sort-directories-first (files)
-    ;; Still sort by history position, length and alphabetically
-    (setq files (vertico-sort-history-length-alpha files))
-    ;; But then move directories first
-    (nconc (seq-filter (lambda (x) (string-suffix-p "/" x)) files)
-           (seq-remove (lambda (x) (string-suffix-p "/" x)) files)))
   (defun toggle-sort-directories-first ()
     (interactive)
-    (if (eq vertico-sort-function 'sort-directories-first)
+    (if (eq vertico-sort-function 'vertico-sort-directories-first)
         (set (make-local-variable 'vertico-sort-function) 'vertico-sort-history-length-alpha)
-      (set (make-local-variable 'vertico-sort-function) 'sort-directories-first))
+      (set (make-local-variable 'vertico-sort-function) 'vertico-sort-directories-first))
     (setq vertico--input t)
     (vertico--update))
 
@@ -143,7 +136,8 @@
         '((execute-extended-command
            (+vertico-transform-functions . +vertico-highlight-enabled-mode))))
   (setq vertico-multiform-categories
-        '((file (+vertico-transform-functions . +vertico-highlight-directory))
+        '((file (+vertico-transform-functions . +vertico-highlight-directory)
+                (:keymap . vertico-directory-map))
           (imenu grid)))
   :bind (:map vertico-multiform-map
               ("M-H" . vertico-multiform-buffer-grid)))
@@ -521,6 +515,9 @@ The symbol at point is added to the future history."
 (use-package consult-ls-git
   :bind ("C-c g f" . consult-ls-git))
 
+(use-package consult-vc-modified-files
+  :bind (:map vc-prefix-map ("f" . consult-vc-modified-files)))
+
 (use-package consult-project-extra)
 
 (use-package marginalia
@@ -532,8 +529,9 @@ The symbol at point is added to the future history."
 (use-package embark
   :bind
   (("C-." . embark-act)
-   ("M-." . embark-dwim)
    ([remap xref-find-definitions-current-list-function] . embark-dwim-beginning-of-list)
+   ([remap xref-find-definitions] . embark-dwim)
+   ([remap xref-find-definitions-other-window] . embark-dwim-other-window)
    ("C-c C-o" . embark-export)
    ("C-h b" . embark-bindings)
    ("C-h B" . describe-bindings)
@@ -548,6 +546,11 @@ The symbol at point is added to the future history."
   :custom
   (prefix-help-command 'embark-prefix-help-command)
   :config
+  (defun embark-dwim-other-window ()
+    "Like `embark-dwim' but switch to the other window."
+    (interactive)
+    (other-window-prefix)
+    (embark-dwim))
   (defun embark-dwim-beginning-of-list ()
     "`embark-dwim' at the beginning of the current list.
 With a prefix argument, moves up `current-prefix-arg' sexps first."
diff --git a/.emacs.d/lisp/init-navigation.el b/.emacs.d/lisp/init-navigation.el
index e178d70..b407e7b 100644
--- a/.emacs.d/lisp/init-navigation.el
+++ b/.emacs.d/lisp/init-navigation.el
@@ -7,6 +7,13 @@
   (avy-all-windows nil)
   (avy-all-windows-alt t)
   (avy-timeout-seconds 0.3)
+  :init
+  ;; Allow C-[ to be bound (instead of being equivalent to ESC), but only in GUI Emacs
+  ;; https://emacs.stackexchange.com/a/52334
+  (let ((frame (framep (selected-frame))))
+    (or (eq  t  frame)
+        (eq 'pc frame)
+        (define-key input-decode-map (kbd "C-[") [control-bracketleft])))
   :config
   ;; https://karthinks.com/software/avy-can-do-anything/#avy-plus-embark-any-action-anywhere
   (defun avy-action-embark (pt)
@@ -38,7 +45,7 @@
   ("C-c C-;" . avy-copy-as-kill-in-line))
 
 (use-package casual-avy
-  :bind ("C-M-;" . casual-avy-tmenu))
+  :bind ([control-bracketleft] . casual-avy-tmenu))
 
 (use-package smartscan
   :custom (smartscan-symbol-selector "symbol")
diff --git a/.emacs.d/lisp/init-packages.el b/.emacs.d/lisp/init-packages.el
index ecc225e..55b3eb5 100644
--- a/.emacs.d/lisp/init-packages.el
+++ b/.emacs.d/lisp/init-packages.el
@@ -3,12 +3,12 @@
 ;;; Code:
 
 ;; Elpaca installer block
-(defvar elpaca-installer-version 0.8)
+(defvar elpaca-installer-version 0.11)
 (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
+                              :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))
@@ -18,7 +18,7 @@
   (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))
+    (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"
@@ -38,7 +38,7 @@
   (unless (require 'elpaca-autoloads nil t)
     (require 'elpaca)
     (elpaca-generate-autoloads "elpaca" repo)
-    (load "./elpaca-autoloads")))
+    (let ((load-source-file-function nil)) (load "./elpaca-autoloads"))))
 (add-hook 'after-init-hook #'elpaca-process-queues)
 (elpaca `(,@elpaca-order))
 ;; End of elpaca installer block
@@ -164,14 +164,6 @@ using this command."
       (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.
diff --git a/.emacs.d/lisp/init-project.el b/.emacs.d/lisp/init-project.el
index d2c7ca7..e66a4cd 100644
--- a/.emacs.d/lisp/init-project.el
+++ b/.emacs.d/lisp/init-project.el
@@ -5,6 +5,7 @@
 (require 'subr-x)
 
 (use-package project
+  :ensure (:ref "87db670d045bea2d90139b1f741eea8db7c193ea" :pin t)
   :config
   (defun project--clojure-switch-to-test (filename project-root)
     (let* ((project-src-file (string-remove-prefix project-root filename))
diff --git a/.emacs.d/lisp/init-shell.el b/.emacs.d/lisp/init-shell.el
index 8a64d4b..bf737cb 100644
--- a/.emacs.d/lisp/init-shell.el
+++ b/.emacs.d/lisp/init-shell.el
@@ -9,21 +9,31 @@
   (eshell-mode-hook . (lambda () (setenv "TERM" "xterm-256color")))
   :custom
   (eshell-directory-name (expand-file-name "eshell" save-dir))
+  ;; https://lambdaland.org/posts/2024-08-19_fancy_eshell_prompt/#eshell-prompt
+  (eshell-highlight-prompt nil)
+  (eshell-prompt-regexp "^[^#$\n]* [$#] ")
   (eshell-prompt-function
-   ;; Based on https://www.reddit.com/r/emacs/comments/6f0rkz/my_fancy_eshell_prompt/
    (lambda ()
-     (concat
-      (propertize "┌─[" 'face `(:foreground "green"))
-      (propertize (user-login-name) 'face `(:foreground "red"))
-      (propertize "@" 'face `(:foreground "green"))
-      (propertize (system-name) 'face `(:foreground "LightBlue"))
-      (propertize "]──[" 'face `(:foreground "green"))
-      (propertize (format-time-string "%H:%M" (current-time)) 'face `(:foreground "yellow"))
-      (propertize "]──[" 'face `(:foreground "green"))
-      (propertize (concat (eshell/pwd)) 'face `(:foreground "white"))
-      (propertize "]\n" 'face `(:foreground "green"))
-      (propertize "└─>" 'face `(:foreground "green"))
-      (propertize (if (= (user-uid) 0) " # " " $ ") 'face `(:foreground "green")))))
+     (let* ((cwd (abbreviate-file-name (eshell/pwd)))
+            (ref (magit-get-shortname "HEAD"))
+            (stat (magit-file-status))
+            (x-stat eshell-last-command-status)
+            (git-chunk
+             (if ref
+                 (format "%s%s%s "
+                         (propertize (if stat "[" "(") 'font-lock-face (list :foreground (if stat "red" "green")))
+                         (propertize ref 'font-lock-face '(:foreground "yellow"))
+                         (propertize (if stat "]" ")") 'font-lock-face (list :foreground (if stat "red" "green"))))
+               "")))
+       (propertize
+        (format "%s %s %s$ "
+                (if (< 0 x-stat) (format (propertize "!%s" 'font-lock-face '(:foreground "red")) x-stat)
+                  (propertize "➤" 'font-lock-face (list :foreground (if (< 0 x-stat) "red" "green"))))
+                (propertize cwd 'font-lock-face '(:foreground "#45babf"))
+                git-chunk)
+        'read-only t
+        'front-sticky   '(font-lock-face read-only)
+        'rear-nonsticky '(font-lock-face read-only)))))
   :config
   (setenv "PAGER" "cat"))
 
diff --git a/.emacs.d/lisp/init-sql.el b/.emacs.d/lisp/init-sql.el
index d1a3fe3..cf3a89a 100644
--- a/.emacs.d/lisp/init-sql.el
+++ b/.emacs.d/lisp/init-sql.el
@@ -49,6 +49,7 @@
   :bind ("C-c c C-u" . sqlup-capitalize-keywords-in-region))
 
 (use-package sql-indent
+  :diminish sqlind-minor-mode
   :commands sqlind-minor-mode)
 
 (use-package sqlformat
diff --git a/.emacs.d/lisp/init-ui.el b/.emacs.d/lisp/init-ui.el
index 354f187..50e9cdb 100644
--- a/.emacs.d/lisp/init-ui.el
+++ b/.emacs.d/lisp/init-ui.el
@@ -8,6 +8,8 @@
   :hook
   (elpaca-after-init . (lambda ()
                          (cond
+                          ((find-font (font-spec :name "aporetic serif mono"))
+                           (set-face-attribute 'default nil :font "aporetic serif mono"))
                           ((find-font (font-spec :name "iosevka comfy"))
                            (set-face-attribute 'default nil :font "iosevka comfy"))
                           ((find-font (font-spec :name "iosevka"))
diff --git a/.emacs.d/themes/non-modo-theme.el b/.emacs.d/themes/non-modo-theme.el
index c5f4422..4ef4a54 100644
--- a/.emacs.d/themes/non-modo-theme.el
+++ b/.emacs.d/themes/non-modo-theme.el
@@ -1479,7 +1479,7 @@
    `(shortdoc-section (())) ; remove the default's variable-pitch style
 ;;;;; show-paren-mode
    `(show-paren-match ((,class :inherit bold :background "#7416b5" :foreground "#ffffff" :underline t)))
-   `(show-paren-match-expression ((,class :background "#221044")))
+   `(show-paren-match-expression ((,class :background "grey12")))
    `(show-paren-mismatch ((,class :background "#a4202a" :foreground "#ffffff")))
 ;;;;; shr
    `(shr-abbreviation ((,class :foreground "#9d9def" :underline (:color "#5f6fff" :style wave))))
diff --git a/nix-conf/home/includes/clojure.nix b/nix-conf/home/includes/clojure.nix
index a942a90..3915ab3 100644
--- a/nix-conf/home/includes/clojure.nix
+++ b/nix-conf/home/includes/clojure.nix
@@ -14,6 +14,7 @@ in
       babashka
       clj-kondo
       clojure-lsp
+      emacs-lsp-booster
       jet
       maven
       neil
diff --git a/nix-conf/home/includes/common.nix b/nix-conf/home/includes/common.nix
index 960a74c..e12558c 100644
--- a/nix-conf/home/includes/common.nix
+++ b/nix-conf/home/includes/common.nix
@@ -8,20 +8,6 @@ let
   hcr = pkgs.callPackage ./scripts/hm-changes-report.nix { inherit config pkgs; };
   scr = pkgs.callPackage ./scripts/system-changes-report.nix { inherit config pkgs; };
   unstable = import <unstable> { };
-
-  nix-search = (
-    pkgs.buildGoModule {
-      pname = "nix-search";
-      version = "0.3.1";
-      src = pkgs.fetchFromGitHub {
-        owner = "diamondburned";
-        repo = "nix-search";
-        rev = "e616ac1c82a616fa6e6d8c94839c5052eb8c808d";
-        hash = "sha256-h9yYOjL9i/m0r5NbqMcLMFNnwSKsIgfUr5qk+47pOtc=";
-      };
-      vendorHash = "sha256-bModWDH5Htl5rZthtk/UTw/PXT+LrgyBjsvE6hgIePY=";
-    }
-  );
 in
 {
   imports = [
@@ -64,8 +50,10 @@ in
     aspellDicts.en
     aspellDicts.en-computers
     aspellDicts.en-science
+    bandwhich
     bottom
     broot
+    comma
     curl
     diff-so-fancy
     difftastic
@@ -97,6 +85,8 @@ in
     nixpkgs-review
     nvd
     pass
+    procs
+    pstree
     rage
     ripgrep
     rlwrap
@@ -111,11 +101,12 @@ in
     uni
     unzip
     w3m
+    xan
     yq
+    zip
     zstd
 
     unstable.nixfmt-rfc-style
-    unstable.wcurl
   ];
 
   programs.bat = {
@@ -140,8 +131,7 @@ in
   programs.eza = {
     enable = true;
     git = true;
-    # TODO remove when 24.11 is released
-    icons = if  builtins.substring 0 5 lib.version == "24.05" then true else "auto";
+    icons = "auto";
     enableBashIntegration = false;
     enableZshIntegration = false;
     enableFishIntegration = false;
@@ -375,6 +365,7 @@ in
 
   programs.lsd = {
     enable = true;
+    enableZshIntegration = false; # don't set aliases
     settings = {
       indicators = true;
       #layout = "oneline";
diff --git a/nix-conf/home/includes/darwin.nix b/nix-conf/home/includes/darwin.nix
index ebda874..e85f3f9 100644
--- a/nix-conf/home/includes/darwin.nix
+++ b/nix-conf/home/includes/darwin.nix
@@ -26,6 +26,63 @@ let
         --prefix PYTHONPATH : $out/${pkgs.mopidyPackages.python.sitePackages}
     '';
   };
+
+  # https://github.com/NixOS/nixpkgs/issues/395169
+  patched-pkgs = pkgs.extend (
+    _final: prev: {
+      ld64 = prev.ld64.overrideAttrs (old: {
+        patches = old.patches ++ [ ./Dedupe-RPATH-entries.patch  ];
+      });
+      libuv = prev.libuv.overrideAttrs (old: {
+        doCheck = false;
+      });
+      dbus = prev.dbus.overrideAttrs (old: {
+        doCheck = false;
+      });
+      python313 = prev.python313.override {
+        packageOverrides = self: super: {
+          execnet = super.execnet.overridePythonAttrs (old: {
+            doCheck = false;
+          });
+          pytest-xdist = super.pytest-xdist.overridePythonAttrs (old: {
+            doCheck = false;
+          });
+          requests = super.requests.overridePythonAttrs (old: {
+            doCheck = false;
+          });
+          sphinx = super.sphinx.overridePythonAttrs (old: {
+            doCheck = false;
+          });
+        };
+      };
+    }
+  );
+
+  # Use the patches from emacs-plus
+  emacs-plus = (patched-pkgs.emacs30-pgtk.overrideAttrs (old: {
+        patches =
+          (old.patches or [])
+          ++ [
+            (pkgs.fetchpatch {
+              url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-30/fix-window-role.patch";
+              sha256 = "0c41rgpi19vr9ai740g09lka3nkjk48ppqyqdnncjrkfgvm2710z";
+            })
+            (pkgs.fetchpatch {
+              url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-30/round-undecorated-frame.patch";
+              sha256 = "uYIxNTyfbprx5mCqMNFVrBcLeo+8e21qmBE3lpcnd+4=";
+            })
+            (pkgs.fetchpatch {
+              url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-30/system-appearance.patch";
+              sha256 = "3QLq91AQ6E921/W9nfDjdOUWR8YVsqBAT/W9c1woqAw=";
+            })
+          ];
+      })).override{ withNativeCompilation = true; };
+
+  emacs-plus-with-packages = (pkgs.emacsPackagesFor emacs-plus).emacsWithPackages (ps: [
+    ps.vterm
+    ps.multi-vterm
+  ]);
+
 in
 {
   imports = [ ./dev-common.nix ];
@@ -37,10 +94,7 @@ in
     coreutils
     curl
     diffutils
-    ((emacsPackagesFor emacs29-macport).emacsWithPackages (ps: [
-      ps.vterm
-      ps.multi-vterm
-    ]))
+    emacs-plus-with-packages
     findutils
     gh
     gh-dash
@@ -57,14 +111,21 @@ in
     pgcli
     pgformatter
     #pms
+    poetry
     postgresql
     podman
     #python310Packages.sqlparse
+    redis
     sqls
     #vimpc
     wget
   ];
 
+  nixpkgs.config.permittedInsecurePackages = [
+    "emacs-mac-macport-29.1"
+    "emacs-mac-macport-with-packages-29.1"
+  ];
+
   nix.settings = {
     sandbox = true;
     keep-outputs = true;
@@ -78,4 +139,6 @@ in
     })
   ];
 
+  # TODO is this a good idea?
+  #programs.zsh.shellAliases = { emacs = "${emacs-plus-with-packages}/Applications/Emacs.app/Contents/MacOS/Emacs"; };
 }
diff --git a/nix-conf/home/includes/linux-dev.nix b/nix-conf/home/includes/linux-dev.nix
index d680760..473118e 100644
--- a/nix-conf/home/includes/linux-dev.nix
+++ b/nix-conf/home/includes/linux-dev.nix
@@ -4,7 +4,6 @@
 
   programs.emacs = {
     enable = true;
-    package = pkgs.emacs29;
     extraPackages = (
       epkgs: [
         epkgs.vterm
diff --git a/nix-conf/home/includes/linux-server.nix b/nix-conf/home/includes/linux-server.nix
index 427b167..62233f0 100644
--- a/nix-conf/home/includes/linux-server.nix
+++ b/nix-conf/home/includes/linux-server.nix
@@ -7,7 +7,6 @@
     irssi
     libtree
     msmtp
-    neomutt
     pinentry
     restic
     sword
@@ -16,7 +15,7 @@
 
   services.gpg-agent = {
     enable = true;
-    pinentryPackage = pkgs.pinentry-curses;
+    pinentry.package = pkgs.pinentry-curses;
     defaultCacheTtl = 34560000;
     maxCacheTtl = 34560000;
   };
diff --git a/nix-conf/home/includes/secrets.yaml b/nix-conf/home/includes/secrets.yaml
index 8222439..2fc9d8c 100644
--- a/nix-conf/home/includes/secrets.yaml
+++ b/nix-conf/home/includes/secrets.yaml
@@ -1,14 +1,10 @@
 ssh_config:
     oci: ENC[AES256_GCM,data:l1GZ6mszgDhGztWmMdkNY2wRGfLIOGfHou7m0p8NkvaZZ3oKhblyu9C2Y2uEZArC8aCysxmU0QDfeIxDAzBdszUY,iv:HD8xdaiF9s0XZAuHNjAQfEtMgKaM0R12FCv5rTq19+Y=,tag:bfa48iOXhASXc+JhmYy/EQ==,type:str]
-    otm: ENC[AES256_GCM,data:fGChw7JlnWtnP4lVX1XXAH97gR0iWgBPuR2o7IgQ5wI8QlQCsrkY/GGa6pFanFsblYWGnwpiv8Cu7Bj7A+ShR1bjTeMdVRjLTe6fkAAj7jL5Np+C/xK12zUK,iv:X486VWdXg9KtuK4yDsq3+P+lY45+nxAwmEkI59olwwI=,tag:PVif5yh0M9dBLmsnGqYJYw==,type:str]
+    otm: ""
 git_email_config:
     default: ENC[AES256_GCM,data:ADmbGuV+E5wvGdbdC12BDi2TvHeoIRWjerKxnvDV7dENCxFyy+3P01IyCA==,iv:Nik4YiC8WhWmAnM7g1ER5HU0pg88l9uFiHQNtou5jas=,tag:RtK0XKKcHHR39p3mSl5YRw==,type:str]
     otm: ENC[AES256_GCM,data:dFrxmxFRU5MThUSdqWuL3ZmBCJfMUVYWQTnWQF25Cnn6lMflau5vHNEFZZDZxyFBk7A=,iv:EOv1xgxXuN3LuiO1eorazgQHBkWY9GKUjFBaYnfkLRI=,tag:Mg6SwdQSGjtlR5iiOU/q7g==,type:str]
 sops:
-    kms: []
-    gcp_kms: []
-    azure_kv: []
-    hc_vault: []
     age:
         - recipient: age1w7kjp0qdgfyg9cyj5w4qc4fc9qz3w65xw2veazesfgdenqrd3ucqsc5ejv
           enc: |
@@ -19,8 +15,7 @@ sops:
             cjlWWTNQR3lLLzBqTHhld05VblFJdHcKihceil9ge+IKG2GZcLpGWUncvRvmyJ7w
             YiWtb/ApF4T27wsmmFyLSnG8OWkLCKzaeU4QOVIGYQcfzzcQD5nUGg==
             -----END AGE ENCRYPTED FILE-----
-    lastmodified: "2024-08-29T14:36:21Z"
-    mac: ENC[AES256_GCM,data:AVaoEELI5iftC2eNI9pRoL/LWhwGVgCm/VfiVi67yYdG7HwyJwK60L1gAoLxvsvhIeZPXGq+CIt0iN2jjOSnNymh8b9zbpIs8h3PHelZs+yaKgpxRCKnIy6OKvUoRft16P1/VVq6ZMqA1qmOvXxtUOp/F5yZx7x7ix1aPoO2rpw=,iv:DTwuUqYCI98vNF5viz7r3DzZhjj9Xu5rFbabkmY5gK4=,tag:MQTIONNC29xeCOg0/C0jfw==,type:str]
-    pgp: []
+    lastmodified: "2025-04-29T13:45:42Z"
+    mac: ENC[AES256_GCM,data:Z4jJujUvl8jmJQbquV9NeczVZF17HI01sDpUoSSS7cM89WUOZzAOcT3zxR4hzyCfq4je++YkBPPFl4hcqbuVyBu8zCxY4z9673sFSLYrUA8THVeLYjMOTo0Hu0tIy8vy+uZZcAuRFaXyS+GrQHAdSSm4zVkwLG9R1nod+ys6LvQ=,iv:WfubcgFSY94cyfrlAlND6CQudoISuGL5fBhm9E3O4Q4=,tag:IeKYzou3EDwGyA23FGHtdA==,type:str]
     unencrypted_suffix: _unencrypted
-    version: 3.9.0
+    version: 3.10.2
diff --git a/nix-conf/home/includes/zsh.nix b/nix-conf/home/includes/zsh.nix
index 982675a..650f559 100644
--- a/nix-conf/home/includes/zsh.nix
+++ b/nix-conf/home/includes/zsh.nix
@@ -54,10 +54,13 @@ in
   programs.zsh = {
     enable = true;
     enableCompletion = true;
-    # TODO: put strategy here after 24.11 is released
     autosuggestion = {
       enable = true;
       highlight = "fg=#808080";
+      strategy = [
+        "history"
+        "completion"
+      ];
     };
     defaultKeymap = "emacs";
     history = {
@@ -85,6 +88,7 @@ in
       mv = "mv -iv";
       mkdir = "mkdir -v";
       cat = "bat -p";
+      c = "bat -p";
       l = "eza";
       la = "eza -a";
       lg = "eza -G";
@@ -92,6 +96,10 @@ in
       ll = "\\eza --icons --git --colour --long --group-directories-first --classify";
       lla = "ll -a";
       t = "eza --tree";
+      p = "lsd";
+      pa = "lsd -a";
+      pll = "lsd -l";
+      pla = "lsd -la";
 
       pp = ''pushbullet push "Pixel" link "''${1}" "''${1}"'';
 
@@ -135,198 +143,197 @@ in
     localVariables = {
       PER_DIRECTORY_HISTORY_TOGGLE = "^\\\\"; # ^\\ is ^#
       HISTORY_START_WITH_GLOBAL = true;
-
-      # TODO move to programs.zsh.autosuggestion.strategy when 24.11 is released
-      ZSH_AUTOSUGGEST_STRATEGY = [
-        "history"
-        "completion"
-      ];
-
       LESS = "-iRXF";
     };
-    initExtraFirst = ''
-      [[ $TERM == "tramp" ]] && unsetopt zle && PS1='$ ' && return
-    '';
-    initExtra = ''
-      # Based on prezto tmux plugin
-      if [[ -z "$TMUX" && -z "$EMACS" && -z "$VIM" && -z "$INSIDE_EMACS" && (-z "$SSH_TTY" || -n "$TMUX_AUTO_ATTACH") ]]; then
-        tmux start-server
+    initContent = lib.mkMerge [
+      (lib.mkBefore ''
+        [[ $TERM == "tramp" ]] && unsetopt zle && PS1='$ ' && return
+      '')
+      ''
+        # Based on prezto tmux plugin
+        if [[ -z "$TMUX" && -z "$EMACS" && -z "$VIM" && -z "$INSIDE_EMACS" && (-z "$SSH_TTY" || -n "$TMUX_AUTO_ATTACH") ]]; then
+          tmux start-server
+
+          if ! tmux has-session 2> /dev/null; then
+            tmux new-session -d -s "0" \; set-option -t "0" destroy-unattached off &> /dev/null
+          fi
 
-        if ! tmux has-session 2> /dev/null; then
-          tmux new-session -d -s "0" \; set-option -t "0" destroy-unattached off &> /dev/null
+          if [[ -n "$SSH_TTY" ]]; then
+            exec tmux -u attach-session
+          else
+            exec tmux -u attach-session -d
+          fi
         fi
 
-        if [[ -n "$SSH_TTY" ]]; then
-          exec tmux -u attach-session
-        else
-          exec tmux -u attach-session -d
-        fi
-      fi
-
-      autopair-init
-      enable-fzf-tab
-
-      # make home and end work
-      [[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
-      [[ -z "$terminfo[kend]" ]] || bindkey -M emacs "$terminfo[kend]" end-of-line
-
-      # disable sort when completing `git checkout`
-      zstyle ':completion:*:git-checkout:*' sort false
-      # set descriptions format to enable group support
-      zstyle ':completion:*:descriptions' format '[%d]'
-      # Allow tab to expand aliases
-      zstyle ':completion:*' completer _expand_alias _complete _ignored
-      # set list-colors to enable filename colorizing
-      #zstyle ':completion:*' list-colors ''${(s.:.)LS_COLORS}
-      # preview directory's content with eza when completing cd
-      zstyle ':fzf-tab:complete:cd:*' fzf-preview 'eza -1 --color=always $realpath'
-      # switch group using `,` and `.`
-      zstyle ':fzf-tab:*' switch-group ',' '.'
-
-      # functions modified from https://www.josean.com/posts/7-amazing-cli-tools
-      _fzf_compgen_path() {
-        fd --hidden --exclude .git --exclude node_modules . "$1"
-      }
-      _fzf_compgen_dir() {
-        fd --type=d --hidden --exclude .git --exclude node_modules . "$1"
-      }
-      _fzf_comprun() {
-        local command=$1
-        shift
-
-        case "$command" in
-          cd)           fzf --preview 'eza --tree --color=always {} | head -200' "$@" ;;
-          export|unset) fzf --preview "eval 'echo $'{}"         "$@" ;;
-          ssh)          fzf --preview 'dig {}'                   "$@" ;;
-          *)            fzf --preview "${show_file_or_dir_preview}" "$@" ;;
-        esac
-      }
-
-      set -o noclobber
-
-      # disable flow control (so that fzf-git.sh's ^g^s can work)
-      stty -ixon
-
-      # These functions are called as follows, after using ea (using vip as an example):
-      # vip  # edits the first result from ea (roughly equivalent to vi `ea p 1`)
-      # vip <n> # edits the nth result from ea (vi `ea p <n>`)
-      # vip <n> foo # if the nth result from ea is a directory, edit foo in that directory (vi `ea p <n>`/foo)
-      # Will add +<line-number>, where the line number is available
-      function _vip () {
-        local cmd=(''${=1}) # zsh only, not portable; something like CMD=($(echo $1)) is more portable but is ugly
-        local idx=''${2:-1}
-        local base_path=$(ea p $idx)
-        local line=$(ea p $idx "{line}")
-        local ea_format="'{path}'"
-
-        if [ -z "$base_path" ]; then
-          echo "No file path found for index $2"
-          return 1
-        fi
+        autopair-init
+        enable-fzf-tab
+
+        # make home and end work
+        [[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
+        [[ -z "$terminfo[kend]" ]] || bindkey -M emacs "$terminfo[kend]" end-of-line
+
+        # disable sort when completing `git checkout`
+        zstyle ':completion:*:git-checkout:*' sort false
+        # set descriptions format to enable group support
+        zstyle ':completion:*:descriptions' format '[%d]'
+        # Allow tab to expand aliases
+        zstyle ':completion:*' completer _expand_alias _complete _ignored
+        # set list-colors to enable filename colorizing
+        #zstyle ':completion:*' list-colors ''${(s.:.)LS_COLORS}
+        # preview directory's content with eza when completing cd
+        zstyle ':fzf-tab:complete:cd:*' fzf-preview 'eza -1 --color=always $realpath'
+        # switch group using `,` and `.`
+        zstyle ':fzf-tab:*' switch-group ',' '.'
+
+        # functions modified from https://www.josean.com/posts/7-amazing-cli-tools
+        _fzf_compgen_path() {
+          fd --hidden --exclude .git --exclude node_modules . "$1"
+        }
+        _fzf_compgen_dir() {
+          fd --type=d --hidden --exclude .git --exclude node_modules . "$1"
+        }
+        _fzf_comprun() {
+          local command=$1
+          shift
+
+          case "$command" in
+            cd)           fzf --preview 'eza --tree --color=always {} | head -200' "$@" ;;
+            export|unset) fzf --preview "eval 'echo $'{}"         "$@" ;;
+            ssh)          fzf --preview 'dig {}'                   "$@" ;;
+            *)            fzf --preview "${show_file_or_dir_preview}" "$@" ;;
+          esac
+        }
 
-        if [ $# -gt 2 -a ! -d "$base_path" ]; then
-          echo "$base_path is not a directory"
-          return 2
-        fi
+        set -o noclobber
+
+        # disable flow control (so that fzf-git.sh's ^g^s can work)
+        stty -ixon
+
+        # These functions are called as follows, after using ea (using vip as an example):
+        # vip  # edits the first result from ea (roughly equivalent to vi `ea p 1`)
+        # vip <n> # edits the nth result from ea (vi `ea p <n>`)
+        # vip <n> foo # if the nth result from ea is a directory, edit foo in that directory (vi `ea p <n>`/foo)
+        # Will add +<line-number>, where the line number is available
+        function _vip () {
+          local cmd=(''${=1}) # zsh only, not portable; something like CMD=($(echo $1)) is more portable but is ugly
+          local idx=''${2:-1}
+          local base_path=$(ea p $idx)
+          local line=$(ea p $idx "{line}")
+          local ea_format="'{path}'"
+
+          if [ -z "$base_path" ]; then
+            echo "No file path found for index $2"
+            return 1
+          fi
 
-        if [ $# -lt 3 -a $line -ne 1 ]; then
-          ea_format+=" +{line}"
-        fi
+          if [ $# -gt 2 -a ! -d "$base_path" ]; then
+            echo "$base_path is not a directory"
+            return 2
+          fi
 
-        eval $(ea p $idx "$cmd ''${ea_format}$3")
-      }
+          if [ $# -lt 3 -a $line -ne 1 ]; then
+            ea_format+=" +{line}"
+          fi
 
-      function vip () {
-        _vip $EDITOR ''${@}
-      }
-      function bp () {
-        _vip bat ''${@}
-      }
-      function bpp () {
-        # this will be split into an array in _vip
-        CMD="bat -p"
-        _vip $CMD ''${@}
-      }
+          eval $(ea p $idx "$cmd ''${ea_format}$3")
+        }
 
-      function generate () { gopass generate -s -p $1 $((RANDOM % 14 + 45)) }
-      function fcd { cd $(fd -L --max-depth=''${1:-4} --type=d 2>/dev/null | fzf-tmux) }
+        function vip () {
+          _vip $EDITOR ''${@}
+        }
+        function bp () {
+          _vip bat ''${@}
+        }
+        function bpp () {
+          # this will be split into an array in _vip
+          CMD="bat -p"
+          _vip $CMD ''${@}
+        }
 
-      fif() {
-        if [ ! "$#" -gt 0  ]; then
-          echo "usage: fif <SEARCH_TERM>"
-          return 1;
-        fi
-        rg --files-with-matches --no-messages "$1" | fzf $FZF_PREVIEW_WINDOW --preview "rg --ignore-case --pretty --context 10 '$1' {}"
-      }
+        function ecd () {
+          cd $(ea p ''${1:-1})
+        }
 
-      fe() {
-        IFS=$'\n' files=($(fzf-tmux --query="$1" --multi --select-1 --exit-0))
-        [[ -n "$files" ]] && ''${EDITOR:-vim} "''${files[@]}"
-      }
+        function generate () { gopass generate -s -p $1 $((RANDOM % 14 + 45)) }
+        function fcd { cd $(fd -L --max-depth=''${1:-4} --type=d 2>/dev/null | fzf-tmux) }
 
-      # TODO is there a way to do this in shellAliases
-      alias ..="cd .."
-      alias ...="cd ../.."
-      alias -- -="cd -"
-
-      .,() {
-        local declare dirs=()
-        get_parent_dirs() {
-          if [[ -d "''${1}" ]]; then dirs+=("$1"); else return; fi
-          if [[ "''${1}" == '/' ]]; then
-            for _dir in "''${dirs[@]}"; do echo $_dir; done
-          else
-            get_parent_dirs $(dirname "$1")
+        fif() {
+          if [ ! "$#" -gt 0  ]; then
+            echo "usage: fif <SEARCH_TERM>"
+            return 1;
           fi
+          rg --files-with-matches --no-messages "$1" | fzf $FZF_PREVIEW_WINDOW --preview "rg --ignore-case --pretty --context 10 '$1' {}"
         }
-        local DIR=$(get_parent_dirs $(realpath "$PWD/..") | fzf-tmux)
-        cd "$DIR"
-      }
 
-      # From omz
-      function mkcd () {
-        mkdir -p $@ && cd ''${@:$#}
-      }
+        fe() {
+          IFS=$'\n' files=($(fzf-tmux --query="$1" --multi --select-1 --exit-0))
+          [[ -n "$files" ]] && ''${EDITOR:-vim} "''${files[@]}"
+        }
 
-      tre () { command tre "$@" -e && source "/tmp/tre_aliases_$USER" 2>/dev/null; }
+        # TODO is there a way to do this in shellAliases
+        alias ..="cd .."
+        alias ...="cd ../.."
+        alias -- -="cd -"
+
+        .,() {
+          local declare dirs=()
+          get_parent_dirs() {
+            if [[ -d "''${1}" ]]; then dirs+=("$1"); else return; fi
+            if [[ "''${1}" == '/' ]]; then
+              for _dir in "''${dirs[@]}"; do echo $_dir; done
+            else
+              get_parent_dirs $(dirname "$1")
+            fi
+          }
+          local DIR=$(get_parent_dirs $(realpath "$PWD/..") | fzf-tmux)
+          cd "$DIR"
+        }
 
-      function gcd () {
-        if [ $# -eq 0 ] ; then
-          echo "Number of days must be specified" >&2
-          return 1
-        fi
-        if ! [[ $1 =~ '^[0-9]+$' ]] ; then
-          echo "Number of days must be a number" >&2
-          return 2
-        fi
+        # From omz
+        function mkcd () {
+          mkdir -p $@ && cd ''${@:$#}
+        }
 
-        if [ $1 -eq 0 ] ; then
-         GC_ARGS=(-d)
-        else
-          GC_ARGS=(--delete-older-than ''${1}d)
-        fi
+        tre () { command tre "$@" -e && source "/tmp/tre_aliases_$USER" 2>/dev/null; }
 
-        DOAS=$(command -v doas)
+        function gcd () {
+          if [ $# -eq 0 ] ; then
+            echo "Number of days must be specified" >&2
+            return 1
+          fi
+          if ! [[ $1 =~ '^[0-9]+$' ]] ; then
+            echo "Number of days must be a number" >&2
+            return 2
+          fi
 
-        # Run as the current user (as well as root) to clean up hm generations
-        nix-collect-garbage ''${GC_ARGS[@]}
-        if [ -n $DOAS ] ; then
-          $DOAS nix-collect-garbage ''${GC_ARGS[@]}
-        fi
+          if [ $1 -eq 0 ] ; then
+           GC_ARGS=(-d)
+          else
+            GC_ARGS=(--delete-older-than ''${1}d)
+          fi
 
-        df -h
-        date
-      }
+          DOAS=$(command -v doas)
 
-      function checkout-pr () {
-        git fetch ''${2:-upstream} pull/''${1}/head:pr-''${1}
-        git switch pr-''${1}
-      }
+          # Run as the current user (as well as root) to clean up hm generations
+          nix-collect-garbage ''${GC_ARGS[@]}
+          if [ -n $DOAS ] ; then
+            $DOAS nix-collect-garbage ''${GC_ARGS[@]}
+          fi
 
-      [[ ! -f ~/.zsh.local ]] || source ~/.zsh.local
+          df -h
+          date
+        }
 
-      [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
-    '';
+        function checkout-pr () {
+          git fetch ''${2:-upstream} pull/''${1}/head:pr-''${1}
+          git switch pr-''${1}
+        }
+
+        [[ ! -f ~/.zsh.local ]] || source ~/.zsh.local
+
+        [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
+      ''
+    ];
 
     plugins = with pkgs; [
       {
diff --git a/nix-conf/home/otm.nix b/nix-conf/home/otm.nix
index e7e152f..2055780 100644
--- a/nix-conf/home/otm.nix
+++ b/nix-conf/home/otm.nix
@@ -115,9 +115,6 @@ let
   zscaler-lein = pkgs.leiningen.override { jdk = zscaler-jdk; };
   zscaler-clojure = pkgs.clojure.override { jdk = zscaler-jdk; };
 
-  toggle = pkgs.writeShellScriptBin "remote-toggle" ''
-    ssh -nT pi "playerctl play-pause" 2>/dev/null
-  '';
 in
 {
   imports = [ ./includes/darwin.nix ];
@@ -148,14 +145,14 @@ in
     notify_success = ''( osascript -e 'display notification "The command finished" with title "Success"' && afplay /System/Library/Sounds/Ping.aiff && say done  )'';
     notify_failure = ''( osascript -e 'display notification "The command failed" with title "Failure"' && afplay /System/Library/Sounds/Sosumi.aiff && say failed  )'';
     notify = "notify_success || notify_failure";
+    ltn = "lein test && notify";
+    yb = "aws codeartifact login --tool npm --repository otm-js --domain otm --domain-owner 103567893073 --region eu-west-1 --profile aws_otm_dev_developers && yarn && yarn build && notify";
     auth = "auth2aws login -r aws_otm_dev_developers,aws_otm_prd_developers && osascript -e 'tell app \"iTerm\" to activate'";
-    yarn_build = "aws codeartifact login --tool npm --repository otm-js --domain otm --domain-owner 103567893073 --region eu-west-1 --profile aws_otm_dev_developers && yarn && yarn build && notify";
   };
 
   home.packages = with pkgs; [
     zscaler-clojure
     zscaler-lein
-    toggle
   ];
 
   home.file = {
@@ -164,8 +161,8 @@ in
     "certs/full-cert.pem".source = full-cert-file;
     "certs/internal-ca.pem".text = internal-cert;
     "certs/staging-internal-ca.pem".text = internal-staging-cert;
-
-    ".skhdrc".text = "play : remote-toggle";
+    ".docker/certs.d/zcaler-cert.pem".source = zscaler-cert-file;
+    ".wgetrc".text = "ca_certificate=${full-cert-file}";
   };
 
   sops.secrets = {
diff --git a/nix-conf/machines/djmuk1/configuration.nix b/nix-conf/machines/djmuk1/configuration.nix
index be45319..7405e9a 100644
--- a/nix-conf/machines/djmuk1/configuration.nix
+++ b/nix-conf/machines/djmuk1/configuration.nix
@@ -29,11 +29,7 @@
   services.sshguard.enable = true;
   services.oidentd.enable = true;
 
-  services.locate = {
-    enable = true;
-    package = pkgs.plocate;
-    localuser = null;
-  };
+  services.locate.enable = true;
 
   users.users.djm = {
     isNormalUser = true;
@@ -66,11 +62,13 @@
 
   programs.zsh.enable = true;
 
-  programs.vim.defaultEditor = true;
+  programs.vim = {
+    enable = true;
+    defaultEditor = true;
+  };
 
   environment.systemPackages = with pkgs; [
     #procmail
-    vim
     wget
   ];
 
diff --git a/nix-conf/machines/djmuk2/configuration.nix b/nix-conf/machines/djmuk2/configuration.nix
index a84ddf8..0b31a01 100644
--- a/nix-conf/machines/djmuk2/configuration.nix
+++ b/nix-conf/machines/djmuk2/configuration.nix
@@ -30,11 +30,7 @@
   services.sshguard.enable = true;
   services.oidentd.enable = true;
 
-  services.locate = {
-    enable = true;
-    package = pkgs.plocate;
-    localuser = null;
-  };
+  services.locate.enable = true;
 
   # Emulate nix-sops. Technically an anti-pattern, but this isn't a real secret, and this has to be embedded here, as we cannot set a file path to read it from.
   # Populate/update with:
@@ -74,12 +70,14 @@
 
   programs.zsh.enable = true;
 
-  programs.vim.defaultEditor = true;
+  programs.vim = {
+    enable = true;
+    defaultEditor = true;
+  };
 
   environment.systemPackages = with pkgs; [
     #procmail
     git
-    vim
     wget
   ];
 
diff --git a/nix-conf/machines/edrahil/configuration.nix b/nix-conf/machines/edrahil/configuration.nix
index 2054253..a1bc8e3 100644
--- a/nix-conf/machines/edrahil/configuration.nix
+++ b/nix-conf/machines/edrahil/configuration.nix
@@ -49,11 +49,7 @@
   services.sshguard.enable = true;
   services.oidentd.enable = true;
 
-  services.locate = {
-    enable = true;
-    package = pkgs.plocate;
-    localuser = null;
-  };
+  services.locate.enable = true;
 
   services.restic = {
     backups = {
@@ -177,7 +173,10 @@
 
   programs.zsh.enable = true;
 
-  programs.vim.defaultEditor = true;
+  programs.vim = {
+    enable = true;
+    defaultEditor = true;
+  };
 
   environment.etc = {
     "restic-environment" = {
diff --git a/nix-conf/machines/egalmoth/configuration.nix b/nix-conf/machines/egalmoth/configuration.nix
index 21b7d23..e47cd45 100644
--- a/nix-conf/machines/egalmoth/configuration.nix
+++ b/nix-conf/machines/egalmoth/configuration.nix
@@ -4,7 +4,9 @@
   lib,
   ...
 }:
-
+let
+  unstable = import <unstable> { };
+in
 {
   imports = [ ./hardware-configuration.nix ];
 
@@ -52,8 +54,7 @@
     };
   };
 
-  hardware.opengl.enable = true;
-  hardware.opengl.driSupport = true;
+  hardware.graphics.enable = true;
 
   networking.hostName = "egalmoth"; # Define your hostname.
   networking.networkmanager.enable = true;
@@ -158,11 +159,7 @@
     ];
   };
 
-  services.locate = {
-    enable = true;
-    package = pkgs.plocate;
-    localuser = null;
-  };
+  services.locate.enable = true;
 
   environment.systemPackages = with pkgs; [
     acpi
@@ -181,7 +178,8 @@
     rofi
     st
     sway
-    vim
+    vdhcoapp
+    ungoogled-chromium
     wayland
     wayst
     wezterm
@@ -206,6 +204,7 @@
     iosevka-bin
     jetbrains-mono
     meslo-lgs-nf
+    unstable.aporetic
   ];
 
   programs.zsh.enable = true;
@@ -220,7 +219,10 @@
     enableSSHSupport = true;
   };
 
-  programs.vim.defaultEditor = true;
+  programs.vim = {
+    enable = true;
+    defaultEditor = true;
+  };
 
   services.openssh.enable = true;