From 9012a765a856284702085fea454b7cbf22854c99 Mon Sep 17 00:00:00 2001 From: Ray Andrew Date: Sat, 27 Dec 2025 00:08:51 -0600 Subject: [PATCH] chore(emacs): refactor emacs config --- config/emacs/.gitignore | 1 + config/emacs/early-init.el | 159 ++++ config/emacs/init.el | 1087 ++++++++++++++++++++++++++++ config/emacs/lib/naysayer-theme.el | 14 +- home/emacs.nix | 15 +- 5 files changed, 1263 insertions(+), 13 deletions(-) create mode 100644 config/emacs/early-init.el create mode 100644 config/emacs/init.el diff --git a/config/emacs/.gitignore b/config/emacs/.gitignore index b650c16..d0f655f 100644 --- a/config/emacs/.gitignore +++ b/config/emacs/.gitignore @@ -1,2 +1,3 @@ var undo +elpa diff --git a/config/emacs/early-init.el b/config/emacs/early-init.el new file mode 100644 index 0000000..1c589d6 --- /dev/null +++ b/config/emacs/early-init.el @@ -0,0 +1,159 @@ +;;; early-init.el --- Early Init -*- lexical-binding: t; -*- + +;;; Startup time +(defvar rs/show-startup-time t + "If non-nil, display startup time after Emacs loads.") + +(defun rs/display-startup-time () + "Display startup time in milliseconds and seconds." + (when rs/show-startup-time + (let* ((time (float-time (time-subtract after-init-time before-init-time))) + (ms (* time 1000))) + (message "Emacs loaded in %.0fms (%.2fs) with %d garbage collections." + ms time gcs-done)))) + +(add-hook 'emacs-startup-hook #'rs/display-startup-time 110) + +;;; GC optimization +(defvar rs/backup-gc-cons-threshold gc-cons-threshold) +(defvar rs/backup-gc-cons-percentage gc-cons-percentage) +(setq gc-cons-threshold most-positive-fixnum) +(setq gc-cons-percentage 1.0) + +;;; Directories +(defvar rs/emacs-dir user-emacs-directory) +(defvar rs/lib-dir (expand-file-name "lib/" rs/emacs-dir)) +(defvar rs/var-dir (expand-file-name "var/" rs/emacs-dir)) + +(setq package-user-dir (expand-file-name "elpa/" rs/var-dir)) +(setq user-emacs-directory rs/var-dir) +(setq custom-file null-device) +(setq custom-theme-directory (expand-file-name "themes/" rs/emacs-dir)) + +;;; Restore GC after startup +(add-hook 'emacs-startup-hook + (lambda () + (setq gc-cons-threshold (* 64 1024 1024)) + (setq gc-cons-percentage 0.1)) 105) + +;;; Native compilation +(when (and (featurep 'native-compile) + (fboundp 'native-comp-available-p) + (native-comp-available-p)) + (setq package-native-compile t) + (setq native-comp-async-report-warnings-errors 'silent) + (setq native-compile-prune-cache t) + (startup-redirect-eln-cache (expand-file-name "eln-cache/" rs/var-dir))) + +(setq native-comp-warning-on-missing-source nil) +(setq jka-compr-verbose nil) +(setq byte-compile-warnings nil) +(setq byte-compile-verbose nil) + +;;; GCC paths for macOS +(when-let* ((gcc-base "/opt/homebrew/opt/gcc/lib/gcc/current") + ((file-directory-p gcc-base))) + (setenv "LIBRARY_PATH" + (string-join + (delq nil + (list gcc-base + (let ((jit-path "/opt/homebrew/opt/libgccjit/lib/gcc/current")) + (when (file-directory-p jit-path) jit-path)) + (car (last (file-expand-wildcards + (concat gcc-base "/gcc/aarch64-apple-darwin*/*")))))) + ":"))) + +;;; Misc performance +(setq load-prefer-newer t) +(setq read-process-output-max (* 2 1024 1024)) +(setq process-adaptive-read-buffering nil) +(setq ffap-machine-p-known 'reject) +(setq ad-redefinition-action 'accept) +(setq warning-suppress-types '((lexical-binding))) +(setq inhibit-compacting-font-caches t) + +(when (boundp 'pgtk-wait-for-event-timeout) + (setq pgtk-wait-for-event-timeout 0.001)) + +;;; File name handler optimization +(defvar rs/old-file-name-handler-alist (default-toplevel-value 'file-name-handler-alist)) + +(defun rs/restore-file-name-handler-alist () + (set-default-toplevel-value + 'file-name-handler-alist + (delete-dups (append file-name-handler-alist rs/old-file-name-handler-alist)))) + +(unless (daemonp) + (set-default-toplevel-value + 'file-name-handler-alist + (if (locate-file-internal "calc-loaddefs.el" load-path) + nil + (list (rassq 'jka-compr-handler rs/old-file-name-handler-alist)))) + (put 'file-name-handler-alist 'initial-value rs/old-file-name-handler-alist) + (add-hook 'emacs-startup-hook #'rs/restore-file-name-handler-alist 101)) + +;;; UI - disable before frame creation +(setq default-frame-alist '((background-color . "#072626") + (ns-appearance . dark) + (ns-transparent-titlebar . t) + (menu-bar-lines . 0) + (tool-bar-lines . 0) + (vertical-scroll-bars . nil) + (horizontal-scroll-bars . nil) + (frame-resize-pixelwise . t))) + +(setq frame-resize-pixelwise t) +(setq frame-inhibit-implied-resize t) +(setq auto-mode-case-fold nil) + +(setq inhibit-splash-screen t) +(setq inhibit-startup-screen t) +(setq inhibit-startup-echo-area-message user-login-name) +(setq inhibit-startup-buffer-menu t) +(setq inhibit-x-resources t) +(setq initial-buffer-choice nil) +(setq initial-scratch-message nil) +(setq initial-major-mode 'fundamental-mode) + +(setq menu-bar-mode nil) +(setq tool-bar-mode nil) +(setq scroll-bar-mode nil) + +(setq frame-title-format "%b – Emacs") +(setq icon-title-format frame-title-format) + +;; Bidirectional text optimization +(setq-default bidi-display-reordering 'left-to-right) +(setq-default bidi-paragraph-direction 'left-to-right) +(setq bidi-inhibit-bpa t) + +;; Suppress startup messages +(advice-add 'display-startup-echo-area-message :override #'ignore) +(advice-add 'display-startup-screen :override #'ignore) + +;; Unset irrelevant command line options +(unless (eq system-type 'darwin) + (setq command-line-ns-option-alist nil)) +(unless (memq initial-window-system '(x pgtk)) + (setq command-line-x-option-alist nil)) + +;;; Security +(setq gnutls-verify-error t) +(setq tls-checktrust t) +(setq gnutls-min-prime-bits 3072) + +;;; Package archives +(setq package-enable-at-startup nil) +(setq use-package-always-ensure t) +(setq use-package-enable-imenu-support t) +(setq use-package-expand-minimally t) +(setq package-archives '(("melpa" . "https://melpa.org/packages/") + ("gnu" . "https://elpa.gnu.org/packages/") + ("nongnu" . "https://elpa.nongnu.org/nongnu/") + ("melpa-stable" . "https://stable.melpa.org/packages/"))) +(setq package-archive-priorities '(("gnu" . 99) + ("nongnu" . 80) + ("melpa" . 70) + ("melpa-stable" . 50))) + +;;; early-init.el ends here diff --git a/config/emacs/init.el b/config/emacs/init.el new file mode 100644 index 0000000..d30f18a --- /dev/null +++ b/config/emacs/init.el @@ -0,0 +1,1087 @@ +;;; init.el --- Init -*- lexical-binding: t; -*- + +;;; Constants +(defconst rs/notes-dir "~/NPersonal/" + "Directory for notes, org files, and denote.") +(defconst rs/mail-dir "~/mail" + "Directory for mail.") +(defconst rs/full-name "Ray Andrew" + "Full name for email and git.") +(defconst rs/email-uchicago "rayandrew@uchicago.edu" + "UChicago email address.") +(defconst rs/email-personal "raydreww@gmail.com" + "Personal email address.") +(defconst rs/mu-binary "/etc/profiles/per-user/rayandrew/bin/mu" + "Path to mu binary (Nix).") +(defconst rs/mbsync-command "~/dotfiles/bin/path-shim mbsync -a" + "Command to sync mail.") + +;;; Elpaca bootstrap +(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 :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) + (load "./elpaca-autoloads"))) +(add-hook 'after-init-hook #'elpaca-process-queues) +(elpaca `(,@elpaca-order)) + +(elpaca elpaca-use-package + (elpaca-use-package-mode)) + +;; Block until elpaca is ready +; (elpaca-wait) + +;;; Font +(defun rs/get-default-font () + (cond + ((eq system-type 'windows-nt) "Consolas-11") + ((eq system-type 'gnu/linux) "Consolas-11") + ((eq system-type 'darwin) "Consolas-12"))) + +(set-face-font 'default (rs/get-default-font)) + +;;; Basic settings from minimal-emacs +(setq native-comp-async-query-on-exit t) +(setq read-answer-short t) +(setq use-short-answers t) + +;; Undo limits +(setq undo-limit (* 13 160000) + undo-strong-limit (* 13 240000) + undo-outer-limit (* 13 24000000)) + +;; Minibuffer +(setq enable-recursive-minibuffers t) +(setq minibuffer-prompt-properties + '(read-only t intangible t cursor-intangible t face minibuffer-prompt)) +(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) + +;; UI updates +(setq which-func-update-delay 1.0) +(setq idle-update-delay 1.0) +(defalias #'view-hello-file #'ignore) +(setq visible-bell nil) +(setq ring-bell-function #'ignore) + +;; Show-paren +(setq show-paren-delay 0.1 + show-paren-highlight-openparen t + show-paren-when-point-inside-paren t + show-paren-when-point-in-periphery t) + +;; Misc +(setq custom-buffer-done-kill t) +(setq whitespace-line-column nil) +(setq-default display-line-numbers-width 3) +(setq-default display-line-numbers-widen t) +(setq truncate-string-ellipsis "…") +(setq eval-expression-print-length nil + eval-expression-print-level nil) +(setq x-underline-at-descent-line t) +(setq remote-file-name-inhibit-cache 50) +(setq imenu-auto-rescan t) +(setq imenu-max-item-length 160) +(setq next-line-add-newlines nil) +(setq bookmark-save-flag 1) + +;; Tramp +(setq tramp-verbose 1) +(setq tramp-completion-reread-directory-timeout 50) + +;; Files +(setq delete-by-moving-to-trash (not noninteractive)) +(setq remote-file-name-inhibit-delete-by-moving-to-trash t) +(setq find-file-suppress-same-file-warnings t) +(setq find-file-visit-truename t + vc-follow-symlinks t) +(setq split-width-threshold 170 + split-height-threshold nil) + +;; Buffers +(setq uniquify-buffer-name-style 'forward) + +;; Comint +(setq ansi-color-for-comint-mode t + comint-prompt-read-only t + comint-buffer-maximum-size 4096) + +;; Compilation +(setq compilation-ask-about-save nil + compilation-always-kill t + compilation-scroll-output 'first-error) +(setq confirm-nonexistent-file-or-buffer nil) + +;; Backup files +(setq create-lockfiles nil) +(setq make-backup-files nil) +(setq backup-directory-alist + `(("." . ,(expand-file-name "backup" user-emacs-directory)))) +(setq tramp-backup-directory-alist backup-directory-alist) +(setq backup-by-copying-when-linked t) +(setq backup-by-copying t) +(setq delete-old-versions t) +(setq version-control t) +(setq kept-new-versions 5) +(setq kept-old-versions 5) + +;; VC +(setq vc-git-print-log-follow t) +(setq vc-make-backup-files nil) +(setq vc-git-diff-switches '("--histogram")) + +;; Auto save +(setq auto-save-default nil) +(setq auto-save-no-message t) +(setq auto-save-include-big-deletions t) +(setq auto-save-list-file-prefix + (expand-file-name "autosave/" user-emacs-directory)) +(setq tramp-auto-save-directory + (expand-file-name "tramp-autosave/" user-emacs-directory)) +(setq kill-buffer-delete-auto-save-files t) +(setq kill-do-not-save-duplicates t) + +;; Auto revert +(setq revert-without-query (list ".") + auto-revert-stop-on-user-input nil + auto-revert-verbose t) +(setq global-auto-revert-non-file-buffers t) +(setq global-auto-revert-ignore-modes '(Buffer-menu-mode)) + +;; Recentf +(setq recentf-max-saved-items 300) +(setq recentf-max-menu-items 15) +(setq recentf-auto-cleanup 'mode) +(setq recentf-exclude nil) + +;; Saveplace +(setq save-place-file (expand-file-name "saveplace" user-emacs-directory)) +(setq save-place-limit 600) + +;; Savehist +(setq history-length 300) +(setq savehist-save-minibuffer-history t) +(setq savehist-additional-variables + '(kill-ring register-alist mark-ring global-mark-ring search-ring regexp-search-ring)) + +;; Frames and windows +(setq window-resize-pixelwise nil) +(setq resize-mini-windows 'grow-only) +(setq window-divider-default-bottom-width 1 + window-divider-default-places t + window-divider-default-right-width 1) + +;; Fontification +(setq redisplay-skip-fontification-on-input t) + +;; Scrolling +(setq fast-but-imprecise-scrolling t) +(setq scroll-error-top-bottom t) +(setq scroll-preserve-screen-position t) +(setq scroll-conservatively 20) +(setq auto-window-vscroll nil) +(setq scroll-margin 0) +(setq next-screen-context-lines 0) +(setq hscroll-margin 2 + hscroll-step 1) + +;; Mouse +(setq mouse-yank-at-point nil) + +;; Cursor +(setq blink-matching-paren nil) +(setq x-stretch-cursor nil) +(setq-default cursor-in-non-selected-windows nil) +(setq highlight-nonselected-windows nil) + +;; Text editing +(setq global-text-scale-adjust-resizes-frames nil) +(setq delete-pair-blink-delay 0.03) +(setq-default left-fringe-width 8) +(setq-default right-fringe-width 8) +(setq-default indicate-buffer-boundaries nil) +(setq-default indicate-empty-lines nil) +(setq-default word-wrap t) +(setq-default truncate-lines t) +(setq truncate-partial-width-windows nil) +(setq-default electric-indent-chars '(?\n ?\^?)) +(setq-default indent-tabs-mode nil + tab-width 4) +(setq tab-always-indent 'complete) +(setq tab-first-completion 'word-or-paren-or-punct) +(setq read-extended-command-predicate #'command-completion-default-include-p) +(setq comment-multi-line t) +(setq comment-empty-lines t) +(setq-default fill-column 80) +(setq sentence-end-double-space nil) +(setq require-final-newline t) +(setq lazy-highlight-initial-delay 0) + +;; Modeline +(setq display-time-default-load-average nil) + +;; Filetype +(setq python-indent-guess-indent-offset-verbose nil) +(setq sh-indent-after-continuation 'always) + +;; Dired and ls-lisp +(setq dired-free-space nil + dired-dwim-target t + dired-deletion-confirmer 'y-or-n-p + dired-filter-verbose nil + dired-recursive-deletes 'top + dired-recursive-copies 'always + dired-vc-rename-file t + dired-create-destination-dirs 'ask + dired-clean-confirm-killing-deleted-buffers nil) +(setq auto-revert-remote-files nil) +(setq dired-auto-revert-buffer 'dired-buffer-stale-p) +(setq dired-omit-verbose nil) +(setq ls-lisp-verbosity nil) +(setq ls-lisp-dirs-first t) + +;; Ediff +(setq ediff-window-setup-function 'ediff-setup-windows-plain + ediff-split-window-function 'split-window-horizontally) + +;; Help +(setq apropos-do-all t) +(setq help-enable-completion-autoload nil) +(setq help-enable-autoload nil) +(setq help-enable-symbol-autoload nil) +(setq help-window-select t) + +;; Eglot +(setq eglot-sync-connect 0) +(setq eglot-autoshutdown t) +(setq eglot-extend-to-xref t) +(setq jsonrpc-event-hook nil) +(setq eglot-events-buffer-size 0) +(setq eglot-events-buffer-config '(:size 0 :format short)) +(setq eglot-report-progress nil) + +;; Flymake +(setq flymake-show-diagnostics-at-end-of-line nil) +(setq flymake-wrap-around nil) + +;; hl-line-mode +(setq hl-line-sticky-flag nil) +(setq global-hl-line-sticky-flag nil) + +;; icomplete +(setq icomplete-compute-delay 0.01) + +;; flyspell +(setq flyspell-issue-welcome-flag nil) +(setq flyspell-issue-message-flag nil) + +;; ispell +(setq text-mode-ispell-word-completion nil) +(setq ispell-silently-savep t) + +;; ibuffer +(setq ibuffer-formats + '((mark modified read-only locked + " " (name 55 55 :left :elide) + " " (size 8 -1 :right) + " " (mode 18 18 :left :elide) " " filename-and-process) + (mark " " (name 16 -1) " " filename))) + +;; xref +(setq xref-show-definitions-function 'xref-show-definitions-completing-read + xref-show-xrefs-function 'xref-show-definitions-completing-read) + +;; abbrev +(setq abbrev-file-name (expand-file-name "abbrev_defs" user-emacs-directory)) +(setq save-abbrevs 'silently) + +;; dabbrev +(setq dabbrev-upcase-means-case-search t) +(setq dabbrev-ignored-buffer-modes + '(archive-mode image-mode docview-mode tags-table-mode pdf-view-mode)) +(setq dabbrev-ignored-buffer-regexps + '("\\` " "\\(?:\\(?:[EG]?\\|GR\\)TAGS\\|e?tags\\|GPATH\\)\\(<[0-9]+>\\)?")) + +;; Remove warnings from disabled commands +(dolist (cmd '(list-timers narrow-to-region upcase-region downcase-region + list-threads erase-buffer scroll-left + dired-find-alternate-file set-goal-column)) + (put cmd 'disabled nil)) + +;;; Hooks for built-in modes +(add-hook 'elpaca-after-init-hook #'global-auto-revert-mode) +(add-hook 'elpaca-after-init-hook #'(lambda () + (let ((inhibit-message t)) + (recentf-mode 1)))) +(add-hook 'kill-emacs-hook #'recentf-cleanup) +(add-hook 'elpaca-after-init-hook #'savehist-mode) +(add-hook 'elpaca-after-init-hook #'save-place-mode) + +(setq auth-sources '("~/.authinfo")) + +;;; Emacs settings +(use-package emacs + :ensure nil + :custom + (delete-selection-mode t) + (electric-indent-mode nil) + (electric-pair-mode t) + (blink-cursor-mode nil) + (global-auto-revert-mode t) + (indent-tabs-mode nil) + (editorconfig-mode t) + (recentf-mode t) + (recentf-max-saved-items 50) + (global-display-line-numbers-mode t) + (split-width-threshold nil) + :bind (([escape] . keyboard-escape-quit) + ("C-x c" . compile))) + +;;; Theme +(use-package naysayer-theme + :ensure nil + :config + (load-theme 'naysayer t) + :load-path rs/lib-dir) + +(set-face-foreground 'font-lock-builtin-face "lightgreen") + +;;; Completion +(use-package vertico + :ensure t + :defer t + :commands (vertico-mode vertico-multiform-mode) + :custom + (vertico-cycle t) + (vertico-multiform-commands + '((consult-imenu buffer indexed) + (find-file flat (vertico-cycle . t)) + (execute-extended-command flat (vertico-cycle . t)))) + (vertico-multiform-categories + '((consult-grep buffer))) + :hook + (elpaca-after-init . vertico-mode) + (elpaca-after-init . vertico-multiform-mode)) + +(use-package orderless + :ensure t + :custom + (completion-styles '(orderless basic)) + (completion-category-defaults nil) + (completion-category-overrides '((file (styles partial-completion))))) + +(use-package marginalia + :ensure t + :defer t + :commands (marginalia-mode marginalia-cycle) + :hook (elpaca-after-init . marginalia-mode)) + +(use-package embark + :ensure t + :defer t + :commands (embark-act + embark-dwim + embark-export + embark-collect + embark-bindings + embark-prefix-help-command) + :bind + (("C-." . embark-act) + ("C-;" . embark-dwim) + ("C-h B" . embark-bindings)) + :init + (setq prefix-help-command #'embark-prefix-help-command) + :config + (add-to-list 'display-buffer-alist + '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" + nil + (window-parameters (mode-line-format . none))))) + +(use-package embark-consult + :ensure t + :hook + (embark-collect-mode . consult-preview-at-point-mode)) + +(use-package consult + :ensure t + :bind (("C-c M-x" . consult-mode-command) + ("C-c h" . consult-history) + ("C-c k" . consult-kmacro) + ("C-c m" . consult-man) + ("C-c i" . consult-info) + ([remap Info-search] . consult-info) + ("C-x M-:" . consult-complex-command) + ("C-x b" . consult-buffer) + ("C-x 4 b" . consult-buffer-other-window) + ("C-x 5 b" . consult-buffer-other-frame) + ("C-x t b" . consult-buffer-other-tab) + ("C-x r b" . consult-bookmark) + ("C-x p b" . consult-project-buffer) + ("M-#" . consult-register-load) + ("M-'" . consult-register-store) + ("C-M-#" . consult-register) + ("M-y" . consult-yank-pop) + ("M-g e" . consult-compile-error) + ("M-g f" . consult-flymake) + ("M-g g" . consult-goto-line) + ("M-g M-g" . consult-goto-line) + ("M-g o" . consult-outline) + ("M-g m" . consult-mark) + ("M-g k" . consult-global-mark) + ("M-g i" . consult-imenu) + ("M-g I" . consult-imenu-multi) + ("M-s d" . consult-find) + ("M-s c" . consult-locate) + ("M-s g" . consult-grep) + ("M-s G" . consult-git-grep) + ("M-s r" . consult-ripgrep) + ("M-s l" . consult-line) + ("M-s L" . consult-line-multi) + ("M-s k" . consult-keep-lines) + ("M-s u" . consult-focus-lines) + ("M-s e" . consult-isearch-history) + :map isearch-mode-map + ("M-e" . consult-isearch-history) + ("M-s e" . consult-isearch-history) + ("M-s l" . consult-line) + ("M-s L" . consult-line-multi) + :map minibuffer-local-map + ("M-s" . consult-history) + ("M-r" . consult-history)) + :hook (completion-list-mode . consult-preview-at-point-mode) + :init + (setq register-preview-delay 0.5 + register-preview-function #'consult-register-format) + (advice-add #'register-preview :override #'consult-register-window) + (setq xref-show-xrefs-function #'consult-xref + xref-show-definitions-function #'consult-xref) + :config + (consult-customize + consult-theme :preview-key '(:debounce 0.2 any) + consult-ripgrep consult-git-grep consult-grep + consult-bookmark consult-recent-file consult-xref + consult--source-bookmark consult--source-file-register + consult--source-recent-file consult--source-project-recent-file + :preview-key '(:debounce 0.4 any)) + (setq consult-narrow-key "<")) + +;;; Outline Indent +(use-package outline-indent + :ensure t + :defer t + :commands outline-indent-minor-mode + :init + (add-hook 'python-mode-hook #'outline-indent-minor-mode) + (add-hook 'python-ts-mode-hook #'outline-indent-minor-mode) + (add-hook 'yaml-mode-hook #'outline-indent-minor-mode) + (add-hook 'yaml-ts-mode-hook #'outline-indent-minor-mode) + :custom + (outline-indent-ellipsis " ▼ ")) + +;;; Dired +(defun rs/dired-copy-path-at-point () + (interactive) + (dired-copy-filename-as-kill 0)) + +(use-package dired + :ensure nil + :bind (("C-x -" . dired-jump) + ("C-x e" . dired-jump) + (:map dired-mode-map + ("-" . dired-up-directory) + ("W" . rs/dired-copy-path-at-point))) + :custom + (dired-deletion-confirmer #'y-or-n-p) + (dired-dwim-target t) + (dired-listing-switches "-AlhcF") + (dired-auto-revert-buffer t)) + +(use-package dired-x + :after dired + :ensure nil) + +(add-hook 'dired-mode-hook #'dired-hide-details-mode) + +(setq dired-omit-files (concat "\\`[.]\\'" + "\\|\\(?:\\.js\\)?\\.meta\\'" + "\\|\\.\\(?:elc|a\\|o\\|pyc\\|pyo\\|swp\\|class\\)\\'" + "\\|^\\.DS_Store\\'" + "\\|^\\.\\(?:svn\\|git\\)\\'" + "\\|^\\.ccls-cache\\'" + "\\|^__pycache__\\'" + "\\|^\\.project\\(?:ile\\)?\\'" + "\\|^flycheck_.*" + "\\|^flymake_.*")) +(add-hook 'dired-mode-hook #'dired-omit-mode) + +;;; Undo Tree +(use-package undo-tree + :ensure t + :defer t + :diminish + :bind (("C-M-u" . undo-tree-visualize) + ("M-_" . undo-tree-redo) + ("M--" . go-back-to-last-edit) + :map undo-tree-map + (("C-x u" . nil))) + :custom + (undo-tree-visualizer-diff t) + (undo-tree-enable-undo-in-region t) + (undo-tree-history-directory-alist `((".*" . ,(expand-file-name "undo" rs/emacs-dir)))) + :config + (defun go-back-to-last-edit () + "Jump back to the last change in the current buffer." + (interactive) + (ignore-errors + (let ((inhibit-message t)) + (undo-tree-undo) + (undo-tree-redo)))) + + (defun undo-tree-split-side-by-side (original-function &rest args) + "Split undo-tree side-by-side" + (let ((split-height-threshold nil) + (split-width-threshold 0)) + (apply original-function args))) + + (advice-add 'undo-tree-visualize :around #'undo-tree-split-side-by-side) + :hook + (elpaca-after-init . global-undo-tree-mode)) + +;;; Multiple Cursors +(use-package multiple-cursors + :bind (("C-S-c C-S-c" . mc/edit-lines) + ("C-M-SPC" . set-rectangular-region-anchor) + ("C->" . mc/mark-next-like-this) + ("C-<" . mc/mark-previous-like-this) + ("C-c C-<" . mc/mark-all-like-this) + ("C-\"" . mc/skip-to-next-like-this) + ("C-:" . mc/skip-to-previous-like-this))) + +(use-package move-text + :bind (("M-p" . move-text-up) + ("M-n" . move-text-down))) + +;;; Magit +(use-package magit + :commands magit-status + :bind ("C-x g" . magit)) + +(use-package forge + :after magit) + +;;; Programming Languages +(use-package nix-mode + :mode "\\.nix\\'") + +(use-package python-mode + :mode ("\\.py\\'" . python-mode)) + +(use-package go-mode + :mode ("\\.go\\'" . go-mode)) + +(use-package csv-mode + :mode ("\\.csv\\'" . csv-mode)) + +(use-package markdown-mode + :mode ("\\.md\\'" . markdown-mode)) + +(use-package lua-mode + :mode ("\\.lua\\'" . lua-mode)) + +(use-package yaml-mode + :mode (("\\.yml\\'" . yaml-mode) + ("\\.yaml\\'" . yaml-mode))) + +(use-package yasnippet + :commands (yas-minor-modeb yas-reload-all) + :config + (yas-reload-all) + :hook + (prog-mode . yas-minor-mode)) + +(use-package yasnippet-snippets + :after yasnippet) + +(use-package clipetty + :hook (elpaca-after-init . global-clipetty-mode)) + +;;; Miscellaneous +(global-unset-key (kbd "C-M-_")) + +(use-package diminish) + +(use-package rainbow-mode + :commands (rainbow-mode)) + +(use-package rainbow-delimiters + :hook (prog-mode . rainbow-delimiters-mode)) + +(use-package term-keys + :ensure (:host github :repo "CyberShadow/term-keys") + :config (unless (display-graphic-p) (term-keys-mode t))) + +(use-package windmove + :ensure nil + :bind (("C-c " . windmove-left) + ("C-c " . windmove-right) + ("C-c " . windmove-up) + ("C-c " . windmove-down))) + +(use-package ace-window + :defer t + :commands (ace-window) + :bind ("C-x C-o" . ace-window)) + +(use-package transient) + +(use-package compile-angel + :diminish + :ensure t + :demand t + :config + (setq compile-angel-verbose nil) + (setq compile-angel-excluded-files-regexps '("/init\\.el$" "/early-init\\.el$")) + (compile-angel-on-load-mode) + (add-hook 'emacs-lisp-mode-hook #'compile-angel-on-save-local-mode)) + +(use-package which-key + :defer t + :commands which-key-mode + :hook (elpaca-after-init . which-key-mode) + :custom + (which-key-idle-delay 1.5) + (which-key-idle-secondary-delay 0.25) + (which-key-add-column-padding 1) + (which-key-max-description-length 40)) + +(unless (and (eq window-system 'mac) + (bound-and-true-p mac-carbon-version-string)) + (setq pixel-scroll-precision-use-momentum nil) + (pixel-scroll-precision-mode 1)) + +(unless (display-graphic-p) + (xterm-mouse-mode 1) + (global-set-key (kbd "") 'scroll-down-line) + (global-set-key (kbd "") 'scroll-up-line)) + +(display-time-mode 1) +(show-paren-mode 1) +(winner-mode 1) +(delete-selection-mode 1) + +(setq confirm-kill-emacs 'y-or-n-p) + +(use-package uniquify + :ensure nil + :custom + (uniquify-buffer-name-style 'reverse) + (uniquify-separator "•") + (uniquify-after-kill-buffer-p t) + (uniquify-ignore-buffers-re "^\\*")) + +(add-hook 'elpaca-after-init-hook #'window-divider-mode) +(add-hook 'text-mode-hook #'flyspell-mode) + +;;; Window splitting +(defun delete-window-evenly () + (interactive) + (command-execute 'delete-window) + (command-execute 'balance-windows)) +(global-set-key (kbd "C-x 0") 'delete-window-evenly) + +(defun split-vertical-evenly () + (interactive) + (command-execute 'split-window-vertically) + (command-execute 'balance-windows)) +(global-set-key (kbd "C-x 2") 'split-vertical-evenly) + +(defun split-horizontal-evenly () + (interactive) + (command-execute 'split-window-horizontally) + (command-execute 'balance-windows)) +(global-set-key (kbd "C-x 3") 'split-horizontal-evenly) + +;;; Zoom +(defun rs/zoom-frame (&optional amt frame) + "Increaze FRAME font size by amount AMT. Defaults to selected +frame if FRAME is nil, and to 1 if AMT is nil." + (interactive "p") + (let* ((frame (or frame (selected-frame))) + (font (face-attribute 'default :font frame)) + (size (font-get font :size)) + (amt (or amt 1)) + (new-size (+ size amt))) + (set-frame-font (font-spec :size new-size) t `(,frame)) + (message "Frame's font new size: %d" new-size))) + +(defun rs/zoom-frame-out (&optional amt frame) + "Call `rs/zoom-frame' with negative argument." + (interactive "p") + (rs/zoom-frame (- (or amt 1)) frame)) + +(global-set-key (kbd "C-=") 'rs/zoom-frame) +(global-set-key (kbd "C--") 'rs/zoom-frame-out) +(global-set-key (kbd "") 'rs/zoom-frame) +(global-set-key (kbd "") 'rs/zoom-frame-out) +(global-set-key (kbd "") 'rs/zoom-frame) +(global-set-key (kbd "") 'rs/zoom-frame-out) + +;;; Org +(setq org-directory rs/notes-dir) +(setq org-agenda-files '("agenda.org")) + +(setq org-tag-alist '((:startgroup) + ("home" . ?h) + ("work" . ?w) + ("school" . ?s) + (:endgroup) + (:newline) + (:startgroup) + ("one-shot" . ?o) + ("project" . ?j) + ("tiny" . ?t) + (:endgroup) + ("meta") + ("review") + ("reading"))) + +(setq org-refile-targets '(("agenda.org" :maxlevel . 2) + ("archive.org" :level . 1))) + +(setq org-archive-location "archive.org::* Archived") + +(setq org-link-abbrev-alist + '(("family_search" . "https://www.familysearch.org/tree/person/details/%s"))) + +(use-package org + :ensure nil + :hook ((org-mode . visual-line-mode) + (org-mode . flyspell-mode)) + :init + (with-eval-after-load 'org + (require 'mu4e-org nil t)) + :bind (:map global-map + ("C-c a" . org-agenda) + ("C-c c" . org-capture) + ("C-c l s" . org-store-link) + ("C-c l i" . org-insert-link-global)) + :custom + (org-time-stamp-rounding-minutes '(0 5)) + (org-read-date-prefer-future t) + (org-return-follows-link t) + (org-agenda-window-setup 'current-window) + (org-agenda-start-with-log-mode t) + (org-agenda-include-diary nil) + (org-agenda-tags-column -80) + (org-agenda-block-separator ?─) + (org-agenda-time-grid '((daily today require-timed) + (800 1000 1200 1400 1600 1800 2000) + " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")) + (org-agenda-current-time-string "◀── now ──────────────────────────────────────") + :config + (require 'oc-csl) + (add-to-list 'org-export-backends 'md) + (setf (cdr (assoc 'file org-link-frame-setup)) 'find-file) + (setq org-export-with-smart-quotes t) + (setq org-todo-keywords + '((sequence "TODO(t)" "WAITING(w@/!)" "STARTED(s!)" "|" "DONE(d!)" "OBSOLETE(o@)"))) + (setq org-outline-path-complete-in-steps nil) + (setq org-refile-use-outline-path 'file) + (setq org-capture-templates + '(("c" "Quick Capture" entry (file+headline "agenda.org" "Inbox") + "** TODO %?\n%U\n%i") + ("r" "Capture with Reference" entry (file+headline "agenda.org" "Inbox") + "** TODO %?\n%U\n%i\n%a") + ("t" "Task" entry (file+headline "agenda.org" "Tasks") + "** TODO %?\n%U\n%i") + ("m" "Meeting" entry (file+headline "agenda.org" "Meetings") + "** TODO %?\n%U\n%i\n%a") + ("e" "Email") + ("ei" "Email to Inbox" entry (file+headline "agenda.org" "Inbox") + "** TODO %:subject\nFrom: %:fromname <%:fromaddress>\nEmail: %a\n%?") + ("et" "Email to Tasks" entry (file+headline "agenda.org" "Tasks") + "** TODO %:subject\nFrom: %:fromname <%:fromaddress>\nEmail: %a\n%?") + ("ef" "Email Follow-up" entry (file+headline "agenda.org" "Tasks") + "** TODO Follow up: %:subject\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\nFrom: %:fromname\nEmail: %a\n%?"))) + (setq org-agenda-custom-commands + '(("n" "Dashboard" + ((tags-todo "+DEADLINE<\"\"" + ((org-agenda-overriding-header "⚠ Overdue!"))) + (agenda "" ((org-agenda-span 'day) + (org-deadline-warning-days 7) + (org-agenda-time-grid nil) + (org-agenda-overriding-header "📅 Today"))) + (todo "STARTED" + ((org-agenda-overriding-header "🔨 In Progress"))) + (todo "WAITING" + ((org-agenda-overriding-header "⏳ Waiting"))) + (tags-todo "+DEADLINE>=\"\"+DEADLINE<=\"<+7d>\"" + ((org-agenda-overriding-header "📆 Due This Week"))) + (tags-todo "inbox" + ((org-agenda-overriding-header "📥 Inbox"))) + (agenda "" ((org-agenda-span 7) + (org-agenda-start-day "+1d") + (org-agenda-start-on-weekday nil) + (org-agenda-show-all-dates t) + (org-agenda-time-grid nil) + (org-agenda-overriding-header "📅 Next 7 Days"))) + (alltodo "" + ((org-agenda-skip-function + '(org-agenda-skip-entry-if 'scheduled 'deadline 'todo '("STARTED" "WAITING"))) + (org-agenda-overriding-header "📋 Backlog"))))) + ("w" "Week View" + ((agenda "" ((org-agenda-span 'week) + (org-deadline-warning-days 14))))) + ("i" "Inbox" tags-todo "inbox") + ("p" "Projects" tags-todo "project")))) + +;;; Denote +(use-package denote + :ensure t + :custom + (denote-directory rs/notes-dir) + (denote-file-type 'markdown-yaml) + (denote-known-keywords '("project" "idea" "ref" "meeting" "paper" "misc")) + (denote-prompts '(subdirectory title keywords)) + (denote-excluded-directories-regexp "^\\.\\|^scripts$") + :bind + (("C-c n n" . denote) + ("C-c n f" . denote-open-or-create) + ("C-c n d" . denote-sort-dired) + ("C-c n i" . denote-link) + ("C-c n l" . denote-backlinks) + ("C-c n r" . denote-rename-file) + ("C-c n R" . denote-rename-file-using-front-matter) + ("C-c n k" . denote-keywords-add) + ("C-c n K" . denote-keywords-remove)) + :config + (denote-rename-buffer-mode 1)) + +(use-package denote-org + :ensure t + :commands + (denote-org-link-to-heading + denote-org-backlinks-for-heading + + denote-org-extract-org-subtree + + denote-org-convert-links-to-file-type + denote-org-convert-links-to-denote-type + + denote-org-dblock-insert-files + denote-org-dblock-insert-links + denote-org-dblock-insert-backlinks + denote-org-dblock-insert-missing-links + denote-org-dblock-insert-files-as-headings)) + +(use-package denote-org-extras + :ensure nil + :after denote + :config + (denote-org-extras-dblock-backlinks-mode 1) + :bind + (("C-c n b" . denote-org-extras-backlinks-for-heading) + ("C-c n h" . denote-org-extras-link-to-heading))) + +(use-package denote-journal + :ensure t + :custom + (denote-journal-directory "journal/") + (denote-journal-keyword "journal") + (denote-journal-title-format 'day-date-month-year) + :bind + (("C-c n j" . denote-journal-new-entry) + ("C-c n J" . denote-journal-new-or-existing-entry))) + +(use-package denote-sequence + :ensure t + :bind + (("C-c n s s" . denote-sequence) + ("C-c n s c" . denote-sequence-new-child-of-current) + ("C-c n s S" . denote-sequence-new-sibling-of-current) + ("C-c n s f" . denote-sequence-find) + ("C-c n s l" . denote-sequence-link) + ("C-c n s d" . denote-sequence-dired))) + +(use-package denote-explore + :ensure t + :bind + (("C-c n e n" . denote-explore-count-notes) + ("C-c n e k" . denote-explore-count-keywords) + ("C-c n e r" . denote-explore-random-note) + ("C-c n e l" . denote-explore-random-link) + ("C-c n e g" . denote-explore-network) + ("C-c n e b" . denote-explore-barchart-keywords) + ("C-c n e s" . denote-explore-sync-metadata))) + +;;; Email (mu4e) +(use-package mu4e + :ensure (:host github :repo "djcb/mu" + :files ("mu4e/*.el") + :pre-build (with-temp-file "mu4e/mu4e-config.el" + (insert (format "(defconst mu4e-mu-version %S)\n" + (string-trim (shell-command-to-string "mu --version | head -1 | awk '{print $2}'"))) + "(provide 'mu4e-config)\n"))) + :defer t + :commands (mu4e mu4e-compose-new) + :bind ("C-c e" . mu4e) + :config + (setq mu4e-mu-binary (or (executable-find "mu") rs/mu-binary)) + + (require 'mu4e-org) + + (setq mu4e-maildir rs/mail-dir) + (setq mu4e-get-mail-command rs/mbsync-command) + (setq mu4e-update-interval 180) + (setq mu4e-change-filenames-when-moving t) + + (setq sendmail-program "msmtp") + (setq send-mail-function 'sendmail-send-it) + (setq message-sendmail-f-is-evil t) + (setq message-sendmail-extra-arguments '("--read-envelope-from")) + (setq message-send-mail-function 'message-send-mail-with-sendmail) + + (setq message-kill-buffer-on-exit t) + + (setq mu4e-headers-date-format "%Y-%m-%d") + (setq mu4e-headers-time-format "%H:%M") + (setq mu4e-view-show-addresses t) + (setq mu4e-view-show-images t) + (setq mu4e-compose-dont-reply-to-self t) + + (setq mm-discouraged-alternatives '("text/html" "text/richtext")) + + (setq mml-secure-openpgp-sign-with-sender t) + (setq mm-sign-option nil) + + (defun mu4e-compose-sign-message () + "Sign the current message with GPG." + (interactive) + (mml-secure-message-sign-pgpmime)) + + (add-hook 'mu4e-compose-mode-hook + (lambda () + (local-set-key (kbd "C-c C-s") 'mu4e-compose-sign-message))) + + (add-hook 'mu4e-headers-mode-hook + (lambda () + (local-set-key (kbd "r") 'mu4e-compose-reply) + (local-set-key (kbd "R") 'mu4e-compose-wide-reply))) + (add-hook 'mu4e-view-mode-hook + (lambda () + (local-set-key (kbd "r") 'mu4e-compose-reply) + (local-set-key (kbd "R") 'mu4e-compose-wide-reply))) + + (define-key mu4e-headers-mode-map (kbd "e") 'mu4e-headers-mark-for-refile) + (define-key mu4e-view-mode-map (kbd "e") 'mu4e-view-mark-for-refile) + + (define-key mu4e-headers-mode-map (kbd "t") 'mu4e-headers-mark-for-something) + + (defun mu4e-headers-mark-all-for-something () + "Mark all messages in current view for an action (prompts once)." + (interactive) + (let* ((mark (mu4e-read-option "Mark all as: " + '(("Read" . read) + ("Unread" . unread) + ("Trash" . trash) + ("Delete" . delete) + ("Archive" . refile) + ("Move" . move) + ("Flag" . flag) + ("uNflag" . unflag)))) + (target (when (eq mark 'move) + (mu4e-ask-maildir "Move all to: "))) + (count 0)) + (save-excursion + (goto-char (point-min)) + (while (and (not (eobp)) + (not (get-text-property (point) 'msg))) + (forward-line 1)) + (while (not (eobp)) + (when (get-text-property (point) 'msg) + (cond + ((eq mark 'move) + (mu4e-mark-at-point 'move target)) + ((eq mark 'refile) + (mu4e-mark-at-point 'refile (mu4e--mark-get-refile-target + (mu4e-message-at-point)))) + (t + (mu4e-mark-at-point mark nil))) + (setq count (1+ count))) + (forward-line 1))) + (message "Marked %d messages for %s" count mark))) + (define-key mu4e-headers-mode-map (kbd "T") 'mu4e-headers-mark-all-for-something) + + (setq mu4e-completing-read-function 'completing-read) + + (setq mu4e-contexts + `(,(make-mu4e-context + :name "uchicago" + :match-func (lambda (msg) + (when msg + (string-prefix-p "/uchicago" (mu4e-message-field msg :maildir)))) + :vars `((user-mail-address . ,rs/email-uchicago) + (user-full-name . ,rs/full-name) + (mu4e-drafts-folder . "/uchicago/Drafts") + (mu4e-sent-folder . "/uchicago/Sent") + (mu4e-trash-folder . "/uchicago/Trash") + (mu4e-refile-folder . "/uchicago/Archive") + (message-sendmail-extra-arguments . ("--read-envelope-from" "-a" "uchicago")))) + ,(make-mu4e-context + :name "personal" + :match-func (lambda (msg) + (when msg + (string-prefix-p "/personal" (mu4e-message-field msg :maildir)))) + :vars `((user-mail-address . ,rs/email-personal) + (user-full-name . ,rs/full-name) + (mu4e-drafts-folder . "/personal/[Gmail]/Drafts") + (mu4e-sent-folder . "/personal/[Gmail]/Sent Mail") + (mu4e-trash-folder . "/personal/[Gmail]/Trash") + (mu4e-refile-folder . "/personal/Archive") + (message-sendmail-extra-arguments . ("--read-envelope-from" "-a" "personal")))))) + + (setq mu4e-context-policy 'pick-first) + (setq mu4e-compose-context-policy 'ask-if-none) + + (setq mu4e-bookmarks + '((:name "Unread messages" :query "flag:unread AND NOT flag:trashed" :key ?u) + (:name "Today's messages" :query "date:today..now" :key ?t) + (:name "Last 7 days" :query "date:7d..now" :key ?w) + (:name "UChicago Inbox" :query "maildir:/uchicago/Inbox" :key ?i) + (:name "Personal Inbox" :query "maildir:/personal/Inbox" :key ?p)))) + +(use-package wakatime-mode + :config + (global-wakatime-mode)) + +;;; init.el ends here diff --git a/config/emacs/lib/naysayer-theme.el b/config/emacs/lib/naysayer-theme.el index d9492f2..9003842 100644 --- a/config/emacs/lib/naysayer-theme.el +++ b/config/emacs/lib/naysayer-theme.el @@ -1,4 +1,4 @@ -;;; naysayer-theme.el --- The naysayer color theme +;;; naysayer-theme.el --- The naysayer color theme -*- lexical-binding: t; -*- ;; Author: Nick Aversano ;; Version: 0.33 @@ -58,11 +58,11 @@ ;; ***************************************************************************** `(default ((t (:foreground ,text :background ,background, :weight normal)))) - `(region ((t (:foreground nil :background ,selection)))) + `(region ((t (:foreground unspecified :background ,selection)))) `(cursor ((t (:background ,white )))) `(fringe ((t (:background ,background :foreground ,white)))) `(linum ((t (:background ,background :foreground ,gutter-fg)))) - `(highlight ((t (:foreground nil :background ,selection)))) + `(highlight ((t (:foreground unspecified :background ,selection)))) ;; Font lock faces ;; ***************************************************************************** @@ -83,8 +83,8 @@ ;; Plugins ;; ***************************************************************************** - `(trailing-whitespace ((t (:foreground nil :background ,warning)))) - `(whitespace-trailing ((t (:background nil :foreground ,warning :inverse-video t)))) + `(trailing-whitespace ((t (:foreground unspecified :background ,warning)))) + `(whitespace-trailing ((t (:background unspecified :foreground ,warning :inverse-video t)))) `(linum ((t (:foreground ,line-fg :background ,background)))) `(linum-relative-current-face ((t (:foreground ,white :background ,background)))) @@ -135,8 +135,8 @@ `(powerline-inactive2 ((t (:background ,background :foreground ,text)))) ;; better compatibility with default DOOM mode-line - `(error ((t (:foreground nil :weight normal)))) - `(doom-modeline-project-dir ((t (:foreground nil :weight bold)))) + `(error ((t (:foreground unspecified :weight normal)))) + `(doom-modeline-project-dir ((t (:foreground unspecified :weight bold)))) ;; js2-mode `(js2-function-call ((t (:inherit (font-lock-function-name-face))))) diff --git a/home/emacs.nix b/home/emacs.nix index 5c94f89..bb7a08b 100644 --- a/home/emacs.nix +++ b/home/emacs.nix @@ -13,16 +13,19 @@ }; config = lib.mkIf config.custom.emacs.enable { - home.packages = lib.mkIf pkgs.stdenv.isLinux ( + home.packages = with pkgs; [ - emacs + aspell + ispell ] - ); + ++ lib.optionals pkgs.stdenv.isLinux [ + emacs + ]; - home.file.".emacs.d" = { - source = "${pkgs.custom.minimal-emacs-d}"; - }; + # home.file.".emacs.d" = { + # source = "${pkgs.custom.minimal-emacs-d}"; + # }; xdg.configFile."emacs".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/emacs"; };