diff options
56 files changed, 2120 insertions, 964 deletions
diff --git a/.bash_logout b/.bash_logout deleted file mode 100644 index df7ab07..0000000 --- a/.bash_logout +++ /dev/null @@ -1,13 +0,0 @@ -# don't leave behind any stray ssh sessions - kill them when bash exits, -# unless it was running inside a tmux session (but the idea is to kill -# ssh sessions running inside tmux!) -if [ -n "${SSH_CONNECTION}" -a -z "${TMUX}" ]; then - for ssh_host in $(grep 'Host\b' .ssh/config|cut -f2 -d' ') ; do - ssh_pid=$(ps u|awk "/ssh ${ssh_host}/ && !/grep/{print $2}") - [ -n "${ssh_pid}" ] && kill ${ssh_pid} 2>/dev/null - done -fi - -if [ "$SHLVL" = 1 ]; then - [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q -fi diff --git a/.emacs.d/.gitignore b/.emacs.d/.gitignore index 9168e78..2ce66c1 100644 --- a/.emacs.d/.gitignore +++ b/.emacs.d/.gitignore @@ -36,5 +36,8 @@ site-lisp straight !straight/versions elpaca -elpa +elpaca.lock eln-cache +forge-database.sqlite +sql +ielm diff --git a/.emacs.d/README.md b/.emacs.d/README.md index 965a718..0f006b6 100644 --- a/.emacs.d/README.md +++ b/.emacs.d/README.md @@ -10,6 +10,7 @@ My Emacs Configuration, inspired by Prelude (https://github.com/bbatsov/prelude) - https://gitlab.com/protesilaos/dotfiles - https://gitlab.com/buildfunthings/emacs-config - https://www.emacswiki.org/emacs +- https://github.com/jamescherti/minimal-emacs.d As well as the github READMEs and wikis for corfu, vertico, orderless, consult, embark, marginalia, and other places too. diff --git a/.emacs.d/early-init.el b/.emacs.d/early-init.el index 9e1f474..e55becc 100644 --- a/.emacs.d/early-init.el +++ b/.emacs.d/early-init.el @@ -2,12 +2,18 @@ ;;; Commentary: ;;; Code: + +(when (eq system-type 'darwin) + (setq frame-resize-pixelwise t)) + (setq gc-cons-threshold most-positive-fixnum gc-cons-percentage 0.6) (setq load-prefer-newer t native-comp-async-report-warnings-errors nil + native-comp-warning-on-missing-source nil warning-suppress-log-types '((comp) (bytecomp)) + byte-compile-verbose nil byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local obsolete)) (push '(menu-bar-lines . 0) default-frame-alist) @@ -19,15 +25,28 @@ (setq frame-inhibit-implied-resize t) -(toggle-frame-maximized) -(add-to-list 'default-frame-alist '(fullscreen . maximized)) +(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))) (menu-bar-mode -1) (when window-system (tool-bar-mode -1) (scroll-bar-mode -1) + (tooltip-mode -1) (horizontal-scroll-bar-mode -1)) +;; Copied from https://github.com/jamescherti/minimal-emacs.d +;; Some features that are not represented as packages can be found in +;; `features', but this can be inconsistent. The following enforce consistency: +(if (fboundp #'json-parse-string) + (push 'jansson features)) +(if (string-match-p "HARFBUZZ" system-configuration-features) ; no alternative + (push 'harfbuzz features)) +(if (bound-and-true-p module-file-suffix) + (push 'dynamic-modules features)) + (setq package-enable-at-startup nil) ;; Some optimizations from doom.el (some of these probably don't belong here!) @@ -42,6 +61,19 @@ (setq inhibit-compacting-font-caches t) (setq redisplay-skip-fontification-on-input t) +;; Copied/modified from https://github.com/jamescherti/minimal-emacs.d +(setq ad-redefinition-action 'accept + warning-suppress-types '((lexical-binding)) + inhibit-startup-buffer-menu t + inhibit-x-resources t + use-file-dialog nil + use-dialog-box nil) +(advice-add #'display-startup-screen :override #'ignore) +(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)) + (define-advice load-file (:override (file) silence) (load file nil 'nomessage)) (define-advice startup--load-user-init-file (:before (&rest _) undo-silence) diff --git a/.emacs.d/init.el b/.emacs.d/init.el index 7c8c8d8..2250665 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -26,14 +26,6 @@ gc-cons-percentage 0.1)) 99) -;; Some straight functions need to be able to reload everything, so require won't do -(defun require! (feature &optional filename noerror) - "Like `require', but if `force-reload' is non-nil, `load' instead. -`FEATURE', `FILENAME' and `NOERROR' have the same meaning as with require" - (if (and (boundp 'force-reload) force-reload) - (load (prin1-to-string feature) noerror nil nil t) - (require feature filename noerror))) - (require 'init-packages) (require 'init-ui) (require 'init-compile) diff --git a/.emacs.d/lisp/init-clojure.el b/.emacs.d/lisp/init-clojure.el index 2bfaf78..7673565 100644 --- a/.emacs.d/lisp/init-clojure.el +++ b/.emacs.d/lisp/init-clojure.el @@ -28,7 +28,8 @@ ("st" "#spy/t"))) (defalias 'cape-clojure (cape-capf-super #'cider-complete-at-point - #'lsp-completion-at-point)) + #'lsp-completion-at-point + #'cape-dabbrev)) (defun set-clojure-capf () (add-hook 'completion-at-point-functions #'cape-clojure -99 t)) @@ -101,14 +102,13 @@ :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) - :bind :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,30 +196,47 @@ 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." (when (apply #'eq (mapcar 'window-buffer (window-list))) (delete-other-windows))) (advice-add #'cider-close-ancillary-buffers :after #'fix-duplicate-windows) + :bind (:map cider-mode-map ("C-c M-l" . cider-load-file) - ("C-c M-b" . cider-interrupt)) + ("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) + ("C-x M-i v" . cider-inspect-expr)) (:map cider-repl-mode-map - ("C-c M-b" . cider-interrupt)) + ("C-c M-b" . cider-interrupt) + ;; sp commands sometimes behave strangely in the cider repl buffer + ("M-d" . paredit-forward-kill-word) + ("M-DEL" . paredit-backward-kill-word) + ("C-k" . paredit-kill) + ("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) + ("C-x M-i v" . cider-inspect-expr)) (:map cider-start-map - ("C-c M-i" . cider-jack-in-and-run-main)) + ("C-c C-M-j" . cider-jack-in-and-run-main)) (:map clojure-mode-map ("C-c C-r C-m" . run-main) ("C-c C-r C-d" . load-debug-namespaces) - ("C-c M-i" . cider-jack-in-and-run-main) + ("C-c C-M-j" . cider-jack-in-and-run-main) ("C-x p q" . project-clojure-test-switch) ("C-c C-M-c" . (lambda () (interactive) (cider-clear-compilation-highlights t))) ("C-c C->" . cider-find-dwim) diff --git a/.emacs.d/lisp/init-completion.el b/.emacs.d/lisp/init-completion.el index cac9c0a..16eca6b 100644 --- a/.emacs.d/lisp/init-completion.el +++ b/.emacs.d/lisp/init-completion.el @@ -4,75 +4,103 @@ ;; Most of it is taken from the READMEs and wikis of those packages ;;; Code: +(defun +elpaca-unload-dabbrev (e) + (and (featurep 'dabbrev) (unload-feature 'dabbrev t)) + (elpaca--continue-build e)) + +(defun +elpaca-dabbrev-build-steps () + (append (butlast (if (file-exists-p (expand-file-name "dabbrev" elpaca-builds-directory)) + elpaca--pre-built-steps elpaca-build-steps)) + (list '+elpaca-unload-dabbrev 'elpaca--activate-package))) + (use-feature dabbrev - :diminish :custom (dabbrev-case-distinction nil) (dabbrev-case-fold-search t) (dabbrev-case-replace nil)) -(use-feature hippie-expand +(use-package mono-complete :config - (setq hippie-expand-try-functions-list - '(;yas-hippie-try-expand - try-expand-dabbrev - try-expand-all-abbrevs - try-expand-dabbrev-all-buffers - try-expand-dabbrev-from-kill - try-complete-file-name-partially - try-complete-file-name - try-expand-list - try-expand-line - try-complete-lisp-symbol-partially - try-complete-lisp-symbol)) - ;; https://www.emacswiki.org/emacs/HippieExpand#h5o-9 - (defadvice he-substitute-string (after he-paredit-fix) - "Remove extra paren when expanding line in paredit." - (if (and (or smartparens-mode paredit-mode) (equal (substring str -1) ")")) - (progn (backward-delete-char 1) (forward-char)))) + (setq mono-complete-preview-delay 0.15 + mono-complete-backends '(dabbrev filesystem whole-line) + mono-complete-project-root 'persp-current-project-root) + (append-to-list* 'mono-complete-self-insert-commands 'sp-backward-delete-char 'sp-delete-char 'delete-indentation 'backward-delete-char 'delete-char) + (defun mono-complete-expand-or-complete () + (interactive) + (if (eq 'mono-complete-expand-or-complete real-last-command) + (let ((corfu-preselect 'prompt)) + (progn + (primitive-undo 2 buffer-undo-list) + (completion-at-point))) + (mono-complete-expand-or-fallback))) + :hook ((text-mode prog-mode) . mono-complete-mode) :bind - ("C-M-/" . hippie-expand)) + (:map mono-complete-mode-map ("M-/" . mono-complete-expand-or-complete))) -(use-package fancy-dabbrev - :diminish - :config - (global-fancy-dabbrev-mode) - (defun fancy-dabbrev-popup-advice (_next) - (local-set-key (kbd "C-M-/") #'fancy-dabbrev-backward)) - (defun fancy-dabbrev-popup-exit-advice () - (local-unset-key (kbd "C-M-/"))) - (advice-add #'fancy-dabbrev--expand-again :before #'fancy-dabbrev-popup-advice) - (advice-add #'fancy-dabbrev--on-exit :after #'fancy-dabbrev-popup-exit-advice) - :bind ("M-/" . fancy-dabbrev-expand)) +(use-feature hippie-expand + :custom + (hippie-expand-try-functions-list '(try-expand-dabbrev + try-expand-all-abbrevs + try-expand-dabbrev-all-buffers + try-expand-dabbrev-from-kill + try-complete-file-name-partially + try-complete-file-name + try-expand-list + try-expand-line + try-complete-lisp-symbol-partially + try-complete-lisp-symbol)) + :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)) (use-feature emacs :config - (setq completion-cycle-threshold 3) + (setq completion-cycle-threshold 2) (setq tab-always-indent 'complete) (setq read-buffer-completion-ignore-case t read-file-name-completion-ignore-case t completion-ignore-case t)) (use-package orderless - :defer 2 - :bind (:map minibuffer-local-map - ("C-l" . my/orderless-match-components-literally)) + :bind + (:map minibuffer-local-map + ("C-l" . orderless-toggle-literal-matching)) + (:map corfu-map + ("C-l" . orderless-toggle-literal-matching)) :custom (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))))) (orderless-matching-styles '(orderless-literal orderless-regexp orderless-strict-initialism)) - (orderless-style-dispatchers '(+orderless-dispatch)) + (orderless-style-dispatchers (list #'+orderless-consult-dispatch + #'orderless-affix-dispatch)) :config - (defun my/orderless-match-components-literally () - "Components match literally for the rest of the session." + ;; Inspired by https://github.com/oantolin/orderless/blob/ac4aeb66f331f4c4a430d5556071e33177304c37/README.org#interactively-changing-the-configuration + (defun orderless-toggle-literal-matching () + "Toggle matching components literally for the rest of the session." (interactive) - (setq-local orderless-matching-styles '(orderless-literal) - orderless-style-dispatchers nil)) + (if orderless-style-dispatchers + (progn + (setq-local +saved-orderless-matching-styles orderless-matching-styles + +saved-orderless-style-dispatchers orderless-style-dispatchers) + (setq-local orderless-matching-styles '(orderless-literal) + orderless-style-dispatchers nil)) + (setq-local orderless-matching-styles +saved-orderless-matching-styles + orderless-style-dispatchers +saved-orderless-style-dispatchers)) + (when vertico--input + (setq vertico--input t) + (vertico--update)) + (when corfu--input + (setq corfu--input t) + (corfu--update))) (defun orderless-strict-initialism (component &optional leading) - "Match a component as a strict leading initialism. + "Match a component as a strict initialism. This means the characters in COMPONENT must occur in the candidate, in that order, at the beginning of words, with no words in between. If LEADING is non-nil, anchor to the @@ -88,68 +116,84 @@ candidate, in that order, at the beginning of words, with no words in between, beginning with the first word." (orderless-strict-initialism component t)) - ;; based on https://github.com/minad/consult/wiki#minads-orderless-configuration - (defvar +orderless-dispatch-alist - '((?% . char-fold-to-regexp) - (?! . orderless-without-literal) - (?` . orderless-strict-leading-initialism) - (?= . orderless-literal) - (?_ . orderless-prefix) - (?~ . orderless-flex))) + ;; 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) - (defun +orderless--suffix-regexp () + ;; Copied from https://github.com/minad/consult/wiki#minads-orderless-configuration + (defun +orderless--consult-suffix () + "Regexp which matches the end of string with Consult tofu support." (if (and (boundp 'consult--tofu-char) (boundp 'consult--tofu-range)) (format "[%c-%c]*$" consult--tofu-char (+ consult--tofu-char consult--tofu-range -1)) "$")) + ;; Copied from https://github.com/minad/consult/wiki#minads-orderless-configuration ;; Recognizes the following patterns: - ;; * ~flex flex~ - ;; * =literal literal= - ;; * _prefix prefix_ - ;; * %char-fold char-fold% - ;; * `strict-leading-initialism strict-leading-initialism` - ;; * !without-literal without-literal! ;; * .ext (file extension) ;; * regexp$ (regexp matching at end) - (defun +orderless-dispatch (word _index _total) + (defun +orderless-consult-dispatch (word _index _total) (cond ;; Ensure that $ works with Consult commands, which add disambiguation suffixes ((string-suffix-p "$" word) - `(orderless-regexp . ,(concat (substring word 0 -1) (+orderless--suffix-regexp)))) + `(orderless-regexp . ,(concat (substring word 0 -1) (+orderless--consult-suffix)))) ;; File extensions ((and (or minibuffer-completing-file-name (derived-mode-p 'eshell-mode)) (string-match-p "\\`\\.." word)) - `(orderless-regexp . ,(concat "\\." (substring word 1) (+orderless--suffix-regexp)))) - ;; Ignore single ! - ((equal "!" word) `(orderless-literal . "")) - ;; Prefix and suffix - ((if-let (x (assq (aref word 0) +orderless-dispatch-alist)) - (cons (cdr x) (substring word 1)) - (when-let (x (assq (aref word (1- (length word))) +orderless-dispatch-alist)) - (cons (cdr x) (substring word 0 -1)))))))) + `(orderless-regexp . ,(concat "\\." (substring word 1) (+orderless--consult-suffix)))))) + + ;; 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))) + + (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 :ensure (corfu :files (:defaults "extensions/*")) :custom (corfu-cycle t) + (corfu-preselect 'first) :bind (:map corfu-map + ("SPC" . corfu-insert) ("TAB" . corfu-next) ([tab] . corfu-next) + ("M-/" . corfu-next) ("S-TAB" . corfu-previous) - ([backtab] . corfu-previous)) + ([backtab] . corfu-previous) + ("C-M-/" . corfu-previous)) :hook (elpaca-after-init . global-corfu-mode)) (use-extension corfu corfu-indexed - :config (corfu-indexed-mode 1)) + :config + (defmacro define-corfu-complete (n) + `(defun ,(intern (format "corfu-indexed-complete-%s" n)) () + ,(format "Complete with candidate %s." n) + (interactive) + (let ((corfu--index ,n)) + (funcall-interactively 'corfu-complete)))) + (defmacro define-corfu-insert (n) + `(defun ,(intern (format "corfu-indexed-insert-%s" n)) () + ,(format "Insert candidate %s." n) + (interactive) + (let ((corfu--index ,n)) + (funcall-interactively 'corfu-insert)))) + (dotimes (n 10) + (eval `(define-corfu-complete ,n)) + (eval `(define-corfu-insert ,n)) + (define-key corfu-map (kbd (format "C-%s" n)) (intern (format "corfu-indexed-complete-%s" n))) + (define-key corfu-map (kbd (format "M-%s" n)) (intern (format "corfu-indexed-insert-%s" n)))) + (corfu-indexed-mode 1)) (use-extension corfu corfu-quick :bind (:map corfu-map ("M-;" . corfu-quick-insert) - ("M-'" . corfu-quick-exit))) + ("M-'" . corfu-quick-complete))) (use-extension corfu corfu-history :after savehist diff --git a/.emacs.d/lisp/init-crux.el b/.emacs.d/lisp/init-crux.el index 0739bd3..5f7b836 100644 --- a/.emacs.d/lisp/init-crux.el +++ b/.emacs.d/lisp/init-crux.el @@ -6,16 +6,6 @@ :defer 5 :commands crux-start-or-switch-to :config - (defmacro crux-with-region-or-sexp-or-line (func) - "When called with no active region, call FUNC on current sexp." - `(defadvice ,func (before with-region-or-sexp-or-line activate compile) - (interactive - (cond - (mark-active (list (region-beginning) (region-end))) - ((in-string-p) (flatten-list (bounds-of-thing-at-point 'string))) - ((thing-at-point 'list) (flatten-list (bounds-of-thing-at-point 'list))) - (t (list (line-beginning-position) (line-beginning-position 2))))))) - (crux-with-region-or-sexp-or-line sp-kill-region) (crux-with-region-or-buffer shell-command-on-region) (crux-with-region-or-buffer indent-region) @@ -25,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-dired.el b/.emacs.d/lisp/init-dired.el index 5ec6531..bd01329 100644 --- a/.emacs.d/lisp/init-dired.el +++ b/.emacs.d/lisp/init-dired.el @@ -13,6 +13,8 @@ (dired-kill-when-opening-new-dired-buffer t) (wdired-use-dired-vertical-movement 'sometimes) (dired-vc-rename-file t) + (dired-clean-confirm-killing-deleted-buffers nil) + (dired-create-destination-dirs 'ask) :bind (:map dired-mode-map ("M-o" . dired-omit-mode) ("E" . wdired-change-to-wdired-mode))) @@ -25,7 +27,8 @@ ("i" . dired-subtree-insert) (";" . dired-subtree-remove))) -(use-package casual-dired +(use-feature casual-dired + :after dired :bind (:map dired-mode-map ("C-o" . casual-dired-tmenu) ("s" . casual-dired-sort-by-tmenu))) diff --git a/.emacs.d/lisp/init-editor.el b/.emacs.d/lisp/init-editor.el index 5cb0cc7..fc575c4 100644 --- a/.emacs.d/lisp/init-editor.el +++ b/.emacs.d/lisp/init-editor.el @@ -33,14 +33,24 @@ (setq comment-auto-fill-only-comments t) (setq large-file-warning-threshold 100000000) (setq create-lockfiles nil) - (setq global-auto-revert-non-file-buffers t) - (setq backup-by-copying t) + (setq global-auto-revert-non-file-buffers t + revert-without-query (list ".") + auto-revert-stop-on-user-input nil) + (setq backup-by-copying t + delete-old-versions t + version-control t + kept-new-versions 5 + kept-old-versions 5) (setq backup-directory-alist `((".*" . ,temporary-file-directory)) auto-save-file-name-transforms - `((".*" ,temporary-file-directory t))) + `((".*" ,temporary-file-directory t)) + auto-save-include-big-deletions t) + (setq comment-multi-line t + comment-empty-lines t) - (setq save-place-file (expand-file-name "saveplace" save-dir)) + (setq save-place-file (expand-file-name "saveplace" save-dir) + save-place-limit 800) ;; https://git.sr.ht/~technomancy/better-defaults/tree/master/item/better-defaults.el (setq save-interprogram-paste-before-kill t apropos-do-all t @@ -50,11 +60,12 @@ (setq ffap-machine-p-local 'accept ffap-machine-p-known 'reject ffap-machine-p-unkown 'reject) - ;; https://github.com/natecox/dotfiles/blob/master/workspaces/shared/symlinks/emacs/.emacs.d/nathancox.org + (setq sentence-end-double-space nil) - (set-charset-priority 'unicode) - (setq locale-coding-system 'utf-8) - (setq default-process-coding-system '(utf-8-unix . utf-8-unix)) + (set-language-environment "UTF-8") + ;; The previous line sets this to "rfc1345" + (setq default-input-method nil) + (set-default 'imenu-auto-rescan t)) (use-package move-text @@ -72,6 +83,7 @@ (savehist-additional-variables '(search-ring regexp-search-ring)) (savehist-autosave-interval 60) (savehist-file (expand-file-name "savehist" save-dir)) + (history-length 300) :hook (elpaca-after-init . savehist-mode)) (use-package super-save @@ -99,13 +111,21 @@ :config (global-flycheck-mode)) -;(use-package flyspell -; :custom -; (ispell-program-name "aspell") -; (ispell-extra-args '("--sug-mode=ultra")) -; :hook -; (text-mode . (lambda () (flyspell-mode +1))) -; (prog-mode . (lambda () (flyspell-prog-mode)))) +(use-feature flyspell + :diminish + :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)) (use-feature bookmark :custom @@ -125,7 +145,6 @@ (undo-tree-auto-save-history t)) (use-feature abbrev - :defer 5 :diminish :hook (text-mode . abbrev-mode) @@ -146,28 +165,48 @@ (use-package operate-on-number :bind - ("C-c ." . operate-on-number-at-point)) + ("C-c +" . operate-on-number-at-point)) (defun +elpaca-unload-xref (e) (and (featurep 'xref) (unload-feature 'xref t)) + ;; Make sure these aren't overwritten + (setq xref-search-program 'ripgrep + xref-show-xrefs-function #'consult-xref + xref-show-definitions-function #'consult-xref) (elpaca--continue-build e)) (defun +elpaca-xref-build-steps () (append (butlast (if (file-exists-p (expand-file-name "xref" elpaca-builds-directory)) elpaca--pre-built-steps elpaca-build-steps)) - (list '+elpaca-unload-xref'elpaca--activate-package))) + (list '+elpaca-unload-xref 'elpaca--activate-package))) -;;(elpaca `(xref :build ,(+elpaca-xref-build-steps))) (use-package xref - :ensure `(xref :build ,(+elpaca-xref-build-steps)) - :custom (xref-search-program 'ripgrep) + :ensure `(xref :build ,(+elpaca-xref-build-steps) :ref "87db670d045bea2d90139b1f741eea8db7c193ea" :pin t) + :custom + (xref-search-program 'ripgrep) + (xref-show-xrefs-function #'consult-xref) + (xref-show-definitions-function #'consult-xref) :config + (defun xref-find-references-current-defun () + "`xref-find-references' for the enclosing defun." + (interactive) + (xref-backend-identifier-completion-table (xref-find-backend)) + (xref-find-references (which-function))) + (defun xref-find-definitions-current-list-function () + "`xref-find-definitions' for the function at the beginning of the current list. +With a prefix argument, moves up `current-prefix-arg' sexps first." + (interactive) + (let ((fn-name (save-excursion + (when current-prefix-arg + (sp-backward-up-sexp current-prefix-arg)) + (sp-beginning-of-sexp) (thing-at-point 'symbol)))) + (xref-find-definitions fn-name))) (defun xref-find-references-other-window (identifier) - "Like `xref-find-references' but switch to the other window" + "Like `xref-find-references' but switch to the other window." (interactive (list (xref--read-identifier "Find references of: "))) (xref--find-xrefs identifier 'references identifier 'window)) (defun xref-find-references-other-frame (identifier) - "Like `xref-find-references' but switch to the other frame" + "Like `xref-find-references' but switch to the other frame." (interactive (list (xref--read-identifier "Find references of: "))) (xref--find-xrefs identifier 'references identifier 'frame)) (define-key ctl-x-4-map (kbd "M-?") 'xref-find-references-other-window) @@ -177,7 +216,10 @@ ;; there is no value at point that can be used (add-to-list 'xref-prompt-for-identifier 'xref-find-references t) (add-to-list 'xref-prompt-for-identifier 'xref-find-references-other-window t) - (add-to-list 'xref-prompt-for-identifier 'xref-find-references-other-frame t)) + (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)) (use-package ws-butler :diminish @@ -222,8 +264,9 @@ :hook (elpaca-after-init . editorconfig-mode)) (use-package titlecase - ;; TODO find a better binding - :bind ("C-c c t t" . titlecase-dwim)) + :bind (("C-c c t t" . titlecase-dwim) + (:map embark-heading-map ("T" . titlecase-line)) + (:map embark-region-map ("T" . titlecase-region)))) (use-package caser :ensure (caser :host github :repo "emacsmirror/caser") @@ -266,5 +309,9 @@ ("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-emacs-lisp.el b/.emacs.d/lisp/init-emacs-lisp.el index 4ca010a..0cf1f44 100644 --- a/.emacs.d/lisp/init-emacs-lisp.el +++ b/.emacs.d/lisp/init-emacs-lisp.el @@ -10,6 +10,10 @@ :diminish) (use-feature emacs + :custom + ;; These don't really belong here, but do affect ielm + (comint-prompt-read-only t) + (comint-buffer-maximum-size 2048) :config ;; Based on prelude-emacs-lisp.el (defun recompile-init-lisp () @@ -61,6 +65,16 @@ Start `ielm' if it's not already running." (use-package eros + :config + ;; https://xenodium.com/inline-previous-result-and-why-you-should-edebug/ + (defun adviced:edebug-previous-result (_ &rest r) + "Adviced `edebug-previous-result'." + (eros--make-result-overlay edebug-previous-result + :where (point) + :duration eros-eval-result-duration)) + (advice-add #'edebug-previous-result + :around + #'adviced:edebug-previous-result) :hook (emacs-lisp-mode . eros-mode)) diff --git a/.emacs.d/lisp/init-git.el b/.emacs.d/lisp/init-git.el index 1d7183e..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,8 +340,13 @@ 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 - :defer 10) + :bind + ("C-c g #" . git-related-find-file) + ("C-c g ~" . git-related-update)) (provide 'init-git) ;;; init-git.el ends here diff --git a/.emacs.d/lisp/init-kill.el b/.emacs.d/lisp/init-kill.el index 37103e3..d72f776 100644 --- a/.emacs.d/lisp/init-kill.el +++ b/.emacs.d/lisp/init-kill.el @@ -16,6 +16,7 @@ (:map easy-kill-base-map ("C-=" . easy-kill-expand))) (use-feature emacs + :custom (kill-do-not-save-duplicates t) :hook (elpaca-after-init . (lambda () ;; Based on code in prelude-editor.el diff --git a/.emacs.d/lisp/init-lsp.el b/.emacs.d/lisp/init-lsp.el index e496813..9a0b4d5 100644 --- a/.emacs.d/lisp/init-lsp.el +++ b/.emacs.d/lisp/init-lsp.el @@ -26,6 +26,7 @@ (lsp-lens-mode . really-diminish-lsp-lens-mode) (lsp-completion-mode . my/lsp-mode-setup-completion) (sql-mode . lsp) + (lsp-after-apply-edits . save-buffer) :config (defun really-diminish-lsp-lens-mode () (diminish 'lsp-lens-mode) @@ -55,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 9fbcf0c..118f730 100644 --- a/.emacs.d/lisp/init-minibuffer.el +++ b/.emacs.d/lisp/init-minibuffer.el @@ -12,7 +12,7 @@ :config ;; Do not allow the cursor in the minibuffer prompt (setq minibuffer-prompt-properties - '(read-only t cursor-intangible t face minibuffer-prompt)) + '(read-only t cursor-intangible t intangible t face minibuffer-prompt)) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) (setq enable-recursive-minibuffers t) (minibuffer-depth-indicate-mode t) @@ -42,24 +42,31 @@ " ") cand))) + ;; https://github.com/minad/vertico/wiki#ding-when-wrapping-around + (advice-add #'vertico-next + :around + #'(lambda (origin &rest args) + (let ((beg-index vertico--index)) + (apply origin args) + (if (not (eq 1 (abs (- beg-index vertico--index)))) + (ding))))) + + ;; https://github.com/minad/vertico/wiki#useful-commands-from-outside-minibuffer (defun down-from-outside () "Move to next candidate in minibuffer, even when minibuffer isn't selected." (interactive) (with-selected-window (active-minibuffer-window) (execute-kbd-macro [down]))) - (defun up-from-outside () "Move to previous candidate in minibuffer, even when minibuffer isn't selected." (interactive) (with-selected-window (active-minibuffer-window) (execute-kbd-macro [up]))) - (defun preview-from-outside () "Preview the selected candidate, even when minibuffer isn't selected." (interactive) (with-selected-window (active-minibuffer-window) (execute-kbd-macro (kbd "M-.")))) - (defun to-and-fro-minibuffer () "Go back and forth between minibuffer and other window." (interactive) @@ -67,18 +74,73 @@ (select-window (minibuffer-selected-window)) (select-window (active-minibuffer-window)))) - (defun minibuffer-really-quit () - "Quit minibuffer session, even if it is not the selected window." + ;; Modified from https://github.com/minad/vertico/wiki#update-minibuffer-history-with-candidate-insertions + (defadvice vertico-insert + (after vertico-insert-add-history activate) + "Make vertico-insert add to the minibuffer history." + (if (and (not (eq minibuffer-history-variable t)) + (eq 'file (vertico--metadata-get 'category))) + (add-to-history minibuffer-history-variable (minibuffer-contents)))) + + (defun toggle-sort-directories-first () (interactive) - (with-selected-window (active-minibuffer-window) - (minibuffer-keyboard-quit))) + (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) 'vertico-sort-directories-first)) + (setq vertico--input t) + (vertico--update)) :bind (("C-M-<" . up-from-outside) ("C-M->" . down-from-outside) ("C-M-+" . preview-from-outside) ("M-X" . to-and-fro-minibuffer) - ("C-M-S-g" . minibuffer-really-quit) - (:map vertico-map ("M-RET" . minibuffer-force-complete-and-exit)))) + (:map vertico-map + ("M-RET" . minibuffer-force-complete-and-exit) + ("M-D" . toggle-sort-directories-first)))) + +(use-extension vertico vertico-multiform + :config + (vertico-multiform-mode +1) + + (defun vertico-multiform-buffer-grid () + "Toggle displaying Vertico as a grid in a large window (like a regular buffer).)" + (interactive) + (if (equal '(vertico-buffer-mode vertico-grid-mode) (car vertico-multiform--stack)) + (vertico-multiform-vertical) + (setcar vertico-multiform--stack '(vertico-buffer-mode vertico-grid-mode)) + (vertico-multiform--toggle 1))) + + ;; https://github.com/minad/vertico/wiki#candidate-display-transformations-custom-candidate-highlighting + (defvar +vertico-transform-functions nil) + (cl-defmethod vertico--format-candidate :around + (cand prefix suffix index start &context ((not +vertico-transform-functions) null)) + (dolist (fun (ensure-list +vertico-transform-functions)) + (setq cand (funcall fun cand))) + (cl-call-next-method cand prefix suffix index start)) + (defun +vertico-highlight-directory (file) + "If FILE ends with a slash, highlight it as a directory." + (if (string-suffix-p "/" file) + (propertize file 'face 'marginalia-file-priv-dir) + file)) + (defun +vertico-highlight-enabled-mode (cmd) + "If MODE is enabled, highlight it as font-lock-doc-face." + (let ((sym (intern cmd))) + (if (or (eq sym major-mode) + (and + (memq sym minor-mode-list) + (boundp sym))) + (propertize cmd 'face 'font-lock-doc-face) + cmd))) + + (setq vertico-multiform-commands + '((execute-extended-command + (+vertico-transform-functions . +vertico-highlight-enabled-mode)))) + (setq vertico-multiform-categories + '((file (+vertico-transform-functions . +vertico-highlight-directory) + (:keymap . vertico-directory-map)) + (imenu grid))) + :bind (:map vertico-multiform-map + ("M-H" . vertico-multiform-buffer-grid))) (use-extension vertico vertico-directory :config @@ -115,28 +177,28 @@ DEFS is a plist associating completion categories to commands." (let ((default-command (lookup-key vertico-map (kbd key)))) (define-key vertico-map (kbd key) - (list 'menu-item nil defs :filter - (lambda (d) - (or (plist-get d (completion-metadata-get - (completion-metadata (minibuffer-contents) - minibuffer-completion-table - minibuffer-completion-predicate) - 'category)) - default-command)))))) + (list 'menu-item nil defs :filter + (lambda (d) + (or (plist-get d (completion-metadata-get + (completion-metadata (minibuffer-contents) + minibuffer-completion-table + minibuffer-completion-predicate) + 'category)) + default-command)))))) (define-vertico-key "/" - 'file #'vertico-directory-slash - 'project-file #'vertico-directory-slash) + 'file #'vertico-directory-slash + 'project-file #'vertico-directory-slash) (define-vertico-key "RET" - 'file #'vertico-directory-enter-or-select-project - 'project-file #'vertico-directory-enter) + 'file #'vertico-directory-enter-or-select-project + 'project-file #'vertico-directory-enter) (define-vertico-key "~" - 'file #'vertico-directory-home) + 'file #'vertico-directory-home) (define-vertico-key "DEL" - 'file #'vertico-directory-delete-char - 'project-file #'vertico-directory-delete-char) + 'file #'vertico-directory-delete-char + 'project-file #'vertico-directory-delete-char) (define-vertico-key "M-DEL" - 'file #'vertico-directory-delete-word - 'project-file #'vertico-directory-delete-word) + 'file #'vertico-directory-delete-word + 'project-file #'vertico-directory-delete-word) :commands (vertico-directory-enter vertico-directory-delete-word vertico-directory-delete-char) ;; Tidy shadowed file names :hook (rfn-eshadow-update-overlay . vertico-directory-tidy)) @@ -152,21 +214,21 @@ DEFS is a plist associating completion categories to commands." (use-extension vertico vertico-indexed :config - (defmacro define-choose (n) + (defmacro define-vertico-choose (n) `(defun ,(intern (format "vertico-indexed-choose-%s" n)) () ,(format "Exit minibuffer with candidate %s." n) (interactive) - (let ((current-prefix-arg ,n)) + (let ((vertico--index ,n)) (funcall-interactively 'vertico-exit)))) - (defmacro define-insert (n) + (defmacro define-vertico-insert (n) `(defun ,(intern (format "vertico-indexed-insert-%s" n)) () ,(format "Insert candidate %s in minibuffer." n) (interactive) - (let ((current-prefix-arg ,n)) + (let ((vertico--index ,n)) (funcall-interactively 'vertico-insert)))) (dotimes (n 10) - (eval `(define-choose ,n)) - (eval `(define-insert ,n)) + (eval `(define-vertico-choose ,n)) + (eval `(define-vertico-insert ,n)) (define-key vertico-map (kbd (format "C-%s" n)) (intern (format "vertico-indexed-choose-%s" n))) (define-key vertico-map (kbd (format "M-%s" n)) (intern (format "vertico-indexed-insert-%s" n)))) (vertico-indexed-mode 1)) @@ -179,32 +241,36 @@ DEFS is a plist associating completion categories to commands." (use-package consult :bind (;; C-c bindings (mode-specific-map) ("C-c h" . consult-history) - ("C-c m" . consult-mode-command) + ("C-c M-x" . consult-mode-command) ("C-c b" . consult-bookmark) ("C-c k" . consult-kmacro) + ("C-c m" . consult-man) + ("C-c i" . consult-info) + ([remap Info-search] . consult-info) ;; C-x bindings (ctl-x-map) ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command ("C-x b" . consult-buffer) ;; orig. switch-to-buffer - ("C-x B" . consult-buffer-no-preview) ;; orig. switch-to-buffer + ("C-x B" . consult-buffer-no-preview) ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame + ("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab + ("C-x r b" . consult-bookmark) ;; orig. bookmark-jump + ("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer ;; Custom M-# bindings for fast register access ("M-#" . consult-register-load) ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated) ("C-M-#" . consult-register) ;; Other custom bindings + ("C-," . consult-line) ("C-S-s" . consult-line) - ("M-*" . consult-line-thing-at-point) ("C-c f" . consult-recent-file) ("C-c r" . consult-ripgrep) + ("C-c ." . consult-ripgrep) ;; convenient for using with embark-act (C-. C-c . to search for thing at point) ;; TODO find an alternative to C-c c? ("C-c c r" . consult-ripgrep-auto-preview) ("C-c c s" . consult-ripgrep-case-sensitive) - ("C-c c z" . consult-z-ripgrep) - ("C-c C-*" . consult-ripgrep-thing-at-point) ("C-c C-^" . consult-ripgrep-parent) ("M-y" . consult-yank-pop) ;; orig. yank-pop - ("<help> a" . consult-apropos) ;; orig. apropos-command ;; M-g bindings (goto-map) ("M-g e" . consult-compile-error) ("M-g f" . consult-flycheck) @@ -227,41 +293,42 @@ DEFS is a plist associating completion categories to commands." ("G" . consult-git-grep) ("r" . consult-ripgrep) ("R" . consult-ripgrep) ;; can't use r in isearch-mode, so add R too - ("M-r" . consult-ripgrep-unrestricted) - ("*" . consult-ripgrep-thing-at-point) - ("z" . consult-z-ripgrep) + ("u" . consult-ripgrep-unrestricted) ("^" . consult-ripgrep-parent) ("l" . consult-line) ("L" . consult-line-multi) ("m" . consult-multi-occur) ("k" . consult-keep-lines) - ("u" . consult-focus-lines) - ("e" . consult-isearch)) + ("C-f" . consult-focus-lines) + ("e" . consult-isearch-history)) (:map vertico-map ;; These are used for previewing with some consult commands (see consult-customize call below) ("C-S-p" . vertico-previous) ("C-S-n" . vertico-next) ;; Toggle preview on/off without changing preview-key - ("M-P" . consult-toggle-preview))) + ("M-P" . consult-toggle-preview) + ("C-x C-M-x" . remove-leading-hash))) :config - ;; Optionally configure the register formatting. This improves the register + ;; Configure register formatting. This improves the register ;; preview for `consult-register', `consult-register-load', ;; `consult-register-store' and the Emacs built-ins. (setq register-preview-delay 0 register-preview-function #'consult-register-format) - ;; Optionally tweak the register preview window. + ;; Tweak the register preview window. ;; This adds thin lines, sorting and hides the mode line of the window. (advice-add #'register-preview :override #'consult-register-window) - ;; Use Consult to select xref locations with preview - (setq xref-show-xrefs-function #'consult-xref - xref-show-definitions-function #'consult-xref) - (add-to-list 'consult-mode-histories '(cider-repl-mode cider-repl-input-history)) + (defvar consult-line-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-s" #'previous-history-element) + map)) + (consult-customize consult-line :keymap consult-line-map) + (defun consult-ripgrep-auto-preview (&optional dir initial) (interactive "P") (consult-ripgrep dir initial)) @@ -269,10 +336,6 @@ DEFS is a plist associating completion categories to commands." (interactive "P") (let ((consult-ripgrep-args (replace-regexp-in-string "\\." "-uu ." consult-ripgrep-args))) (consult-ripgrep dir initial))) - (defun consult-z-ripgrep (&optional dir initial) - (interactive "P") - (let ((consult-ripgrep-args (replace-regexp-in-string "\\." "-z ." consult-ripgrep-args))) - (consult-ripgrep dir initial))) (defun consult-ripgrep-case-sensitive (&optional dir initial) (interactive "P") (let ((consult-ripgrep-args (replace-regexp-in-string "\\." "-s ." consult-ripgrep-args))) @@ -282,25 +345,19 @@ DEFS is a plist associating completion categories to commands." (consult-buffer)) (defun consult-ripgrep-parent (&optional initial) (interactive "P") - (consult-ripgrep (file-name-directory (directory-file-name (persp-current-project-root))) initial)) - - (defalias 'consult-line-thing-at-point 'consult-line) - (defalias 'consult-ripgrep-thing-at-point 'consult-ripgrep) + (consult-ripgrep (file-name-directory + (directory-file-name (or (persp-current-project-root) default-directory))) + initial)) (consult-customize consult-theme :preview-key '(:debounce 0.2 any) ;; For these commands we can use C-N/C-P to scroll and preview, or M-. to preview consult-git-grep consult-grep - consult-ripgrep-parent consult-ripgrep consult-ripgrep-case-sensitive - consult-ripgrep-unrestricted consult-z-ripgrep consult-ripgrep-thing-at-point + consult-ripgrep-parent consult-ripgrep consult-ripgrep-case-sensitive consult-ripgrep-unrestricted consult-bookmark consult-recent-file consult-xref consult-buffer-no-preview - consult--source-recent-file consult--source-project-recent-file consult--source-bookmark - :preview-key '("M-." :debounce 0.2 "C-S-n" :debounce 0.2 "C-S-p") - consult-ripgrep-thing-at-point - :initial (concat "#" (thing-at-point 'symbol)) - consult-line-thing-at-point - :initial (thing-at-point 'symbol)) + consult--source-recent-file consult--source-project-recent-file consult--source-bookmark; + :preview-key '("M-." :debounce 0.2 "C-S-n" :debounce 0.2 "C-S-p")) (defvar-local consult-toggle-preview-orig nil) (defun consult-toggle-preview () @@ -398,12 +455,46 @@ DEFS is a plist associating completion categories to commands." (format "fd --color never -t f -0 . %s" root)) "\0" t)))))))) + (defun remove-leading-hash () + "Remove a # character from the beginning of the current line. + +Designed to be used for consult commands that automatically add a # at the beginning of the minibuffer. +See `+become' and the functions that call it (e.g. `+become-consult-line')." + (interactive) + (save-excursion + (beginning-of-line) + (when (= ?# (char-after)) + (delete-forward-char 1)))) + (defun consult-project-buffer () + "Version of `consult-buffer' that only uses project-related sources." (interactive) (let ((consult-buffer-sources '(consult--project-source-project-buffer consult--project-source-project-file-recentf consult--project-source-project-file-all))) - (consult-buffer)))) + (consult-buffer))) + + ;; https://takeonrules.com/2024/06/08/adding-a-consult-function-for-visualizing-xref/ + (defvar consult--xref-history nil + "History for the `consult-recent-xref' results.") + (defun consult-recent-xref (&optional markers) + "Jump to a marker in MARKERS list (defaults to `xref--history'. + +The command supports preview of the currently selected marker position. +The symbol at point is added to the future history." + (interactive) + (consult--read + (consult--global-mark-candidates + (or markers (flatten-list xref--history))) + :prompt "Go to Xref: " + :annotate (consult--line-prefix) + :category 'consult-location + :sort nil + :require-match t + :lookup #'consult--lookup-location + :history '(:input consult--xref-history) + :add-history (thing-at-point 'symbol) + :state (consult--jump-state)))) (use-package consult-flycheck) @@ -424,6 +515,9 @@ DEFS is a plist associating completion categories to commands." (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 @@ -435,19 +529,38 @@ DEFS is a plist associating completion categories to commands." (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) (:map minibuffer-local-map ("M-." . embark-preview) - ("C-," . embark-become)) + ("C-," . embark-become) + ("C-^" . embark-become-ripgrep-parent) + ("C-S-SPC" . embark-select)) (:map embark-become-file+buffer-map ("e" . consult-project-extra-find) ("E" . project-switch-consult-project-extra-find))) :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." + (interactive) + (progn + (when current-prefix-arg + (sp-backward-up-sexp current-prefix-arg)) + (sp-beginning-of-sexp) + (embark-dwim))) + (defalias 'embark-become-ripgrep-parent (kmacro "C-, ^")) (defun embark-preview () "Previews candidate in vertico buffer, unless it's a consult command" (interactive) @@ -467,10 +580,31 @@ DEFS is a plist associating completion categories to commands." ;; demand, combined with after means that this will load after embark and consult ;; See https://github.com/oantolin/embark/commit/47daded610b245caf01a97d74c940aff91fe14e2#r46010972 :demand t + :config + (defun +become (fn) + "Remove the leading # from the minibuffer, and call `FN'. +Useful with embark-become, when changing from a command that uses # as a separator, to one that doesn't." + (interactive) + (setq unread-command-events (listify-key-sequence "\C-x\C-\M-x")) + (funcall-interactively fn)) + (defun +become-consult-line () + "A version of `consult-line', designed for use with `embark-become'. +The leading # added by other consult commands is removed." + (interactive) + (+become #'consult-line)) + (defun +become-consult-line () + "A version of `consult-imenu', designed for use with `embark-become'. +The leading # added by other consult commands is removed." + (interactive) + (+become #'consult-imenu)) :bind (:map embark-consult-async-search-map + ("l" . +become-consult-line) + ("f" . consult-focus-lines) + ("i" . +become-consult-imenu) ("^" . consult-ripgrep-parent) - ("R" . consult-ripgrep-unrestricted)) + ("u" . consult-ripgrep-unrestricted) + ("c" . consult-ripgrep-case-sensitive)) :hook (embark-collect-mode . consult-preview-at-point-mode)) diff --git a/.emacs.d/lisp/init-misc.el b/.emacs.d/lisp/init-misc.el index d71c646..82c4264 100644 --- a/.emacs.d/lisp/init-misc.el +++ b/.emacs.d/lisp/init-misc.el @@ -44,8 +44,27 @@ (cdar restclient-saved-requests) (alist-get (completing-read "Call: " (map-keys restclient-saved-requests)) restclient-saved-requests nil nil 'string-equal)))) (apply 'restclient-http-do args)))) + + ;; https://github.com/pashky/restclient.el/issues/288#issuecomment-1775770753 + (defun my/restclient-copy-curl-command () + "Formats the request as a curl command and copies the command to the clipboard." + (interactive) + (restclient-http-parse-current-and-do + '(lambda (method url headers entity) + (let* ((header-args + (apply 'append + (mapcar (lambda (header) + (list "-H" (format "\"%s: %s\"" (car header) (cdr header)))) + headers))) + (header-parsed (mapconcat 'identity header-args " ")) + (method-arg (concat "-X" " " method)) + (entity-arg (if (> 0 (string-width entity)) "" + (format "-d \x27%s\x27" entity))) + (curl-command (format "curl %s %s %s %s" header-parsed method-arg url entity-arg))) + (kill-new curl-command) + (message "curl command copied to clipboard."))))) :bind - ("C-c C-h" . restclient-call-saved-request) + ("C-c M-h" . restclient-call-saved-request) (:map restclient-mode-map ("C-c h" . restclient-save-current)) :mode (("\\.http\\'" . restclient-mode))) @@ -61,8 +80,9 @@ (use-package csv-mode :bind (:map csv-mode-map - ("M-]" . csv-forward-field) - ("M-[" . csv-backward-field))) + ;; TODO find something less awkward + ("C-M-)" . csv-forward-field) + ("C-M-(" . csv-backward-field))) (use-package yaml-mode :diminish diff --git a/.emacs.d/lisp/init-navigation.el b/.emacs.d/lisp/init-navigation.el index 513d580..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) @@ -17,14 +24,14 @@ (select-window (cdr (ring-ref avy-ring 0)))) t) - (add-to-list 'avy-dispatch-alist '(111 . avy-action-embark)) + (add-to-list 'avy-dispatch-alist '(?o . avy-action-embark)) (defun avy-copy-as-kill () (interactive) (avy-goto-char-timer) (let ((beg (point))) (avy-goto-char-timer) (copy-region-as-kill beg (point)))) - (defun avy-kill-in-line () + (defun avy-copy-as-kill-in-line () (interactive) (avy-goto-char-timer) (let ((beg (point))) @@ -33,12 +40,12 @@ :bind ("C-'" . avy-goto-char-timer) ("C-;" . avy-goto-char-in-line) + ("C-#" . avy-goto-word-1) ("C-c C-'" . avy-copy-as-kill) ("C-c C-;" . avy-copy-as-kill-in-line)) (use-package casual-avy - :ensure t - :bind ("C-M-;" . casual-avy-tmenu)) + :bind ([control-bracketleft] . casual-avy-tmenu)) (use-package smartscan :custom (smartscan-symbol-selector "symbol") @@ -72,7 +79,8 @@ Or remove all highlighted symbols in the current buffer (with`ARG')." :bind ("C-c o" . symbol-overlay-put-or-clear) ("M-N" . symbol-overlay-switch-forward) - ("M-P" . symbol-overlay-switch-backward)) + ("M-P" . symbol-overlay-switch-backward) + (:map symbol-overlay-map ("o" . symbol-overlay-put-or-clear))) (use-package gumshoe :after perspective @@ -85,16 +93,7 @@ Or remove all highlighted symbols in the current buffer (with`ARG')." (gumshoe-slot-schema '(perspective time buffer position line)) :config (global-gumshoe-mode +1) - (defvar gumshoe-repeat-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "}") #'global-gumshoe-backtracking-mode-forward) - (define-key map (kbd "{") #'global-gumshoe-backtracking-mode-back) - map)) - (dolist (cmd '(global-gumshoe-backtracking-mode-forward global-gumshoe-backtracking-mode-back)) - (put cmd 'repeat-map 'gumshoe-repeat-map)) :bind - ("C-c }" . global-gumshoe-backtracking-mode-forward) - ("C-c {" . global-gumshoe-backtracking-mode-back) ("C-c '" . gumshoe-peruse-in-persp)) (use-package goto-chg diff --git a/.emacs.d/lisp/init-nix.el b/.emacs.d/lisp/init-nix.el index b4cf0fe..c92ef0b 100644 --- a/.emacs.d/lisp/init-nix.el +++ b/.emacs.d/lisp/init-nix.el @@ -5,6 +5,9 @@ (use-package nix-mode :commands nix-repl-show) +(use-package nixfmt + :hook (nix-mode . nixfmt-on-save-mode)) + (use-package nix-update :commands nix-update-fetch) diff --git a/.emacs.d/lisp/init-packages.el b/.emacs.d/lisp/init-packages.el index 48080d8..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.7) +(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,27 +18,27 @@ (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" - ,@(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))) + (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"))) + (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 @@ -118,6 +118,52 @@ ;; https://github.com/progfolio/elpaca/wiki/Logging#customizing-the-position-of-the-elpaca-log-buffer (add-to-list 'display-buffer-alist '("\\*elpaca-log\\*" (display-buffer-reuse-window display-buffer-at-bottom))) +;; https://github.com/progfolio/elpaca/wiki/Reloading-a-package%E2%80%99s-features-after-updating-a-package +(defun +elpaca-reload-package (package &optional allp) + "Reload PACKAGE's features. +If ALLP is non-nil (interactively, with prefix), load all of its +features; otherwise only load ones that were already loaded. + +This is useful to reload a package after upgrading it. Since a +package may provide multiple features, to reload it properly +would require either restarting Emacs or manually unloading and +reloading each loaded feature. This automates that process. + +Note that this unloads all of the package's symbols before +reloading. Any data stored in those symbols will be lost, so if +the package would normally save that data, e.g. when a mode is +deactivated or when Emacs exits, the user should do so before +using this command." + (interactive + (list (let ((elpaca-overriding-prompt "Reload package: ")) + (elpaca--read-queued)) + current-prefix-arg)) + ;; This finds features in the currently installed version of PACKAGE, so if + ;; it provided other features in an older version, those are not unloaded. + (when (yes-or-no-p (format "Unload all of %s's symbols and reload its features? " package)) + (let* ((package-name (symbol-name package)) + (package-dir (file-name-directory + (locate-file package-name load-path (get-load-suffixes)))) + (package-files (directory-files package-dir 'full (rx ".el" eos))) + (package-features + (cl-loop for file in package-files + when (with-temp-buffer + (insert-file-contents file) + (when (re-search-forward (rx bol "(provide" (1+ space)) nil t) + (goto-char (match-beginning 0)) + (cadadr (read (current-buffer))))) + collect it))) + (unless allp + (setf package-features (seq-intersection package-features features))) + (dolist (feature package-features) + (ignore-errors + ;; Ignore error in case it's not loaded. + (unload-feature feature 'force))) + (dolist (feature package-features) + (require feature)) + (when package-features + (message "Reloaded: %s" (mapconcat #'symbol-name package-features " ")))))) + ;; 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 3e847da..e66a4cd 100644 --- a/.emacs.d/lisp/init-project.el +++ b/.emacs.d/lisp/init-project.el @@ -5,16 +5,17 @@ (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)) (project-test-file (replace-regexp-in-string "\.clj$" "_test.clj" - (replace-regexp-in-string "^src/" "test/" project-src-file)))) + (replace-regexp-in-string "^src/" "test/" project-src-file)))) (find-file (expand-file-name project-test-file project-root)))) (defun project--clojure-switch-to-src (test-filename project-root) (let* ((project-test-file (string-remove-prefix project-root test-filename)) (project-src-file (replace-regexp-in-string "_test\.clj$" ".clj" - (replace-regexp-in-string "^test/" "src/" project-test-file)))) + (replace-regexp-in-string "^test/" "src/" project-test-file)))) (find-file (expand-file-name project-src-file project-root)))) (defun project-clojure-test-switch () (interactive) @@ -28,14 +29,18 @@ "Show a list of recently visited files in a project." (interactive) (if (boundp 'recentf-list) + ;; Use expand-file-name for project-root and later recentf-list to ensure consistency (let* ((project-root (expand-file-name (project-root (project-current)))) (project-recentf-files (mapcar (lambda (f) (file-relative-name f project-root)) - (seq-filter (apply-partially 'string-prefix-p project-root) recentf-list)))) + (seq-filter (apply-partially 'string-prefix-p project-root) + (mapcar 'expand-file-name recentf-list))))) (find-file (expand-file-name (funcall project-read-file-name-function "Find recent project files" - project-recentf-files) + project-recentf-files + nil + 'file-name-history) project-root))) (message "recentf is not enabled"))) (defun project-switch-src-project () @@ -136,7 +141,7 @@ mode as the current buffer (or do nothing)." :bind ("C-x p p" . switch-project) - ("C-c C-M-j" . persp-switch-to-previous-buffer) + ("C-c C-M-b" . persp-switch-to-previous-buffer) ("C-x C-b" . persp-previous-buffer-same-mode) ("C-x 4 C-b" . persp-previous-buffer-same-mode-other-window) ("C-x C-S-b" . persp-switch-buffer-same-mode) diff --git a/.emacs.d/lisp/init-search.el b/.emacs.d/lisp/init-search.el index cdb8d4d..f82d527 100644 --- a/.emacs.d/lisp/init-search.el +++ b/.emacs.d/lisp/init-search.el @@ -15,95 +15,6 @@ (goto-char (point-min))) (advice-add 'isearch-occur :after 'isearch-occur-advice) - ;; Modified from http://yummymelon.com/devnull/improving-emacs-isearch-usability-with-transient.html - (transient-define-prefix isearch-menu () - "isearch Menu" - [["Edit Search String" - ("e" - "Edit the search string (recursive)" - isearch-edit-string - :transient nil) - ("w" - "Pull next word or character word from buffer" - isearch-yank-word-or-char - :transient nil) - ("s" - "Pull next symbol or character from buffer" - isearch-yank-symbol-or-char - :transient nil) - ("l" - "Pull rest of line from buffer" - isearch-yank-line - :transient nil) - ("y" - "Pull string from kill ring" - isearch-yank-kill - :transient nil) - ("t" - "Pull thing from buffer" - isearch-forward-thing-at-point - :transient nil)] - - ["Replace" - ("q" - "Start ‘query-replace’" - anzu-isearch-query-replace - :if-nil buffer-read-only - :transient nil) - ("x" - "Start ‘query-replace-regexp’" - anzu-isearch-query-replace-regexp - :if-nil buffer-read-only - :transient nil)]] - - [["Toggle" - ("X" - "Toggle regexp searching" - isearch-toggle-regexp - :transient nil) - ("S" - "Toggle symbol searching" - isearch-toggle-symbol - :transient nil) - ("W" - "Toggle word searching" - isearch-toggle-word - :transient nil) - ("F" - "Toggle case fold" - isearch-toggle-case-fold - :transient nil) - ("L" - "Toggle lax whitespace" - isearch-toggle-lax-whitespace - :transient nil)] - - ["Misc" - ("o" - "occur" - isearch-occur - :transient nil) - ("h" - "highlight" - isearch-highlight-regexp - :transient nil) - ("H" - "highlight lines" - isearch-highlight-lines-matching-regexp - :transient nil) - ("l" - "consult-line" - consult-line - :transient nil) - ("<" - "isearch-beginning-of-buffer" - isearch-beginning-of-buffer - :transient nil) - (">" - "isearch-end-of-buffer" - isearch-end-of-buffer - :transient nil)]]) - :custom (search-whitespace-regexp ".*\\b") (isearch-lax-whitespace t) @@ -112,16 +23,25 @@ (isearch-lazy-count t) (lazy-count-prefix-format nil) (lazy-count-suffix-format " (%s/%s)") + (lazy-highlight-initial-delay 0) (isearch-message-properties '(read-only t cursor-intangible t face isearch-prompt)) :bind-keymap ("C-c s" . search-map) ;; M-s clashes with paredit/smartparens bindings :bind - ("C-*" . isearch-forward-symbol-at-point) - (:map isearch-mode-map ("<f2>" . isearch-menu)) (:map search-map - ("M-s M-<" . isearch-beginning-of-buffer) - ("M-s M->" . isearch-end-of-buffer) - ("C-c s M-<" . isearch-beginning-of-buffer) - ("C-c s M->" . isearch-end-of-buffer))) + ("<" . isearch-beginning-of-buffer) + (">" . isearch-end-of-buffer))) + +(use-feature casual-isearch + :after isearch + :bind (:map isearch-mode-map ("C-o" . casual-isearch-tmenu)) + :config + ;; Replace isearch-query-replace functions with their aznu equivalents + (transient-replace-suffix 'casual-isearch-tmenu "r" '("r" "Start ‘anzu-query-replace’" anzu-isearch-query-replace + :if-nil buffer-read-only)) + (transient-replace-suffix 'casual-isearch-tmenu "x" '("x" "Start ‘anzu-query-replace-regexp’" anzu-isearch-query-replace-regexp + :if-nil buffer-read-only)) + ;; Add consult-line to Misc section + (transient-append-suffix 'casual-isearch-tmenu "u" '("l" "consult-line" consult-line))) (use-package isearch-dabbrev :after isearch @@ -153,63 +73,57 @@ (use-package deadgrep :config - (defun deadgrep-symbol-at-point () - (interactive) - (deadgrep (thing-at-point 'symbol))) (defun deadgrep-current-directory (search-term) (interactive (list (deadgrep--read-search-term))) (deadgrep search-term (file-name-directory buffer-file-name))) - (defvar include-all nil) + (defvar deadgrep--include-all nil) (defun deadgrep--include-all-advice (rg-args) - (if include-all + (if deadgrep--include-all (push "-uuuLz" rg-args) rg-args)) (advice-add 'deadgrep--arguments :filter-return #'deadgrep--include-all-advice) (defun deadgrep-all (search-term) (interactive (list (deadgrep--read-search-term))) - (let ((include-all t)) + (let ((deadgrep--include-all t)) (deadgrep search-term))) + :hook (deadgrep-mode . next-error-follow-minor-mode) :bind ("C-c c d" . deadgrep) ("C-c c M-d" . deadgrep-all) - ("C-S-z" . deadgrep-symbol-at-point) ("C-c c C-d" . deadgrep-current-directory) + (:map deadgrep-mode-map + ("e" . deadgrep-edit-mode) + ("{" . deadgrep-backward-filename) + ("}" . deadgrep-forward-filename)) (:map search-map ("d" . deadgrep) ("M-d" . deadgrep-all) - ("C-d" . deadgrep-current-directory) - ("D" . deadgrep-symbol-at-point))) + ("C-d" . deadgrep-current-directory))) (use-package affe :config (setq affe-grep-command (replace-regexp-in-string "rg" "rg -Suu" affe-grep-command)) ;; Configure Orderless (defun affe-orderless-regexp-compiler (input _type _ignorecase) - (setq input (orderless-pattern-compiler input)) + (setq input (cdr (orderless-compile input))) (cons input (apply-partially #'orderless--highlight input t))) (setq affe-regexp-compiler #'affe-orderless-regexp-compiler) - ;; Manual preview key for `affe-grep' - (consult-customize affe-grep :preview-key (kbd "M-.")) - (defun my/affe-grep-symbol-at-point (&optional dir initial) - (interactive - (list prefix-arg (when-let ((s (symbol-at-point))) - (symbol-name s)))) - (affe-grep dir initial)) - (defun my/affe-find-symbol-at-point (&optional dir initial) - (interactive - (list prefix-arg (when-let ((s (symbol-at-point))) - (symbol-name s)))) - (affe-find dir initial)) + (defalias 'affe-grep-symbol-at-point 'affe-grep) + (defalias 'affe-find-symbol-at-point 'affe-find) + (consult-customize + affe-grep :preview-key "M-." + affe-grep-symbol-at-point :initial (thing-at-point 'symbol) :preview-key "M-." + affe-find-symbol-at-point :initial (thing-at-point 'symbol) :preview-key "M-.") :bind - ("C-#" . affe-grep) + ("C-c C-#" . affe-grep) ("C-c z" . affe-find) - ("C-c Z" . my/affe-find-symbol-at-point) - ("C-~" . my/affe-grep-symbol-at-point) + ("C-c Z" . affe-find-symbol-at-point) + ("C-c C-~" . affe-grep-symbol-at-point) (:map search-map ("#" . affe-grep) - ("~" . my/affe-grep-symbol-at-point) + ("~" . affe-grep-symbol-at-point) ("a" . affe-find) - ("A" . my/affe-find-symbol-at-point))) + ("A" . affe-find-symbol-at-point))) (provide 'init-search) ;;; init-search.el ends here diff --git a/.emacs.d/lisp/init-shell.el b/.emacs.d/lisp/init-shell.el index 4a03b27..bf737cb 100644 --- a/.emacs.d/lisp/init-shell.el +++ b/.emacs.d/lisp/init-shell.el @@ -9,6 +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 + (lambda () + (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 d71e73d..cf3a89a 100644 --- a/.emacs.d/lisp/init-sql.el +++ b/.emacs.d/lisp/init-sql.el @@ -37,7 +37,7 @@ (format "SQL history will not be saved because %s is nil" (symbol-name rval)))))) - (add-hook 'sql-interactive-mode-hook 'my-sql-save-history-hook)) + :hook (sql-interactive-mode . my-sql-save-history-hook)) (use-package sqlup-mode @@ -46,9 +46,10 @@ :hook (sql-mode . sqlup-mode) (sql-interactive-mode . sqlup-mode) - :bind ("C-c c u" . sqlup-capitalize-keywords-in-region)) + :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 0c12934..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")) @@ -16,37 +18,11 @@ (global-display-line-numbers-mode) (global-hl-line-mode +1) - (global-set-key (kbd "C-x C-S-k") 'kill-this-buffer) - (add-to-list 'custom-theme-load-path "~/.emacs.d/themes") (load-theme 'non-modo t))) - ;; http://yummymelon.com/devnull/enhancing-navigation-in-emacs-view-mode.html - (view-mode . (lambda () - (cond ((derived-mode-p 'org-mode) - (define-key view-mode-map (kbd "p") 'org-previous-visible-heading) - (define-key view-mode-map (kbd "n") 'org-next-visible-heading)) - ((derived-mode-p 'markdown-mode) - (define-key view-mode-map (kbd "p") 'markdown-outline-previous) - (define-key view-mode-map (kbd "n") 'markdown-outline-next)) - ((derived-mode-p 'html-mode) - (define-key view-mode-map (kbd "p") 'sgml-skip-tag-backward) - (define-key view-mode-map (kbd "n") 'sgml-skip-tag-forward)) - ((derived-mode-p 'emacs-lisp-mode) - (define-key view-mode-map (kbd "p") 'backward-sexp) - (define-key view-mode-map (kbd "n") 'forward-sexp)) - ((derived-mode-p 'clojure-mode) - (define-key view-mode-map (kbd "p") 'backward-sexp) - (define-key view-mode-map (kbd "n") 'forward-sexp)) - ((derived-mode-p 'makefile-mode) - (define-key view-mode-map (kbd "p") 'makefile-previous-dependency) - (define-key view-mode-map (kbd "n") 'makefile-next-dependency)) - ((derived-mode-p 'c-mode) - (define-key view-mode-map (kbd "p") 'c-beginning-of-defun) - (define-key view-mode-map (kbd "n") 'c-end-of-defun)) - (t - (define-key view-mode-map (kbd "p") 'scroll-down-command) - (define-key view-mode-map (kbd "n") 'scroll-up-command))))) + :bind ("C-x C-S-k" . kill-buffer) :config + (setq-default display-line-numbers-widen t) ;; https://github.com/rougier/elegant-emacs/blob/master/sanity.el (setq inhibit-startup-screen t inhibit-startup-echo-area-message t @@ -65,13 +41,22 @@ (run-with-timer 0.05 nil 'invert-face 'mode-line)) visible-bell t) - ;; TODO do we want these? (copied from prelude) + ;; A combination of settings from prelude and minimal-emacs.d, may need tweaking (setq scroll-margin 0 scroll-conservatively 100000 - scroll-preserve-screen-position 1) + scroll-preserve-screen-position 1 + hscroll-margin 2 + hscroll-step 1 + auto-window-vscroll nil) (setq pixel-scroll-precision-mode t) + (setq-default word-wrap t + truncate-lines t + fill-column 80) + ;; If enabled and `truncate-lines' is disabled, soft wrapping will not occur + ;; when the window is narrower than `truncate-partial-width-windows' characters. + (setq truncate-partial-width-windows nil) - (fset 'yes-or-no-p 'y-or-n-p) + (setq use-short-answers t) (setq frame-title-format '("Emacs: " (:eval (if (buffer-file-name) @@ -79,9 +64,41 @@ "%b")))) (when (eq system-type 'darwin) - (setq mac-option-modifier 'meta) - (setq mac-right-option-modifier 'none) - (setq mac-command-modifier 'super))) + (setq mac-option-modifier 'meta + mac-right-option-modifier 'none) + ;; After swapping control and command, this works nicely, + ;; otherwise use (setq mac-command-modifier 'super) + (setq mac-command-modifier 'control + mac-control-modifier 'super))) + +(use-feature view + ;; http://yummymelon.com/devnull/enhancing-navigation-in-emacs-view-mode.html + :hook + (view-mode . (lambda () + (cond ((derived-mode-p 'org-mode) + (define-key view-mode-map (kbd "p") 'org-previous-visible-heading) + (define-key view-mode-map (kbd "n") 'org-next-visible-heading)) + ((derived-mode-p 'markdown-mode) + (define-key view-mode-map (kbd "p") 'markdown-outline-previous) + (define-key view-mode-map (kbd "n") 'markdown-outline-next)) + ((derived-mode-p 'html-mode) + (define-key view-mode-map (kbd "p") 'sgml-skip-tag-backward) + (define-key view-mode-map (kbd "n") 'sgml-skip-tag-forward)) + ((derived-mode-p 'emacs-lisp-mode) + (define-key view-mode-map (kbd "p") 'backward-sexp) + (define-key view-mode-map (kbd "n") 'forward-sexp)) + ((derived-mode-p 'clojure-mode) + (define-key view-mode-map (kbd "p") 'backward-sexp) + (define-key view-mode-map (kbd "n") 'forward-sexp)) + ((derived-mode-p 'makefile-mode) + (define-key view-mode-map (kbd "p") 'makefile-previous-dependency) + (define-key view-mode-map (kbd "n") 'makefile-next-dependency)) + ((derived-mode-p 'c-mode) + (define-key view-mode-map (kbd "p") 'c-beginning-of-defun) + (define-key view-mode-map (kbd "n") 'c-end-of-defun)) + (t + (define-key view-mode-map (kbd "p") 'scroll-down-command) + (define-key view-mode-map (kbd "n") 'scroll-up-command)))))) (use-package hl-todo :bind @@ -116,7 +133,7 @@ (dolist (mode whitespace-disabled-modes) (add-hook (intern (concat (symbol-name mode) "-hook")) #'turn-off-whitespace-mode)) :hook - ((text-mode prog-mode) . (lambda () (whitespace-mode +1)))) + ((text-mode prog-mode) . whitespace-mode)) (use-package goggles :diminish @@ -131,6 +148,9 @@ :hook (prog-mode . idle-highlight-mode)) (use-feature paren + :custom + (show-paren-when-point-inside-paren t) + (show-paren-when-point-in-periphery t) :config (show-paren-mode +1)) @@ -194,6 +214,9 @@ ;; Run setup hook for `eval-expression' (calls `eldoc--eval-expression-setup') (run-hooks 'eval-expression-minibuffer-setup-hook) + (mono-complete-mode +1) + (setq-local mono-complete-fallback-command 'dabbrev-expand) + ;; smartparens, but don't insert pairs of ' (smartparens-strict-mode) (setq-local sp-pair-list (assoc-delete-all "'" sp-pair-list)) @@ -217,5 +240,8 @@ (set-face-foreground 'highlight-indent-guides-character-face "grey25") :hook ((prog-mode text-mode conf-mode) . highlight-indent-guides-mode)) +;; Main causal collection package; the individual packages are configured in the appropriate places +(use-package casual) + (provide 'init-ui) ;;; init-ui.el ends here diff --git a/.emacs.d/lisp/init-windows.el b/.emacs.d/lisp/init-windows.el index 2bf54a3..15ec232 100644 --- a/.emacs.d/lisp/init-windows.el +++ b/.emacs.d/lisp/init-windows.el @@ -5,38 +5,30 @@ (use-feature emacs :custom (switch-to-buffer-obey-display-actions t) + (split-height-threshold nil) + (split-width-threshold 200)) + +(use-feature ibuffer :bind - ("C-x C-M-b" . ibuffer) - :config - ;; From EmacsWiki - (defun toggle-window-split () - (interactive) - (if (= (count-windows) 2) - (let* ((this-win-buffer (window-buffer)) - (next-win-buffer (window-buffer (next-window))) - (this-win-edges (window-edges (selected-window))) - (next-win-edges (window-edges (next-window))) - (this-win-2nd (not (and (<= (car this-win-edges) - (car next-win-edges)) - (<= (cadr this-win-edges) - (cadr next-win-edges))))) - (splitter - (if (= (car this-win-edges) - (car (window-edges (next-window)))) - 'split-window-horizontally - 'split-window-vertically))) - (delete-other-windows) - (let ((first-win (selected-window))) - (funcall splitter) - (if this-win-2nd (other-window 1)) - (set-window-buffer (selected-window) this-win-buffer) - (set-window-buffer (next-window) next-win-buffer) - (select-window first-win) - (if this-win-2nd (other-window 1)))))) - (define-key ctl-x-4-map "t" 'toggle-window-split)) + ("C-x M-b" . ibuffer) + (:map ibuffer-mode-map + ("{" . ibuffer-backwards-next-marked) + ("}" . ibuffer-forward-next-marked) + ("[" . ibuffer-backward-filter-group) + ("]" . ibuffer-forward-filter-group) + ("$" . ibuffer-toggle-filter-group)) + :hook (ibuffer-mode . ibuffer-auto-mode)) + +(use-feature casual-ibuffer + :after ibuffer + :bind (:map ibuffer-mode-map + ("C-o" . casual-ibuffer-tmenu) + ("F" . casual-ibuffer-filter-tmenu) + ("s" . casual-ibuffer-sortby-tmenu))) (use-feature winner :defer 5 + :custom (winner-boring-buffers-regexp "\*Minibuf-[0-9]+") :config (winner-mode +1) (defvar winner-repeat-map @@ -49,7 +41,11 @@ (use-feature windmove :defer 5 - :config (windmove-default-keybindings)) + :config (windmove-default-keybindings) + :bind (("C-c M-<up>" . windmove-delete-up) + ("C-c M-<down>" . windmove-delete-down) + ("C-c M-<left>" . windmove-delete-left) + ("C-c M-<right>" . windmove-delete-right))) (use-package buffer-move :bind (("C-S-<up>" . buf-move-up) @@ -68,6 +64,9 @@ (fullframe vc-annotate quit-window) (fullframe elpaca-fetch-all quit-window)) +(use-package transpose-frame + :bind (:map ctl-x-4-map ("t" . transpose-frame))) + (use-package ace-window :diminish :config @@ -91,6 +90,7 @@ ("M-¬" . popper-cycle) ("C-`" . popper-toggle-type)) :custom + (popper-group-function #'popper-group-by-perspective) (popper-reference-buffers '("\\*Messages\\*" "\\*HTTP Response\\*" @@ -142,7 +142,7 @@ ("P" "[project]" frog-jump-buffer-filter-same-project) ("S" "[similar]" frog-jump-buffer-filter-similar-name))) :bind - ("C-," . frog-jump-buffer) + ("C-c C-," . frog-jump-buffer) ("C-x 4 C-," . frog-jump-buffer-other-window)) (use-package buffer-ring @@ -180,9 +180,6 @@ (or (apply orig args) (persp-buffer-filter (car args)))) (advice-add 'buffer-flip-skip-buffer :around 'persp-buffer-flip-skip-buffer) - ;; (defun persp-buffer-flip-skip-buffer (orig-val &rest args) - ;; (or orig-val (persp-buffer-filter (car args)))) - ;; (advice-add 'buffer-flip-skip-buffer :filter-return 'persp-buffer-flip-skip-buffer) :bind (("C-c C-<left>" . buffer-flip) (:map buffer-flip-map ( "C-<left>" . buffer-flip-forward) @@ -194,15 +191,25 @@ (defun iflipb-persp-buffer-list () "Buffer list for iflipb." (seq-filter 'buffer-live-p (persp-current-buffers* t))) - (dolist (cmd '(iflipb-previous-buffer iflipb-next-buffer)) - (put cmd 'repeat-map 'iflipb-repeat-map)) (defun iflibp-abort () "Abort buffer flipping and return to the original buffer." (interactive) (iflipb-restore-buffers)) + (defun iflipb-kill-current-buffer () + "Same as `kill-current-buffer' but keep the iflipb buffer list state. + +Modified from `iflipb-kill-buffer'." + (interactive) + (call-interactively #'kill-current-buffer) + (if (iflipb-first-iflipb-buffer-switch-command) + (setq last-command 'kill-current-buffer) + (if (< iflipb-current-buffer-index (length (iflipb-interesting-buffers))) + (iflipb-select-buffer iflipb-current-buffer-index) + (iflipb-select-buffer (1- iflipb-current-buffer-index))) + (setq last-command 'iflipb-kill-current-buffer))) :custom (iflipb-buffer-list-function 'iflipb-persp-buffer-list) :bind - ("C-x k" . iflipb-kill-buffer) ;; TODO replace with a kill currently selected buffer command + ("C-x k" . iflipb-kill-current-buffer) ("<f12>" . iflipb-previous-buffer) ("<f11>" . iflipb-next-buffer) ("<f10>" . iflibp-abort)) diff --git a/.emacs.d/themes/non-modo-theme.el b/.emacs.d/themes/non-modo-theme.el index d6778c7..4ef4a54 100644 --- a/.emacs.d/themes/non-modo-theme.el +++ b/.emacs.d/themes/non-modo-theme.el @@ -296,6 +296,8 @@ ;;;;; corfu-quick `(corfu-quick1 ((,class :inherit bold :background "#0050af"))) `(corfu-quick2 ((,class :inherit bold :background "#7f1f7f"))) +;;;;; corfu-candidate-overlay + `(corfu-candidate-overlay-face ((t :inherit shadow))) ;;;;; cov `(cov-coverage-not-run-face ((,class :foreground "red"))) `(cov-coverage-run-face ((,class :foreground "#4fe42f"))) @@ -1165,6 +1167,8 @@ `(mode-line-emphasis ((,class :inherit bold :foreground "#d5b1ff"))) `(mode-line-highlight ((,class :inherit 'highlight))) `(mode-line-inactive ((,class :background "#1e1e1e" :foreground "#bfc0c4" :box "#3c3c3c"))) +;;;;; mono-complete + `(mono-complete-preview-face ((t :inherit shadow))) ;;;;; mpdel `(mpdel-browser-directory-face ((,class :foreground "#2fafff"))) `(mpdel-playlist-current-song-face ((,class :inherit bold :foreground "#00bcff"))) @@ -1475,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/.sops.yaml b/nix-conf/.sops.yaml new file mode 100644 index 0000000..2cb1a1e --- /dev/null +++ b/nix-conf/.sops.yaml @@ -0,0 +1,18 @@ +keys: + - &admin_djm age1w7kjp0qdgfyg9cyj5w4qc4fc9qz3w65xw2veazesfgdenqrd3ucqsc5ejv + - &server_edrahil age1tjfctwnwldmyxnu6qmeufgr9l79vyzmrs7fy58v3d0qj4x4nhqhq2gjmlp + - &server_djmuk2 age17j56andser5ddtlfunm35m25xueua4djh9glxlscfcet8865yv9s5aqvla +creation_rules: + - path_regex: edrahil/secrets\.(json|yaml)$ + key_groups: + - age: + - *server_edrahil + - *admin_djm + - path_regex: djmuk2/secrets\.(json|yaml)$ + key_groups: + - age: + - *server_djmuk2 + - path_regex: secrets\.(json|yaml)$ + key_groups: + - age: + - *admin_djm diff --git a/nix-conf/home/config.nix b/nix-conf/home/config.nix deleted file mode 100644 index 69baf10..0000000 --- a/nix-conf/home/config.nix +++ /dev/null @@ -1 +0,0 @@ -{ allowUnfree = true; } diff --git a/nix-conf/home/djmuk1.nix b/nix-conf/home/djmuk1.nix index 54b1171..d11499e 100644 --- a/nix-conf/home/djmuk1.nix +++ b/nix-conf/home/djmuk1.nix @@ -1,8 +1,6 @@ { config, pkgs, ... }: { - imports = [ - ./includes/linux-server.nix - ]; + imports = [ ./includes/linux-server.nix ]; # Let Home Manager install and manage itself. programs.home-manager.enable = true; @@ -11,7 +9,7 @@ # paths it should manage. home.username = "djm"; home.homeDirectory = "/home/djm"; - + # This value determines the Home Manager release that your # configuration is compatible with. This helps avoid breakage # when a new Home Manager release introduces backwards diff --git a/nix-conf/home/djmuk2.nix b/nix-conf/home/djmuk2.nix index b871056..576ed39 100644 --- a/nix-conf/home/djmuk2.nix +++ b/nix-conf/home/djmuk2.nix @@ -1,8 +1,6 @@ { config, pkgs, ... }: { - imports = [ - ./includes/linux-server.nix - ]; + imports = [ ./includes/linux-server.nix ]; # Let Home Manager install and manage itself. programs.home-manager.enable = true; diff --git a/nix-conf/home/edrahil.nix b/nix-conf/home/edrahil.nix index 1db7be3..9b7f2fb 100644 --- a/nix-conf/home/edrahil.nix +++ b/nix-conf/home/edrahil.nix @@ -1,6 +1,6 @@ { config, pkgs, ... }: { - imports = [ + imports = [ ./includes/linux-server.nix ./includes/irssi.nix ]; @@ -14,7 +14,7 @@ home.homeDirectory = "/home/djm"; home.sessionVariables = { - TMUX_AUTO_ATTACH=1; + TMUX_AUTO_ATTACH = 1; }; # This value determines the Home Manager release that your diff --git a/nix-conf/home/egalmoth.nix b/nix-conf/home/egalmoth.nix index 6e41320..79d29d0 100644 --- a/nix-conf/home/egalmoth.nix +++ b/nix-conf/home/egalmoth.nix @@ -1,8 +1,6 @@ { config, pkgs, ... }: { - imports = [ - ./includes/linux-dev.nix - ]; + imports = [ ./includes/linux-dev.nix ]; # Let Home Manager install and manage itself. programs.home-manager.enable = true; @@ -11,7 +9,7 @@ # paths it should manage. home.username = "djm"; home.homeDirectory = "/home/djm"; - + # This value determines the Home Manager release that your # configuration is compatible with. This helps avoid breakage # when a new Home Manager release introduces backwards diff --git a/nix-conf/home/includes/clojure.nix b/nix-conf/home/includes/clojure.nix index 3681e8b..3915ab3 100644 --- a/nix-conf/home/includes/clojure.nix +++ b/nix-conf/home/includes/clojure.nix @@ -1,18 +1,25 @@ -{ config, pkgs, lib, isDarwin, isLinux, ... }: +{ + config, + pkgs, + lib, + ... +}: let inherit (lib) optionals; in { - home.packages = with pkgs; [ - babashka - clj-kondo - clojure - clojure-lsp - jet - maven - neil - ] - ++ optionals stdenv.isDarwin [ (leiningen.override { jdk = jdk8; }) ] - ++ optionals stdenv.isLinux [ leiningen ]; + home.packages = + with pkgs; + [ + babashka + clj-kondo + clojure-lsp + emacs-lsp-booster + jet + maven + neil + ] + # TODO these are here because of the custom versions in otm.nix + # but there should be a better way + ++ optionals stdenv.isLinux [ leiningen clojure ]; } - diff --git a/nix-conf/home/includes/common.nix b/nix-conf/home/includes/common.nix index f43168a..7f88087 100644 --- a/nix-conf/home/includes/common.nix +++ b/nix-conf/home/includes/common.nix @@ -1,14 +1,47 @@ -{ config, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let hcr = pkgs.callPackage ./scripts/hm-changes-report.nix { inherit config pkgs; }; scr = pkgs.callPackage ./scripts/system-changes-report.nix { inherit config pkgs; }; - email = builtins.readFile "${config.home.homeDirectory}/email.txt"; + unstable = import <unstable> { }; in { imports = [ ./zsh.nix + <sops-nix/modules/home-manager/sops.nix> ]; + nixpkgs.config.allowUnfreePredicate = + pkg: builtins.elem (lib.getName pkg) [ "aspell-dict-en-science" ]; + + nix = { + package = pkgs.nix; + settings = { + extra-experimental-features = [ + "nix-command" + "flakes" + ]; + }; + }; + + sops = { + age.keyFile = "${config.xdg.configHome}/sops/age/keys.txt"; + defaultSopsFile = builtins.path { + path = ./secrets.yaml; + name = "home-secrets.yaml"; + }; + secrets."ssh_config/oci" = { }; + secrets."git_email_config/default" = { }; + }; + + home.sessionVariables = { + LSP_USE_PLISTS = "true"; + }; + home.packages = with pkgs; [ hcr scr @@ -17,14 +50,10 @@ in aspellDicts.en aspellDicts.en-computers aspellDicts.en-science - bat - bat-extras.batdiff - bat-extras.batgrep - bat-extras.batman - bat-extras.batwatch - bat-extras.batpipe + bandwhich bottom broot + comma curl diff-so-fancy difftastic @@ -33,7 +62,6 @@ in ea elinks entr - eza fd file fzf @@ -44,37 +72,83 @@ in inetutils ispell isync + jd-diff-patch jq libqalculate lscolors - lsd lynx mercurial - nixfmt-classic nix-info nix-prefetch-git nix-prefetch-github + nix-search nixpkgs-review nvd pass + procs + pstree + rage ripgrep rlwrap sd + shfmt + sops + ssh-to-age tealdeer tre-command + tree ugrep uni + unzip w3m + xan + yq + zip zstd + + unstable.nixfmt-rfc-style + unstable.wcurl ]; - nix = { - package = pkgs.nix; - settings = { - extra-experimental-features = [ "nix-command" "flakes" ]; + programs.bat = { + enable = true; + extraPackages = with pkgs.bat-extras; [ + batdiff + batgrep + batman + batwatch + batpipe + ]; + config = { + style = "full"; + pager = "less -RXF"; + map-syntax = [ + ".ignore:Git Ignore" + "*.jenkinsfile:Groovy" + ]; }; }; + programs.eza = { + enable = true; + git = true; + icons = "auto"; + enableBashIntegration = false; + enableZshIntegration = false; + enableFishIntegration = false; + enableIonIntegration = false; + extraOptions = [ + "--colour=auto" + "--long" + "--group-directories-first" + "--classify" + "--no-user" + "--no-time" + "--no-filesize" + "--no-permissions" + ]; + }; + programs.gpg.enable = true; programs.nix-index = { enable = true; @@ -94,20 +168,29 @@ in set pastetoggle=<F2> nmap <silent> <F3> :silent nohlsearch<CR> imap <silent> <F3> <C-o>:silent nohlsearch<CR> + nmap <silent> <F4> :silent setlocal spell spelllang=en_gb<CR> + imap <silent> <F4> <C-o>:silent setlocal spell spelllang=en_gb<CR> + nmap <silent> <F5> :silent setlocal nospell<CR> + imap <silent> <F5> <C-o>:silent setlocal nospell<CR> + nmap <silent> <F6> :silent set diffopt+=iwhite<CR> + imap <silent> <F6> <C-o>:silent set diffopt+=iwhite<CR> + nmap <silent> <F7> :silent set diffopt-=iwhite<CR> + imap <silent> <F7> <C-o>:silent set diffopt-=iwhite<CR> ''; - plugins = [ pkgs.vimPlugins.sensible - pkgs.vimPlugins.auto-pairs - pkgs.vimPlugins.ctrlp - pkgs.vimPlugins.editorconfig-vim - pkgs.vimPlugins.inkpot - pkgs.vimPlugins.molokai - pkgs.vimPlugins.surround - pkgs.vimPlugins.vim-lastplace - pkgs.vimPlugins.vim-nix - pkgs.vimPlugins.vim-pasta - pkgs.vimPlugins.vim-repeat - pkgs.vimPlugins.vim-sexp-mappings-for-regular-people - pkgs.vimPlugins.vim-sleuth + plugins = [ + pkgs.vimPlugins.sensible + pkgs.vimPlugins.auto-pairs + pkgs.vimPlugins.ctrlp + pkgs.vimPlugins.editorconfig-vim + pkgs.vimPlugins.inkpot + pkgs.vimPlugins.molokai + pkgs.vimPlugins.surround + pkgs.vimPlugins.vim-lastplace + pkgs.vimPlugins.vim-nix + pkgs.vimPlugins.vim-pasta + pkgs.vimPlugins.vim-repeat + pkgs.vimPlugins.vim-sexp-mappings-for-regular-people + pkgs.vimPlugins.vim-sleuth ]; settings = { background = "dark"; @@ -130,17 +213,19 @@ in UseKeychain yes User djm ''; - includes = [ "~/.ssh/config_local" ]; + includes = [ + "~/.ssh/config_local" + config.sops.secrets."ssh_config/oci".path + ]; matchBlocks = { "djm.ovh" = { hostname = "v.djm.ovh"; port = 2222; - dynamicForwards = [ { port = 8889; } ]; }; "devio" = { - hostname = "devio.us"; - user = "deejayem"; - port = 2222; + hostname = "devio.us"; + user = "deejayem"; + port = 2222; }; "sdf" = { hostname = "sdf.org"; @@ -155,18 +240,12 @@ in user = "deejayem"; }; "blinkenshell" = { - hostname = "ssh.blinkenshell.org"; - port = 2222; + hostname = "ssh.blinkenshell.org"; + port = 2222; }; "hashbang" = { hostname = "de1.hashbang.sh"; }; - "o1" = { - hostname = "130.162.163.108"; - }; - "o2" = { - hostname = "143.47.239.39"; - }; "tilde.institute" = { hostname = "tilde.institute"; }; @@ -182,13 +261,29 @@ in identityFile = "~/.ssh/id_ed25519"; identitiesOnly = true; }; + "hb-backup" = { + hostname = "de1.hashbang.sh"; + identityFile = "~/.ssh/hb_backup_key"; + identitiesOnly = true; + }; + "bs-backup" = { + hostname = "ssh.blinkenshell.org"; + port = 2222; + identityFile = "~/.ssh/bs_backup_key"; + identitiesOnly = true; + }; + "tt-backup" = { + hostname = "tilde.team"; + identityFile = "~/.ssh/tt_backup_key"; + identitiesOnly = true; + }; }; }; programs.git = { enable = true; userName = "David Morgan"; - userEmail = email; + includes = [ { path = config.sops.secrets."git_email_config/default".path; } ]; aliases = { # difftastic logt = "!sh -c 'GIT_EXTERNAL_DIFF=\"difft --background=dark\" git log -p --ext-diff'"; @@ -203,9 +298,9 @@ in cshow = "!git -c delta.line-numbers=false show"; cdiff = "!git -c delta.line-numbers=false diff"; # diff-so-fancy - flog = "!git -c core.pager=\"diff-so-fancy | less\" log"; # usually used with -p - fshow = "!git -c core.pager=\"diff-so-fancy | less\" show"; - fdiff = "!git -c core.pager=\"diff-so-fancy | less\" diff"; + flog = ''!git -c core.pager="diff-so-fancy | less" log''; # usually used with -p + fshow = ''!git -c core.pager="diff-so-fancy | less" show''; + fdiff = ''!git -c core.pager="diff-so-fancy | less" diff''; upstream = "!git push -u origin HEAD"; update-master = "!git fetch origin master:master"; @@ -220,13 +315,20 @@ in diff = { tool = "difftastic"; colorMoved = "default"; - elisp = { xfuncname = "^\\((((def\\S+)|use-package)\\s+\\S+)"; }; - clojure = { xfuncname = "^\\((def\\S+\\s+\\S+)"; }; + elisp = { + xfuncname = "^\\((((def\\S+)|use-package)\\s+\\S+)"; + }; + clojure = { + xfuncname = "^\\((def\\S+\\s+\\S+)"; + }; }; difftool = { prompt = false; - difftastic = { cmd = ''difft "$LOCAL" "$REMOTE"''; }; + difftastic = { + cmd = ''difft "$LOCAL" "$REMOTE"''; + }; }; + merge.conflictstyle = "diff3"; pull = { ff = "only"; rebase = false; @@ -261,5 +363,23 @@ in signByDefault = true; }; }; -} + programs.lsd = { + enable = true; + enableZshIntegration = false; # don't set aliases + settings = { + indicators = true; + #layout = "oneline"; + sorting.dir-grouping = "first"; + blocks = [ + "git" + "permission" + "user" + "group" + "size" + "date" + "name" + ]; + }; + }; +} diff --git a/nix-conf/home/includes/darwin.nix b/nix-conf/home/includes/darwin.nix index 3d81678..e85f3f9 100644 --- a/nix-conf/home/includes/darwin.nix +++ b/nix-conf/home/includes/darwin.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: with lib; let @@ -20,56 +25,120 @@ let makeWrapper ${pkgs.mopidy}/bin/mopidy $out/bin/mopidy \ --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 - ]; + imports = [ ./dev-common.nix ]; home.packages = with pkgs; [ awscli2 cacert + caddy coreutils curl diffutils - ((emacsPackagesFor emacs29-macport).emacsWithPackages(ps: [ ps.vterm ps.multi-vterm ])) + emacs-plus-with-packages findutils gh gh-dash #gnused - mopidy-with-extensions - mpdscribble - mpc-cli - mpd - mpv - ncmpcpp + #mopidy-with-extensions + #mpdscribble + #mpc-cli + #mpd + #ncmpcpp nix # on darwin we are not using nixos (duh) nodejs - nodePackages.eslint - openvpn pam-reattach pinentry_mac pgcli pgformatter - pms + #pms + poetry postgresql podman #python310Packages.sqlparse + redis sqls - vimpc + #vimpc wget ]; + nixpkgs.config.permittedInsecurePackages = [ + "emacs-mac-macport-29.1" + "emacs-mac-macport-with-packages-29.1" + ]; + nix.settings = { sandbox = true; keep-outputs = true; keep-derivations = true; }; - programs.java = { - enable = true; - #package = (pkgs.jdk8.overrideAttrs (_: { postPatch = "ln -nsf ../zulu-8.jdk/Contents/Home/man man"; })); - }; -} + programs.bat.extraPackages = with pkgs.bat-extras; [ + (prettybat.override { + withClangTools = false; + withRustFmt = false; + }) + ]; + # 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/dev-common.nix b/nix-conf/home/includes/dev-common.nix index a76eb72..92b286e 100644 --- a/nix-conf/home/includes/dev-common.nix +++ b/nix-conf/home/includes/dev-common.nix @@ -1,21 +1,33 @@ -{ config, pkgs, lib, ... }: { - + config, + pkgs, + lib, + ... +}: +let + inherit (lib) optionals; +in +{ imports = [ ./common.nix ./clojure.nix ]; - home.packages = with pkgs; [ - docker - docker-compose - docker-credential-helpers - ffmpeg - gopass-jsonapi - mpv - multimarkdown - neovim - ]; + home.packages = + with pkgs; + [ + docker + docker-compose + docker-credential-helpers + gopass-jsonapi + multimarkdown + neovim + ripgrep-all + ] + ++ optionals (!stdenv.isDarwin) [ + ffmpeg + mpv + ]; programs.tmux = { enable = true; @@ -47,28 +59,27 @@ } ]; extraConfig = '' - unbind-key R - bind-key R run-shell ' \ - tmux source-file ~/.config/tmux/tmux.conf > /dev/null; \ - tmux display-message "Sourced .config/tmux/tmux.conf!"' + unbind-key R + bind-key R run-shell ' \ + tmux source-file ~/.config/tmux/tmux.conf > /dev/null; \ + tmux display-message "Sourced .config/tmux/tmux.conf!"' - bind-key £ split-window -h + bind-key £ split-window -h - set-option -g status-bg '#666666' - set-option -g status-fg '#aaaaaa' - set-option -g status-left-length 50 - set-option -g status-right " %a, %b %d - %H:%M " + set-option -g status-bg '#666666' + set-option -g status-fg '#aaaaaa' + set-option -g status-left-length 50 + set-option -g status-right " %a, %b %d - %H:%M " - ${lib.optionalString pkgs.stdenv.isLinux '' - bind-key -T copy-mode y send-keys -X copy-pipe-and-cancel "xsel -i -p && xsel -o -p | xsel -i -b" - bind-key C-y run "xsel -o | tmux load-buffer - ; tmux paste-buffer" - ''} - ${lib.optionalString pkgs.stdenv.isDarwin '' - bind-key -T copy-mode y send-keys -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy" - bind-key C-y run "reattach-to-user-namespace pbpaste | tmux load-buffer - ; tmux paste-buffer" - ''} + ${lib.optionalString pkgs.stdenv.isLinux '' + bind-key -T copy-mode y send-keys -X copy-pipe-and-cancel "xsel -i -p && xsel -o -p | xsel -i -b" + bind-key C-y run "xsel -o | tmux load-buffer - ; tmux paste-buffer" + ''} + ${lib.optionalString pkgs.stdenv.isDarwin '' + bind-key -T copy-mode y send-keys -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy" + bind-key C-y run "reattach-to-user-namespace pbpaste | tmux load-buffer - ; tmux paste-buffer" + ''} ''; }; } - diff --git a/nix-conf/home/includes/irssi.nix b/nix-conf/home/includes/irssi.nix index e7cd92c..54bdc9b 100644 --- a/nix-conf/home/includes/irssi.nix +++ b/nix-conf/home/includes/irssi.nix @@ -1,4 +1,9 @@ -{ config, pkgs, lib, ... }: +{ + config, + pkgs, + lib, + ... +}: { programs.irssi = { @@ -41,7 +46,7 @@ extraConfig = '' settings = { core = { - real_name = "David Morgan"; + real_name = "djm"; user_name = "djm"; nick = "djm"; timestamp_format = "%H:%M:%S"; @@ -85,6 +90,7 @@ 11 = { items = ( { type = "CHANNEL"; chat_type = "IRC"; name = "#!"; tag = "hashbang"; }); }; 12 = { items = ( { type = "CHANNEL"; chat_type = "IRC"; name = "#nixos"; tag = "libera"; }); }; 13 = { items = ( { type = "CHANNEL"; chat_type = "IRC"; name = "#home-manager"; tag = "oftc"; }); }; + 14 = { items = ( { type = "CHANNEL"; chat_type = "IRC"; name = "#blinkenshell.log"; tag = "blinkenirc"; }); }; }; ''; networks = { @@ -123,7 +129,6 @@ }; channels = { ctrl-c.autoJoin = true; - emacs.autoJoin = true; institute.autoJoin = true; meta.autoJoin = true; team.autoJoin = true; @@ -147,7 +152,11 @@ }; blinkenirc = { nick = "djm"; - autoCommands = [ "msg chanserv invite #blinkenshell.op" "wait 2000" ]; + autoCommands = [ + "msg chanserv invite #blinkenshell.op" + "msg chanserv invite #blinkenshell.log" + "wait 2000" + ]; saslExternal = true; server = { address = "irc.blinkenshell.org"; @@ -162,6 +171,7 @@ channels = { blinkenshell.autoJoin = true; "blinkenshell.op".autoJoin = true; + "blinkenshell.log".autoJoin = true; }; }; hashbang = { diff --git a/nix-conf/home/includes/linux-dev.nix b/nix-conf/home/includes/linux-dev.nix index cfd3760..473118e 100644 --- a/nix-conf/home/includes/linux-dev.nix +++ b/nix-conf/home/includes/linux-dev.nix @@ -1,23 +1,26 @@ { config, pkgs, ... }: { - imports = [ - ./dev-common.nix - ]; + imports = [ ./dev-common.nix ]; programs.emacs = { enable = true; - package = pkgs.emacs29; - extraPackages = (epkgs: [ epkgs.vterm epkgs.multi-vterm ] ); + extraPackages = ( + epkgs: [ + epkgs.vterm + epkgs.multi-vterm + ] + ); }; home.packages = with pkgs; [ + lame libtree - mpv + mp3cat mu pinentry protonvpn-cli - youtube-dl + sword + yt-dlp ]; } - diff --git a/nix-conf/home/includes/linux-server.nix b/nix-conf/home/includes/linux-server.nix index 12164b4..62233f0 100644 --- a/nix-conf/home/includes/linux-server.nix +++ b/nix-conf/home/includes/linux-server.nix @@ -1,22 +1,21 @@ { config, pkgs, ... }: { - imports = [ - ./common.nix - ]; + imports = [ ./common.nix ]; home.packages = with pkgs; [ emacs-nox irssi libtree msmtp - neomutt pinentry restic + sword + yt-dlp ]; services.gpg-agent = { enable = true; - pinentryPackage = pkgs.pinentry-curses; + pinentry.package = pkgs.pinentry-curses; defaultCacheTtl = 34560000; maxCacheTtl = 34560000; }; @@ -51,4 +50,3 @@ programs.vim.packageConfigurable = pkgs.vim; } - diff --git a/nix-conf/home/includes/scripts/hm-changes-report.nix b/nix-conf/home/includes/scripts/hm-changes-report.nix index 303d482..65e7fe8 100644 --- a/nix-conf/home/includes/scripts/hm-changes-report.nix +++ b/nix-conf/home/includes/scripts/hm-changes-report.nix @@ -2,7 +2,7 @@ # https://github.com/gvolpe/nix-config/blob/e28a220d0087064e6bad6b992b4914a65eb545e5/home/scripts/changes-report.nix let - hm-profiles = "/nix/var/nix/profiles/per-user/${config.home.username}/profile-*-link"; + hm-profiles = "${config.home.homeDirectory}/.local/state/nix/profiles/home-manager-*-link"; in pkgs.writeShellScriptBin "hm-changes-report" '' # Disable nvd if there are less than 2 hm profiles. @@ -12,4 +12,3 @@ pkgs.writeShellScriptBin "hm-changes-report" '' ${pkgs.nvd}/bin/nvd diff $(ls -d1v ${hm-profiles} | tail -2) fi '' - diff --git a/nix-conf/home/includes/scripts/system-changes-report.nix b/nix-conf/home/includes/scripts/system-changes-report.nix index 56166cb..b94498c 100644 --- a/nix-conf/home/includes/scripts/system-changes-report.nix +++ b/nix-conf/home/includes/scripts/system-changes-report.nix @@ -12,4 +12,3 @@ pkgs.writeShellScriptBin "system-changes-report" '' ${pkgs.nvd}/bin/nvd diff $(ls -d1v ${system-profiles} | tail -2) fi '' - diff --git a/nix-conf/home/includes/secrets.yaml b/nix-conf/home/includes/secrets.yaml new file mode 100644 index 0000000..2fc9d8c --- /dev/null +++ b/nix-conf/home/includes/secrets.yaml @@ -0,0 +1,21 @@ +ssh_config: + oci: ENC[AES256_GCM,data:l1GZ6mszgDhGztWmMdkNY2wRGfLIOGfHou7m0p8NkvaZZ3oKhblyu9C2Y2uEZArC8aCysxmU0QDfeIxDAzBdszUY,iv:HD8xdaiF9s0XZAuHNjAQfEtMgKaM0R12FCv5rTq19+Y=,tag:bfa48iOXhASXc+JhmYy/EQ==,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: + age: + - recipient: age1w7kjp0qdgfyg9cyj5w4qc4fc9qz3w65xw2veazesfgdenqrd3ucqsc5ejv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAybC93bWJ1d05pSWdyOHkv + eXBUa1dUcWFnNTRKZXpxckhKNXlLMVBoR0dFCnNKcVhmcWFaQkllc05iVmtub2E2 + YkRTbnNNSnF2WWlET2N4MExYNFAzZFEKLS0tIHhwbTE3bEJlTEpXOXprSTBRckF0 + cjlWWTNQR3lLLzBqTHhld05VblFJdHcKihceil9ge+IKG2GZcLpGWUncvRvmyJ7w + YiWtb/ApF4T27wsmmFyLSnG8OWkLCKzaeU4QOVIGYQcfzzcQD5nUGg== + -----END AGE ENCRYPTED FILE----- + 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.10.2 diff --git a/nix-conf/home/includes/zsh.nix b/nix-conf/home/includes/zsh.nix index 9729386..650f559 100644 --- a/nix-conf/home/includes/zsh.nix +++ b/nix-conf/home/includes/zsh.nix @@ -1,17 +1,33 @@ -{ config, pkgs, lib, isDarwin, ... }: +{ + config, + pkgs, + lib, + ... +}: let - inherit (lib) - optionalAttrs - optionals; + inherit (lib) optionalAttrs optionals; + show_file_or_dir_preview = "if [ -d {} ]; then eza --tree --color=always {} | head -200; else bat -n --color=always --line-range :500 {}; fi"; in { - home.packages = with pkgs; [ - zsh-completions - ]; + home.packages = with pkgs; [ zsh-completions ]; programs.fzf = { enable = true; enableZshIntegration = true; + changeDirWidgetCommand = "fd --type=d --hidden --strip-cwd-prefix --exclude .git --exclude node_modules"; # FZF_ALT_C_COMMAND + changeDirWidgetOptions = [ "--preview 'eza --tree --color=always {} | head -200'" ]; # FZF_ALT_C_OPTS + defaultCommand = "fd --hidden --strip-cwd-prefix --exclude .git --exclude node_modules"; # FZF_DEFAULT_COMMAND + defaultOptions = [ + "--bind=ctrl-t:toggle-all" + "--bind=ctrl-j:jump" + ]; # FZF_DEFAULT_OPTS + fileWidgetCommand = config.programs.fzf.defaultCommand; # FZF_CTRL_T_COMMAND + fileWidgetOptions = [ "--preview '${show_file_or_dir_preview}'" ]; # FZF_CTRL_T_OPTS + historyWidgetOptions = [ + "--preview 'echo {}'" + "--preview-window down:3:hidden:wrap" + "--bind 'ctrl-t:toggle-preview'" + ]; # FZF_CTRL_R_OPTS }; programs.zoxide = { enable = true; @@ -23,20 +39,41 @@ in }; programs.keychain = { enable = lib.mkIf pkgs.stdenv.isLinux true; - agents = [ "ssh" "gpg"]; - keys = [ "id_rsa" "id_ed25519" "C171251002C200F2" ]; - # extraFlags = [ "--quiet" "--ignore-missing" ]; + agents = [ + "ssh" + "gpg" + ]; + keys = [ + "id_rsa" + "id_ed25519" + "C171251002C200F2" + ]; + # extraFlags = [ "--quiet" "--ignore-missing" ]; }; programs.command-not-found.enable = true; programs.zsh = { enable = true; enableCompletion = true; - autosuggestion.enable = true; + autosuggestion = { + enable = true; + highlight = "fg=#808080"; + strategy = [ + "history" + "completion" + ]; + }; defaultKeymap = "emacs"; history = { - size = 100000; - save = 100000; expireDuplicatesFirst = true; + ignoreSpace = true; + save = 100000; + share = true; + size = 100000; + }; + historySubstringSearch = { + enable = true; + searchUpKey = "$terminfo[kcuu1]"; + searchDownKey = "$terminfo[kcud1]"; }; profileExtra = '' @@ -50,11 +87,23 @@ in cp = "cp -iv"; mv = "mv -iv"; mkdir = "mkdir -v"; - tree = "eza --tree"; - - pp = "pushbullet push \"Pixel\" link \"\${1}\" \"\${1}\""; - - upgrade_emacs = "cp ~/.emacs.d/straight/versions/default.el ~/straight-versions-default-`date \"+%Y-%m-%d-%H%M%S\"`.el && emacs --batch -l \"~/.emacs.d/init.el\" -f \"my/upgrade-packages\""; + cat = "bat -p"; + c = "bat -p"; + l = "eza"; + la = "eza -a"; + lg = "eza -G"; + lga = "eza -aG"; + 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}"''; + + upgrade_emacs = ''cp ~/.emacs.d/straight/versions/default.el ~/straight-versions-default-`date "+%Y-%m-%d-%H%M%S"`.el && emacs --batch -l "~/.emacs.d/init.el" -f "my/upgrade-packages"''; diff_emacs = "difft --color always --context 0 $(ls -d1v ~/straight-versions-default-*.el | tail -1) ~/.emacs.d/straight/versions/default.el | grep '\\[9[12]' | egrep -v '(gnu-elpa-mirror|nongnu-elpa|melpa|emacsmirror-mirror)'"; nix-up = "git -C ~/dotfiles pull && doas nix-channel --update && doas nixos-rebuild switch && nix-channel --update && home-manager switch && system-changes-report && hm-changes-report && df -h && date"; @@ -65,13 +114,14 @@ in fb = "fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}'"; + # Restrict matches to subdirs of the current one (https://github.com/skywind3000/z.lua/blob/ef9a49d73d2b4f262c6fbb23262253dcda7c19a7/README.md#tips) zz = "z $PWD"; els = "ea run linear ls -- -1"; erg = "ea run grouped rg --"; fd = "ea run linear fd --"; - git-reset-branch = "git fetch && git reset --hard origin/\$(git branch --show-current)"; + git-reset-branch = "git fetch && git reset --hard origin/$(git branch --show-current)"; # Git log aliases from the omz git plugin gl = "git pull"; @@ -81,165 +131,211 @@ in glgga = "git log --graph --decorate --all"; glgm = "git log --graph --max-count=10"; glo_ = "git log --oneline --decorate"; - glol = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset\""; - glols = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset\" --stat"; - glod = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset\""; - glods = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset\" --date=short"; - glola = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset\" --all"; + glol = ''git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset"''; + glols = ''git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset" --stat''; + glod = ''git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset"''; + glods = ''git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset" --date=short''; + glola = ''git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset" --all''; glog = "git log --oneline --decorate --graph"; gloga = "git log --oneline --decorate --graph --all"; - } - // optionalAttrs pkgs.stdenv.isDarwin { - oemacs = "open -a /Applications/Emacs.app"; - }; + } // optionalAttrs pkgs.stdenv.isDarwin { oemacs = "open -a /Applications/Emacs.app"; }; localVariables = { PER_DIRECTORY_HISTORY_TOGGLE = "^\\\\"; # ^\\ is ^# HISTORY_START_WITH_GLOBAL = true; - - ZSH_AUTOSUGGEST_STRATEGY = ["history" "completion"]; - - NVM_AUTO_USE = true; - NVM_LAZY_LOAD = true; - - LSP_USE_PLISTS = true; 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 - - # Keep these in initExtra, rather than localVariables, because the order matters - export FZF_DEFAULT_COMMAND='rg --files --no-ignore --hidden --follow -g "!{.git,node_modules}/*" 2> /dev/null' - export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" - export FZF_ALT_C_COMMAND='rg --hidden --files --sort-files --null -g "!{.git,node_modules}/*" | xargs -0 dirname | sort -u' - export FZF_ALT_C_OPTS="--preview 'eza --tree {} | head -200'" - export FZF_CTRL_R_OPTS="--preview 'echo {}' --preview-window down:3:hidden:wrap --bind 'ctrl-t:toggle-preview'" - export FZF_DEFAULT_OPTS="--bind=ctrl-t:toggle-all --bind=ctrl-j:jump" - - eval "$(batpipe)" - autopair-init - enable-fzf-tab - bindkey '^[[A' history-substring-search-up - bindkey '^[[B' history-substring-search-down - - # 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 ''\',''\' ''\'.''\' - - set -o noclobber append_history share_history - - # disable flow control (so that fzf-git.sh's ^g^s can work) - stty -ixon - - 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) } - - 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' {}" - } + 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 + } - fe() { - IFS=$'\n' files=($(fzf-tmux --query="$1" --multi --select-1 --exit-0)) - [[ -n "$files" ]] && ''${EDITOR:-vim} "''${files[@]}" - } + 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 - # TODO is there a way to do this in shellAliases - alias ..="cd .." - alias -- -="cd -" + if [ $# -gt 2 -a ! -d "$base_path" ]; then + echo "$base_path is not a directory" + return 2 + fi - ...() { - 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") + if [ $# -lt 3 -a $line -ne 1 ]; then + ea_format+=" +{line}" fi + + eval $(ea p $idx "$cmd ''${ea_format}$3") } - local DIR=$(get_parent_dirs $(realpath "$PWD/..") | fzf-tmux) - cd "$DIR" - } - # From omz - function mkcd () { - mkdir -p $@ && cd ''${@:$#} - } + function vip () { + _vip $EDITOR ''${@} + } + function bp () { + _vip bat ''${@} + } + function bpp () { + # this will be split into an array in _vip + CMD="bat -p" + _vip $CMD ''${@} + } - tre () { command tre "$@" -e && source "/tmp/tre_aliases_$USER" 2>/dev/null; } + function ecd () { + cd $(ea p ''${1:-1}) + } - 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 + 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) } - if [ $1 -eq 0 ] ; then - GC_ARGS=(-d) - else - GC_ARGS=(--delete-older-than ''${1}d) - fi + 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' {}" + } - DOAS=$(command -v doas) + fe() { + IFS=$'\n' files=($(fzf-tmux --query="$1" --multi --select-1 --exit-0)) + [[ -n "$files" ]] && ''${EDITOR:-vim} "''${files[@]}" + } - # 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 + # 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" + } - df -h - date - } + # From omz + function mkcd () { + mkdir -p $@ && cd ''${@:$#} + } - function checkout-pr () { - git fetch ''${2:-upstream} pull/''${1}/head:pr-''${1} - git switch pr-''${1} - } + tre () { command tre "$@" -e && source "/tmp/tre_aliases_$USER" 2>/dev/null; } - [[ ! -f ~/.zsh.local ]] || source ~/.zsh.local + 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 - [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh - ''; + if [ $1 -eq 0 ] ; then + GC_ARGS=(-d) + else + GC_ARGS=(--delete-older-than ''${1}d) + fi - plugins = with pkgs; [ + DOAS=$(command -v doas) + + # 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 + + df -h + date + } + + 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; [ { name = "zsh-autopair"; src = zsh-autopair; @@ -266,11 +362,6 @@ in file = "share/zsh-powerlevel10k/powerlevel10k.zsh-theme"; } { - name = "zsh-history-substring-search"; - src = zsh-history-substring-search; - file = "share/zsh-history-substring-search/zsh-history-substring-search.zsh"; - } - { name = "zsh-forgit"; src = zsh-forgit; file = "share/zsh/zsh-forgit/forgit.plugin.zsh"; @@ -283,7 +374,7 @@ in { name = "fzf-git.sh"; src = fzf-git-sh; - file = "share/zsh/fzf-git-sh/fzf-git.sh"; + file = "share/fzf-git-sh/fzf-git.sh"; } { name = "per-directory-history"; @@ -295,19 +386,6 @@ in }; file = "per-directory-history.zsh"; } - ] - ++ optionals stdenv.isDarwin [ - { - name = "zsh-nvm"; - src = fetchFromGitHub { - owner = "lukechilds"; - repo = "zsh-nvm"; - rev = "23067bd9bb6eb6f4737a3ea90cb0cb5e85f61ba2"; - sha256 = "Zwdi7bezMFKaIKYwsSftu3mJSFvadEWmY2hYnU1Kpu4="; - }; - file = "zsh-nvm.plugin.zsh"; - } ]; }; } - diff --git a/nix-conf/home/otm.nix b/nix-conf/home/otm.nix index cf9a219..2055780 100644 --- a/nix-conf/home/otm.nix +++ b/nix-conf/home/otm.nix @@ -1,12 +1,123 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let - email = builtins.readFile "${config.home.homeDirectory}/email.txt"; - otmEmail = builtins.readFile "${config.home.homeDirectory}/otm_email.txt"; + zscaler-cert = '' + -----BEGIN CERTIFICATE----- + MIIE0zCCA7ugAwIBAgIJANu+mC2Jt3uTMA0GCSqGSIb3DQEBCwUAMIGhMQswCQYD + VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2Ux + FTATBgNVBAoTDFpzY2FsZXIgSW5jLjEVMBMGA1UECxMMWnNjYWxlciBJbmMuMRgw + FgYDVQQDEw9ac2NhbGVyIFJvb3QgQ0ExIjAgBgkqhkiG9w0BCQEWE3N1cHBvcnRA + enNjYWxlci5jb20wHhcNMTQxMjE5MDAyNzU1WhcNNDIwNTA2MDAyNzU1WjCBoTEL + MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBK + b3NlMRUwEwYDVQQKEwxac2NhbGVyIEluYy4xFTATBgNVBAsTDFpzY2FsZXIgSW5j + LjEYMBYGA1UEAxMPWnNjYWxlciBSb290IENBMSIwIAYJKoZIhvcNAQkBFhNzdXBw + b3J0QHpzY2FsZXIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA + qT7STSxZRTgEFFf6doHajSc1vk5jmzmM6BWuOo044EsaTc9eVEV/HjH/1DWzZtcr + fTj+ni205apMTlKBW3UYR+lyLHQ9FoZiDXYXK8poKSV5+Tm0Vls/5Kb8mkhVVqv7 + LgYEmvEY7HPY+i1nEGZCa46ZXCOohJ0mBEtB9JVlpDIO+nN0hUMAYYdZ1KZWCMNf + 5J/aTZiShsorN2A38iSOhdd+mcRM4iNL3gsLu99XhKnRqKoHeH83lVdfu1XBeoQz + z5V6gA3kbRvhDwoIlTBeMa5l4yRdJAfdpkbFzqiwSgNdhbxTHnYYorDzKfr2rEFM + dsMU0DHdeAZf711+1CunuQIDAQABo4IBCjCCAQYwHQYDVR0OBBYEFLm33UrNww4M + hp1d3+wcBGnFTpjfMIHWBgNVHSMEgc4wgcuAFLm33UrNww4Mhp1d3+wcBGnFTpjf + oYGnpIGkMIGhMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8G + A1UEBxMIU2FuIEpvc2UxFTATBgNVBAoTDFpzY2FsZXIgSW5jLjEVMBMGA1UECxMM + WnNjYWxlciBJbmMuMRgwFgYDVQQDEw9ac2NhbGVyIFJvb3QgQ0ExIjAgBgkqhkiG + 9w0BCQEWE3N1cHBvcnRAenNjYWxlci5jb22CCQDbvpgtibd7kzAMBgNVHRMEBTAD + AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAw0NdJh8w3NsJu4KHuVZUrmZgIohnTm0j+ + RTmYQ9IKA/pvxAcA6K1i/LO+Bt+tCX+C0yxqB8qzuo+4vAzoY5JEBhyhBhf1uK+P + /WVWFZN/+hTgpSbZgzUEnWQG2gOVd24msex+0Sr7hyr9vn6OueH+jj+vCMiAm5+u + kd7lLvJsBu3AO3jGWVLyPkS3i6Gf+rwAp1OsRrv3WnbkYcFf9xjuaf4z0hRCrLN2 + xFNjavxrHmsH8jPHVvgc1VD0Opja0l/BRVauTrUaoW6tE+wFG5rEcPGS80jjHK4S + pB5iDj2mUZH1T8lzYtuZy0ZPirxmtsk3135+CKNa2OCAhhFjE0xd + -----END CERTIFICATE----- + ''; + + internal-cert = '' + -----BEGIN CERTIFICATE----- + MIIDpzCCAo+gAwIBAgIRAPimIVPUvFeeWdKoTVr/KaowDQYJKoZIhvcNAQELBQAw + bTELMAkGA1UEBhMCR0IxGDAWBgNVBAoMD29udGhlbWFya2V0LmNvbTELMAkGA1UE + CwwCSVQxDzANBgNVBAgMBkxvbmRvbjEVMBMGA1UEAwwMaW50ZXJuYWwub3RtMQ8w + DQYDVQQHDAZMb25kb24wHhcNMjQwNTIxMTIyNTUzWhcNMzQwNTIxMTMyNTQ1WjBt + MQswCQYDVQQGEwJHQjEYMBYGA1UECgwPb250aGVtYXJrZXQuY29tMQswCQYDVQQL + DAJJVDEPMA0GA1UECAwGTG9uZG9uMRUwEwYDVQQDDAxpbnRlcm5hbC5vdG0xDzAN + BgNVBAcMBkxvbmRvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMb + +jxbONNYRWXFYLHOVsKkTBVY/SkPo9VYv63Xzp8YF5CC3GMNKVvtdfwDLxdB4yDE + 71kOngybxIRTeX+UdZCfhmcgpmu6trT8RB27SzpOVkrVz+wCzYx/3qE4xSQok474 + komOtHkuwoL1MMqTH1WOPqUL3RaNkK3YSq2M8JPfjG9w6eboT0i+c7GG9OEk9BwW + 35M+tdiI9fjAK95yMU9DjVI7PqTfqBVT5pUoyzAKhTikZlC6O8X8U98NJojwhaT4 + RJcbbd1bdNqcxdpshIiP1kWAE4CKp2+tMzzz9yqwgQ1igbsm2j37TxI74JoEV9+k + 95tFwgXLT7Bih3MFuI0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E + FgQUuA22mh+yV3W8D3mpiouhO2Y/2c4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 + DQEBCwUAA4IBAQCJgkhzAWW0Rh4EWyAdVIoUnjHIr032Qu61cXiNqvvRS9GIF5gs + oynXjIIj2scBeNlkG3oSy0G3wWyFzng6ixwuol2fRhDsllvm2bgeaObdbccbLbWx + 8OTobCqWTfZvEn8dYs7Qbx/9l4yBH6pYptnOmDt+Ze2hOVZyTuiVq91CEn+on9FG + 2V6Bjuu8dNpz2CC8na7H4wsqUNRfBVSTSKgdeeiLj1zdueWgOtA1PNOZp5wi452U + mpb61I1k/Xfe6ECUn8QEh9oEB4MprNvlvLVmmnstcBmqU9SvONtmSrn8ekI2OO69 + R7pRciveNTEVrJRPqOfL4fjfQbjtpKx6Gk5m + -----END CERTIFICATE----- + ''; + + internal-staging-cert = '' + -----BEGIN CERTIFICATE----- + MIIDpzCCAo+gAwIBAgIRANXYUsUWHHGL/LgpcIY3zlUwDQYJKoZIhvcNAQELBQAw + bTELMAkGA1UEBhMCR0IxGDAWBgNVBAoMD29udGhlbWFya2V0LmNvbTELMAkGA1UE + CwwCSVQxDzANBgNVBAgMBkxvbmRvbjEVMBMGA1UEAwwMaW50ZXJuYWwub3RtMQ8w + DQYDVQQHDAZMb25kb24wHhcNMjQwNTI0MDc1MDQ3WhcNMzQwNTI0MDg1MDQ0WjBt + MQswCQYDVQQGEwJHQjEYMBYGA1UECgwPb250aGVtYXJrZXQuY29tMQswCQYDVQQL + DAJJVDEPMA0GA1UECAwGTG9uZG9uMRUwEwYDVQQDDAxpbnRlcm5hbC5vdG0xDzAN + BgNVBAcMBkxvbmRvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAImM + FljdqdQ4M0tRYAiRU6WPWiIKFHwZSTsdLohNXikjnSar1xnN1LQLLH1mzPpztnpA + eCnADo9Dc1Nsm+dt6WREL6n57oQSG3d5eM+br6MIm2qWIXQhtJtpKFcbSuOlaB4z + uWNmk3R09+3GaGNhpYBmEbh3Nvc5it0/p6EUOVWigF3ghr0NO2JSOhPtGhNSPyyS + 9Q7DZSwdaGeix9yKWKDh3X4ikZvjm4xqkogFFdyFHKA1qmsaCsT+NP1iH6HNb6pB + xOb1ZyzR1EcFKAP+8uOgoI3bF0iJswNtkSc2kqf0vNQ+K/qoNL8OH7VyKCfeQqNL + 2b8lV+FwHIBD2ZwhsuUCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E + FgQUxbubUk2Kf9k68OUOSwrdgGuAtJYwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 + DQEBCwUAA4IBAQBNRKzWrQQBh1RAU023u0pgNjfk0OV5mTlb2024jCLmqG7U/eSC + X8LoO/Gm3yVuj5RsoH8H5ftNU1j71c+dHg7+UVvQZRCOfgVIMnPCxuMvcaljRnLG + qHaRCra5G3IOLrBtJDg9DgKg6/gUbg5DvZwiO5J21yzJWxy6wmoRBmy43DZBa2RV + /rO3WOM0uuMp4DHqBIYx55d+4mdtshikZoys3TCiFH3C11xrUwkIdNEqvMcjl/Pr + 5WrzfbTpDzvo/GCkPhA0thVgUBx4LXB8HizVmDZgGbSuh7ic7LHyh1ahE0fqGX9C + ZvHif3XTcAZlNkilVHvF3pM4EIosFEc6dHFy + -----END CERTIFICATE----- + ''; + + aws-cert = + (builtins.readFile "${pkgs.awscli2}/lib/python${pkgs.awscli2.python.pythonVersion}/site-packages/awscli/botocore/cacert.pem") + + zscaler-cert; + + full-cert = + (builtins.readFile /etc/ssl/cert.pem) + aws-cert + internal-cert + internal-staging-cert; + + zscaler-cert-file = pkgs.writeText "zscaler-cert.pem" zscaler-cert; + aws-cert-file = pkgs.writeText "aws-cert.pem" aws-cert; + full-cert-file = pkgs.writeText "full-cert.pem" full-cert; + + zscaler-jdk = pkgs.jdk.overrideAttrs (old: { + # passthru.home must be set to ensure JAVA_HOME is set correctly + # See https://github.com/nix-community/home-manager/blob/086f619dd991a4d355c07837448244029fc2d9ab/modules/programs/java.nix#L39-L41 + # and https://github.com/NixOS/nixpkgs/blob/4877ea239f4d02410c3516101faf35a81af0c30e/pkgs/development/compilers/openjdk/jre.nix#L32 + passthru.home = "${zscaler-jdk}"; # make sure JAVA_HOME is set + installPhase = + # This is probably equivalent to + # $out/bin/keytool -import -noprompt -trustcacerts -alias zscalerrootca -keystore $out/lib/security/cacerts <<< "${zscaler-cert}" + # but follow the zscaler instructions just in case + old.installPhase + + '' + ${pkgs.openssl}/bin/openssl x509 -inform pem -outform der <<< "${zscaler-cert}" | $out/bin/keytool -import -noprompt -trustcacerts -alias zscalerrootca -keystore $out/lib/security/cacerts + ''; + }); + + zscaler-lein = pkgs.leiningen.override { jdk = zscaler-jdk; }; + zscaler-clojure = pkgs.clojure.override { jdk = zscaler-jdk; }; + in { - imports = [ - ./includes/darwin.nix - ]; + imports = [ ./includes/darwin.nix ]; # Let Home Manager install and manage itself. programs.home-manager.enable = true; @@ -16,15 +127,84 @@ in home.username = "dmorgan"; home.homeDirectory = "/Users/dmorgan"; + home.sessionPath = [ "$HOME/.costar/auth2aws" ]; + + home.sessionVariables = { + AWS_DEFAULT_REGION = "eu-west-1"; + AWS_PROFILE = "aws_otm_dev_developers"; + AM_PROFILE = "staging"; + AWS_CA_BUNDLE = "${aws-cert-file}"; + CURL_CA_BUNDLE = "${full-cert-file}"; + NIX_SSL_CERT_FILE = "${full-cert-file}"; + NODE_EXTRA_CA_CERTS = "${zscaler-cert-file}"; + JVM_OPTS = "-Dcom.amazonaws.sdk.disableCertChecking"; + LEIN_JVM_OPTS = "-Dcom.amazonaws.sdk.disableCertChecking"; + }; + + home.shellAliases = { + 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'"; + }; + + home.packages = with pkgs; [ + zscaler-clojure + zscaler-lein + ]; + + home.file = { + "certs/zscaler-cert.pem".source = zscaler-cert-file; + "certs/aws-cert.pem".source = aws-cert-file; + "certs/full-cert.pem".source = full-cert-file; + "certs/internal-ca.pem".text = internal-cert; + "certs/staging-internal-ca.pem".text = internal-staging-cert; + ".docker/certs.d/zcaler-cert.pem".source = zscaler-cert-file; + ".wgetrc".text = "ca_certificate=${full-cert-file}"; + }; + + sops.secrets = { + "git_email_config/otm" = { }; + "ssh_config/otm" = { }; + }; + + programs.java = { + enable = true; + package = zscaler-jdk; + }; + programs.git = { signing.signByDefault = lib.mkForce false; - userEmail = lib.mkForce otmEmail; - includes = [ - { contents = { commit.gpgSign = true; user.email = email; }; condition = "gitdir:~/src/personal/"; } - { contents = { commit.gpgSign = true; user.email = email; }; condition = "gitdir:~/dotfiles/"; } + includes = lib.mkForce [ + { path = config.sops.secrets."git_email_config/otm".path; } + { + path = config.sops.secrets."git_email_config/default".path; + condition = "gitdir:~/src/personal/"; + } + { + path = config.sops.secrets."git_email_config/default".path; + condition = "gitdir:~/dotfiles/"; + } + { + contents = { + commit.gpgSign = true; + tag.gpgSign = true; + }; + condition = "gitdir:~/src/personal/"; + } + { + contents = { + commit.gpgSign = true; + tag.gpgSign = true; + }; + condition = "gitdir:~/dotfiles/"; + } ]; extraConfig = { github.user = "david-morgan-otm"; + http.sslcainfo = "${full-cert-file}"; }; ignores = [ ".envrc" @@ -37,21 +217,24 @@ in "resources/next/package-lock.json" ]; }; - programs.ssh.matchBlocks = { - "github.com" = lib.mkForce { - hostname = "github.com"; - user = "git"; - identityFile = "~/.ssh/id_rsa"; - identitiesOnly = true; - }; - "github.com-personal" = { - hostname = "github.com"; - user = "git"; - identityFile = "~/.ssh/id_ed25519"; - identitiesOnly = true; + programs.ssh = { + includes = [ config.sops.secrets."ssh_config/otm".path ]; + matchBlocks = { + "github.com" = lib.mkForce { + hostname = "github.com"; + user = "git"; + identityFile = "~/.ssh/id_rsa"; + identitiesOnly = true; + }; + "github.com-personal" = { + hostname = "github.com"; + user = "git"; + identityFile = "~/.ssh/id_ed25519"; + identitiesOnly = true; + }; }; }; - + # This value determines the Home Manager release that your # configuration is compatible with. This helps avoid breakage # when a new Home Manager release introduces backwards diff --git a/nix-conf/machines/djmuk1/configuration.nix b/nix-conf/machines/djmuk1/configuration.nix index 8c7187e..7405e9a 100644 --- a/nix-conf/machines/djmuk1/configuration.nix +++ b/nix-conf/machines/djmuk1/configuration.nix @@ -1,7 +1,6 @@ -{ config, pkgs, ... }: { - imports = [ - ./hardware-configuration.nix - ]; +{ config, pkgs, ... }: +{ + imports = [ ./hardware-configuration.nix ]; boot.tmp.cleanOnBoot = true; @@ -30,45 +29,60 @@ 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; - home = "/home/djm"; - description = "David Morgan"; - extraGroups = [ "wheel" "plocate" ]; - shell = pkgs.zsh; - openssh.authorizedKeys.keys = [ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCurCpxZCHtByB5wXzsjTXwMyDSB4+B8rq5XY6EGss58NwD8jc5cII4i+QUbCOGTiAggSZUSC9YIP24hjpOeNT/IYs5m7Qn1B9MtBAiUSrIYew8eDwnMLlPzN+k2x9zCrJeCHIvGJaFHPXTh1Lf5Jt2fPVGW9lksE/XUVOe6ht4N/b+nqqszXFhc8Ug6le2bC1YeTCVEf8pjlh/I7DkDBl6IB8uEXc3X2vxxbV0Z4vlBrFkkAywcD3j5VlS/QYfBr4BICNmq/sO3fMkbMbtAPwuFxeL4+h6426AARQZiSS0qVEc8OoFRBVx3GEH5fqVAWfB1geyLzei22HbjUcT9+xN davidmo@gendros" + users.users.djm = { + isNormalUser = true; + home = "/home/djm"; + description = "David Morgan"; + extraGroups = [ + "wheel" + "plocate" + ]; + shell = pkgs.zsh; + openssh.authorizedKeys.keys = [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCurCpxZCHtByB5wXzsjTXwMyDSB4+B8rq5XY6EGss58NwD8jc5cII4i+QUbCOGTiAggSZUSC9YIP24hjpOeNT/IYs5m7Qn1B9MtBAiUSrIYew8eDwnMLlPzN+k2x9zCrJeCHIvGJaFHPXTh1Lf5Jt2fPVGW9lksE/XUVOe6ht4N/b+nqqszXFhc8Ug6le2bC1YeTCVEf8pjlh/I7DkDBl6IB8uEXc3X2vxxbV0Z4vlBrFkkAywcD3j5VlS/QYfBr4BICNmq/sO3fMkbMbtAPwuFxeL4+h6426AARQZiSS0qVEc8OoFRBVx3GEH5fqVAWfB1geyLzei22HbjUcT9+xN davidmo@gendros" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK9UDTaVnUOU/JknrNdihlhhGOk53LmHq9I1ASri3aga djm@gaius" - ]; - }; + ]; + }; - security.sudo.extraConfig = '' - djm ALL=(ALL) NOPASSWD: ALL - ''; - security.doas = { - enable = true; - extraRules = [ { users = [ "djm" ]; noPass = true; keepEnv = true; } ]; - }; + security.sudo.extraConfig = '' + djm ALL=(ALL) NOPASSWD: ALL + ''; + security.doas = { + enable = true; + extraRules = [ + { + users = [ "djm" ]; + noPass = true; + keepEnv = true; + } + ]; + }; - programs.zsh.enable = true; + programs.zsh.enable = true; - programs.vim.defaultEditor = true; + programs.vim = { + enable = true; + defaultEditor = true; + }; - environment.systemPackages = with pkgs; [ - #procmail - vim - wget - ]; + environment.systemPackages = with pkgs; [ + #procmail + wget + ]; + + nix.settings.trusted-users = [ + "root" + "djm" + ]; - nix.settings.trusted-users = [ "root" "djm" ]; + i18n.defaultLocale = "en_GB.UTF-8"; - i18n.defaultLocale = "en_GB.UTF-8"; + swapDevices = [ { + device = "/var/lib/swapfile"; + size = 2*1024; + } ]; - system.stateVersion = "22.05"; + system.stateVersion = "23.11"; } diff --git a/nix-conf/machines/djmuk1/hardware-configuration.nix b/nix-conf/machines/djmuk1/hardware-configuration.nix index 4d5ccf9..894b817 100644 --- a/nix-conf/machines/djmuk1/hardware-configuration.nix +++ b/nix-conf/machines/djmuk1/hardware-configuration.nix @@ -6,7 +6,20 @@ efiInstallAsRemovable = true; device = "nodev"; }; - fileSystems."/boot" = { device = "/dev/disk/by-uuid/C149-C30B"; fsType = "vfat"; }; + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/0D60-CDE2"; + fsType = "vfat"; + }; + boot.initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "xen_blkfront" + "vmw_pvscsi" + ]; boot.initrd.kernelModules = [ "nvme" ]; - fileSystems."/" = { device = "/dev/sda1"; fsType = "ext4"; }; + fileSystems."/" = { + device = "/dev/sda1"; + fsType = "ext4"; + }; + } diff --git a/nix-conf/machines/djmuk2/configuration.nix b/nix-conf/machines/djmuk2/configuration.nix index 8d679ac..0b31a01 100644 --- a/nix-conf/machines/djmuk2/configuration.nix +++ b/nix-conf/machines/djmuk2/configuration.nix @@ -1,7 +1,6 @@ -{ config, pkgs, ... }: { - imports = [ - ./hardware-configuration.nix - ]; +{ config, pkgs, ... }: +{ + imports = [ ./hardware-configuration.nix ]; boot.tmp.cleanOnBoot = true; zramSwap.enable = true; @@ -31,49 +30,65 @@ 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; - home = "/home/djm"; - description = "David Morgan"; - extraGroups = [ "wheel" "plocate" ]; - shell = pkgs.zsh; - openssh.authorizedKeys.keys = [ + # 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: + # SOPS_AGE_KEY=$(doas ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) sops -d --extract '["openiscsi_name"]' machines/djmuk2/secrets.yaml | doas tee /root/.config/secrets/openiscsi_name + services.openiscsi.enable = true; + services.openiscsi.name = builtins.readFile "/root/.config/secrets/openiscsi_name"; + #services.openiscsi.enableAutoLoginOut = true; + + users.users.djm = { + isNormalUser = true; + home = "/home/djm"; + description = "David Morgan"; + extraGroups = [ + "wheel" + "plocate" + ]; + shell = pkgs.zsh; + openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCurCpxZCHtByB5wXzsjTXwMyDSB4+B8rq5XY6EGss58NwD8jc5cII4i+QUbCOGTiAggSZUSC9YIP24hjpOeNT/IYs5m7Qn1B9MtBAiUSrIYew8eDwnMLlPzN+k2x9zCrJeCHIvGJaFHPXTh1Lf5Jt2fPVGW9lksE/XUVOe6ht4N/b+nqqszXFhc8Ug6le2bC1YeTCVEf8pjlh/I7DkDBl6IB8uEXc3X2vxxbV0Z4vlBrFkkAywcD3j5VlS/QYfBr4BICNmq/sO3fMkbMbtAPwuFxeL4+h6426AARQZiSS0qVEc8OoFRBVx3GEH5fqVAWfB1geyLzei22HbjUcT9+xN davidmo@gendros" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK9UDTaVnUOU/JknrNdihlhhGOk53LmHq9I1ASri3aga djm@gaius" - ]; - }; + ]; + }; - security.sudo.extraConfig = '' - djm ALL=(ALL) NOPASSWD: ALL - ''; - security.doas = { - enable = true; - extraRules = [ { users = [ "djm" ]; noPass = true; keepEnv = true; } ]; - }; + security.sudo.extraConfig = '' + djm ALL=(ALL) NOPASSWD: ALL + ''; + security.doas = { + enable = true; + extraRules = [ + { + users = [ "djm" ]; + noPass = true; + keepEnv = true; + } + ]; + }; - programs.zsh.enable = true; + programs.zsh.enable = true; - programs.vim.defaultEditor = true; + programs.vim = { + enable = true; + defaultEditor = true; + }; - environment.systemPackages = with pkgs; [ - #procmail - git - vim - wget - ]; + environment.systemPackages = with pkgs; [ + #procmail + git + wget + ]; - nix.settings.trusted-users = [ "root" "djm" ]; - nix.optimise.automatic = true; - nix.optimise.dates = [ "03:00" ]; + nix.settings.trusted-users = [ + "root" + "djm" + ]; + nix.optimise.automatic = true; + nix.optimise.dates = [ "03:00" ]; - i18n.defaultLocale = "en_GB.UTF-8"; + i18n.defaultLocale = "en_GB.UTF-8"; - system.stateVersion = "22.05"; + system.stateVersion = "22.05"; } - diff --git a/nix-conf/machines/djmuk2/hardware-configuration.nix b/nix-conf/machines/djmuk2/hardware-configuration.nix index e27e899..5c421f9 100644 --- a/nix-conf/machines/djmuk2/hardware-configuration.nix +++ b/nix-conf/machines/djmuk2/hardware-configuration.nix @@ -6,9 +6,19 @@ efiInstallAsRemovable = true; device = "nodev"; }; - fileSystems."/boot" = { device = "/dev/disk/by-uuid/4875-017B"; fsType = "vfat"; }; - boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "xen_blkfront" ]; + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/4875-017B"; + fsType = "vfat"; + }; + boot.initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "xen_blkfront" + ]; boot.initrd.kernelModules = [ "nvme" ]; - fileSystems."/" = { device = "/dev/mapper/ocivolume-root"; fsType = "xfs"; }; - + fileSystems."/" = { + device = "/dev/mapper/ocivolume-root"; + fsType = "xfs"; + }; + } diff --git a/nix-conf/machines/djmuk2/secrets.yaml b/nix-conf/machines/djmuk2/secrets.yaml new file mode 100644 index 0000000..3216fd3 --- /dev/null +++ b/nix-conf/machines/djmuk2/secrets.yaml @@ -0,0 +1,21 @@ +openiscsi_name: ENC[AES256_GCM,data:RZtrRGCnYgiAwq1bVnyK8fiYCxCKbtNs5diV3nUmNWAhU8CYRxau6SIAhB9t3f7p1fKgVC1V0fxV0nko6tdK,iv:M7qSnfBdxdTaCIb2/QZfrTUOZGX19IJY69IncTEk68w=,tag:eIo0fSKZTMEakGHh2zi5oQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age17j56andser5ddtlfunm35m25xueua4djh9glxlscfcet8865yv9s5aqvla + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5UFgxckhMa1RWL3hGQkZw + M25XN1JkT2dnQk9iVXdyaFJsa3hMM0pVam04CmZSWFdJbnl4RzFpUUpYK2JmRXFO + L3ZZbXZ3aHA4NjBuRCtnYlpsNG94ZVkKLS0tIFNIUTVjOUxhS00zZFlyODVuQ1lB + bC9sLzdObkpFNTJRcmk3N3Y0TG1xakkKvFbr1YlLFS7c0BfK1MYczTXgjwcaNjxH + tHCQWzVyx1VzLID1TCQDGXWApkaaQYxa2d/afTTRxk98w6xJIvLj2g== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-09-03T15:08:24Z" + mac: ENC[AES256_GCM,data:CtMDdk/tY52HLDuTHIUWF8qV3wdyykWnEKJk0bGMT+feWd/+PAzJRzCOVDuL6AxT1FmtZGx2lFZz6A9vzFbGsn1fawXVo40q+6TWpdcv80tRaicfyh1FTppWGNOJn/bh7DILuX41HRTEP2ngpMHwSr3cbCUfhxrV+r7giguj1do=,iv:uGe15h57SyQr8yi19sqDRPwtC/4WmBAwqvsHI5g5pAc=,tag:2Lv+QZf0CsgusJMay9MyQQ==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/nix-conf/machines/edrahil/configuration.nix b/nix-conf/machines/edrahil/configuration.nix index 2ef4c9d..a1bc8e3 100644 --- a/nix-conf/machines/edrahil/configuration.nix +++ b/nix-conf/machines/edrahil/configuration.nix @@ -1,7 +1,9 @@ -{ config, pkgs,... }: { +{ config, pkgs, ... }: +{ imports = [ ./hardware-configuration.nix ./network-configuration.nix + <sops-nix/modules/sops> ]; boot.tmp.cleanOnBoot = true; @@ -10,7 +12,20 @@ networking.hostName = "edrahil"; networking.firewall = { enable = true; - allowedTCPPorts = [ 113 2222 ]; + allowedTCPPorts = [ + 113 + 2222 + ]; + }; + + sops = { + defaultSopsFile = builtins.path { + path = /etc/nixos/secrets.yaml; + name = "edrahil-secrets.yaml"; + }; + secrets.restic_password = { + owner = config.users.users.djm.name; + }; }; services.openssh = { @@ -34,50 +49,158 @@ services.sshguard.enable = true; services.oidentd.enable = true; - services.locate = { - enable = true; - package = pkgs.plocate; - localuser = null; + services.locate.enable = true; + + services.restic = { + backups = { + hb = { + paths = [ "${config.users.users.djm.home}" ]; + repository = "sftp:djm@hb-backup:/home/djm/backup/edrahil"; + initialize = true; + user = "djm"; + environmentFile = "/etc/restic-environment"; + passwordFile = config.sops.secrets.restic_password.path; + timerConfig = { + OnCalendar = "02:25"; + RandomizedDelaySec = "20min"; + }; + exclude = [ + "irclogs" + ".cache" + ".config" + ".directory_history" + ".local" + "nixpkgs" + ]; + extraBackupArgs = [ + "--compression=max" + ]; + pruneOpts = [ + "--keep-daily 5" + "--keep-weekly 2" + "--keep-monthly 3" + ]; + }; + bs = { + paths = [ "${config.users.users.djm.home}" ]; + repository = "sftp:djm@bs-backup:/home/djm/backup/edrahil"; + initialize = true; + user = "djm"; + environmentFile = "/etc/restic-environment"; + passwordFile = config.sops.secrets.restic_password.path; + timerConfig = { + OnCalendar = "03:15"; + RandomizedDelaySec = "20min"; + }; + exclude = [ + "irclogs" + ".cache" + ".config" + ".directory_history" + ".local" + "nixpkgs" + ]; + extraBackupArgs = [ + "--compression=max" + ]; + pruneOpts = [ + "--keep-daily 5" + "--keep-weekly 2" + "--keep-monthly 3" + ]; + }; + tt = { + paths = [ "${config.users.users.djm.home}" ]; + repository = "sftp:djm@tt-backup:/home/djm/backup/edrahil"; + initialize = true; + user = "djm"; + environmentFile = "/etc/restic-environment"; + passwordFile = config.sops.secrets.restic_password.path; + timerConfig = { + OnCalendar = "04:05"; + RandomizedDelaySec = "20min"; + }; + exclude = [ + "irclogs" + ".cache" + ".config" + ".directory_history" + ".local" + "nixpkgs" + ]; + extraBackupArgs = [ + "--compression=max" + ]; + pruneOpts = [ + "--keep-daily 5" + "--keep-weekly 2" + "--keep-monthly 3" + ]; + }; + }; }; time.timeZone = "Europe/London"; - users.users.djm = - { isNormalUser = true; - home = "/home/djm"; - description = "David Morgan"; - extraGroups = [ "wheel" "plocate" ]; - shell = pkgs.zsh; - openssh.authorizedKeys.keys = [ + users.users.djm = { + isNormalUser = true; + home = "/home/djm"; + description = "David Morgan"; + extraGroups = [ + "wheel" + "plocate" + ]; + shell = pkgs.zsh; + openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCurCpxZCHtByB5wXzsjTXwMyDSB4+B8rq5XY6EGss58NwD8jc5cII4i+QUbCOGTiAggSZUSC9YIP24hjpOeNT/IYs5m7Qn1B9MtBAiUSrIYew8eDwnMLlPzN+k2x9zCrJeCHIvGJaFHPXTh1Lf5Jt2fPVGW9lksE/XUVOe6ht4N/b+nqqszXFhc8Ug6le2bC1YeTCVEf8pjlh/I7DkDBl6IB8uEXc3X2vxxbV0Z4vlBrFkkAywcD3j5VlS/QYfBr4BICNmq/sO3fMkbMbtAPwuFxeL4+h6426AARQZiSS0qVEc8OoFRBVx3GEH5fqVAWfB1geyLzei22HbjUcT9+xN davidmo@gendros" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK9UDTaVnUOU/JknrNdihlhhGOk53LmHq9I1ASri3aga djm@gaius" - ]; - }; + ]; + }; - security.sudo.extraConfig = '' - djm ALL=(ALL) NOPASSWD: ALL - ''; - security.doas = { - enable = true; - extraRules = [ { users = [ "djm" ]; noPass = true; keepEnv = true; } ]; - }; + security.sudo.extraConfig = '' + djm ALL=(ALL) NOPASSWD: ALL + ''; + security.doas = { + enable = true; + extraRules = [ + { + users = [ "djm" ]; + noPass = true; + keepEnv = true; + } + ]; + }; + + programs.zsh.enable = true; - programs.zsh.enable = true; + programs.vim = { + enable = true; + defaultEditor = true; + }; - programs.vim.defaultEditor = true; + environment.etc = { + "restic-environment" = { + text = '' + RESTIC_COMPRESSION=max + ''; + }; + }; - environment.systemPackages = with pkgs; [ - #procmail - git - wget - ]; + environment.systemPackages = with pkgs; [ + #procmail + git + wget + ]; - nix.settings.trusted-users = [ "root" "djm" ]; - nix.optimise.automatic = true; - nix.optimise.dates = [ "03:00" ]; + nix.settings.trusted-users = [ + "root" + "djm" + ]; + nix.optimise.automatic = true; + nix.optimise.dates = [ "03:00" ]; - i18n.defaultLocale = "en_GB.UTF-8"; + i18n.defaultLocale = "en_GB.UTF-8"; - system.stateVersion = "22.05"; + system.stateVersion = "22.05"; } diff --git a/nix-conf/machines/edrahil/hardware-configuration.nix b/nix-conf/machines/edrahil/hardware-configuration.nix index f67b9f4..c8ee3f5 100644 --- a/nix-conf/machines/edrahil/hardware-configuration.nix +++ b/nix-conf/machines/edrahil/hardware-configuration.nix @@ -2,8 +2,16 @@ { imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; boot.loader.grub.device = "/dev/sda"; - boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "vmw_pvscsi" "xen_blkfront" ]; + boot.initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "vmw_pvscsi" + "xen_blkfront" + ]; boot.initrd.kernelModules = [ "nvme" ]; - fileSystems."/" = { device = "/dev/sda1"; fsType = "ext4"; }; - + fileSystems."/" = { + device = "/dev/sda1"; + fsType = "ext4"; + }; + } diff --git a/nix-conf/machines/edrahil/network-configuration.nix b/nix-conf/machines/edrahil/network-configuration.nix new file mode 100644 index 0000000..4b85912 --- /dev/null +++ b/nix-conf/machines/edrahil/network-configuration.nix @@ -0,0 +1,19 @@ +{ ... }: +{ + networking = { + interfaces.ens3.ipv6.addresses = [ + { + # Emulate nix-sops. Technically an anti-pattern, but IP addresses aren't real secrets, and this has to be embedded here, + # as we cannot set a file path to read it from. + # Populate/update with: + # SOPS_AGE_KEY=$(doas ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) sops -d --extract '["ipv6_address"]' machines/edrahil/secrets.yaml | doas tee /root/.config/secrets/ipv6_address + address = builtins.readFile "/root/.config/secrets/ipv6_address"; + prefixLength = 64; + } + ]; + defaultGateway6 = { + address = "fe80::1"; + interface = "ens3"; + }; + }; +} diff --git a/nix-conf/machines/edrahil/secrets.yaml b/nix-conf/machines/edrahil/secrets.yaml new file mode 100644 index 0000000..1f4c31e --- /dev/null +++ b/nix-conf/machines/edrahil/secrets.yaml @@ -0,0 +1,31 @@ +ipv6_address: ENC[AES256_GCM,data:CGQWUSuwmucIEwtlLK0FodXOWjM=,iv:ZLPiACwjOmes+FbezZKjjwUETujhTbT++4zCuoptpkY=,tag:VjMtetJhRDlJXdKAmJlOxQ==,type:str] +restic_password: ENC[AES256_GCM,data:2sxeUDRdh9cPv0ACY9EIP7JcmPFo/w==,iv:bkA/FW82l5gSEOZPtVhSNoATmoJf07kC0FJLAcXFkZU=,tag:PbDY039oBas7CvK8RaFRkA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1tjfctwnwldmyxnu6qmeufgr9l79vyzmrs7fy58v3d0qj4x4nhqhq2gjmlp + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvUGNnbm1Jemc5dVZYM01h + R0h4RlRpVnU1ZGxyL3V2TXdYS2JUSHFNTm1BCjJxdlFFbURjdXBaNjNUdldXNkJy + blZYRkhkZUgxR0lST2MxM3hENUhiQkEKLS0tIDhvYjhpRnpIVnVmV0VoTDFNOXIx + RlB1dXVsdEhETTNUdTRIbGxIMGNFSEkKqeafOyRg3F9dtENNnH5DhJzJU+AEEqrV + nfndOlVQe0G/e8SUzUYjVtD6V6Hj/x8OxN6FSOfZnNFNFHQgJ42jFg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1w7kjp0qdgfyg9cyj5w4qc4fc9qz3w65xw2veazesfgdenqrd3ucqsc5ejv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwSGIvTjdEZGdGWm9ldnow + RGxnZ3RhMmthQXFhOCtaNUk1UGhYSytQdkFnCmY3UUxWVFJKeDE5eG9GNktobndz + UjBLOFBNWmFXSmJ2akRDYitsZm9TcmMKLS0tIDZoTGFxSWpwWmFTNjN6b2Q2T2Y3 + Qm1PWnAvZGcxWGZjcnE4QWJZaDE2cGMKOAfTIipI68eJnOnvpQyLCOyH1KAWd/d/ + SLnJQ+rmh9onA/znahB7Pn3LQtfKLNBADVtwLIuPID0FcgUW7nlOiw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-09-17T13:43:53Z" + mac: ENC[AES256_GCM,data:lVMbjnDvwlw72CiixJkEXCO7a20DYi4zKA8JTf0kSVQR/xjr9WbLpyllNq9Ex+eca/X0yaHBYjyOnBBpgz1h5o4i5iq738VXOEqD9v5BMdOrVmmDNnVcTAXqmWZGE7/pGmkiKef/iXOyJT2vsrrYR0vhgrvo/0WXce1YLUA4NTs=,iv:Y1w/llSNDry+PWz4oA/0MBJ+Ra6ceC1ZHMKb+CPCvE0=,tag:r2RR6ZfGL9TYwHtV9auL3A==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/nix-conf/machines/egalmoth/configuration.nix b/nix-conf/machines/egalmoth/configuration.nix index 66382dd..e47cd45 100644 --- a/nix-conf/machines/egalmoth/configuration.nix +++ b/nix-conf/machines/egalmoth/configuration.nix @@ -1,14 +1,18 @@ -{ config, pkgs, lib, ... }: - { - imports = - [ - ./hardware-configuration.nix - ]; + config, + pkgs, + lib, + ... +}: +let + unstable = import <unstable> { }; +in +{ + imports = [ ./hardware-configuration.nix ]; boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; - boot.kernelParams = ["intel_pstate=enable"]; + boot.kernelParams = [ "intel_pstate=enable" ]; powerManagement = { enable = true; #cpuFreqGovernor = "powersave"; @@ -50,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; @@ -80,13 +83,19 @@ services.xserver.xkb.layout = "gb"; services.printing.enable = true; - services.printing.drivers = [ pkgs.gutenprint pkgs.hplipWithPlugin ]; - - nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ - "hplip" - "corefonts" + services.printing.drivers = [ + pkgs.gutenprint + pkgs.hplipWithPlugin ]; + nixpkgs.config.allowUnfreePredicate = + pkg: + builtins.elem (lib.getName pkg) [ + "corefonts" + "hplip" + "zoom" + ]; + hardware.sane.enable = true; services.udev.packages = [ @@ -118,31 +127,40 @@ pulse.enable = true; }; - users.users.djm = - { isNormalUser = true; - description = "David Morgan"; - extraGroups = [ "wheel" "networkmanager" "scanner" "lp" "plocate" "cdrom" ]; - shell = pkgs.zsh; - openssh.authorizedKeys.keys = [ + users.users.djm = { + isNormalUser = true; + description = "David Morgan"; + extraGroups = [ + "wheel" + "networkmanager" + "scanner" + "lp" + "plocate" + "cdrom" + "disk" + ]; + shell = pkgs.zsh; + openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCurCpxZCHtByB5wXzsjTXwMyDSB4+B8rq5XY6EGss58NwD8jc5cII4i+QUbCOGTiAggSZUSC9YIP24hjpOeNT/IYs5m7Qn1B9MtBAiUSrIYew8eDwnMLlPzN+k2x9zCrJeCHIvGJaFHPXTh1Lf5Jt2fPVGW9lksE/XUVOe6ht4N/b+nqqszXFhc8Ug6le2bC1YeTCVEf8pjlh/I7DkDBl6IB8uEXc3X2vxxbV0Z4vlBrFkkAywcD3j5VlS/QYfBr4BICNmq/sO3fMkbMbtAPwuFxeL4+h6426AARQZiSS0qVEc8OoFRBVx3GEH5fqVAWfB1geyLzei22HbjUcT9+xN davidmo@gendros" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK9UDTaVnUOU/JknrNdihlhhGOk53LmHq9I1ASri3aga djm@gaius" - ]; - }; - security.sudo.extraConfig = '' - djm ALL=(ALL) NOPASSWD: ALL - ''; - security.doas = { - enable = true; - extraRules = [ { users = [ "djm" ]; noPass = true; keepEnv = true; } ]; - }; - - - services.locate = { + ]; + }; + security.sudo.extraConfig = '' + djm ALL=(ALL) NOPASSWD: ALL + ''; + security.doas = { enable = true; - package = pkgs.plocate; - localuser = null; + extraRules = [ + { + users = [ "djm" ]; + noPass = true; + keepEnv = true; + } + ]; }; + services.locate.enable = true; + environment.systemPackages = with pkgs; [ acpi acpitool @@ -160,19 +178,25 @@ rofi st sway - vim + vdhcoapp + ungoogled-chromium wayland wayst wezterm wl-clipboard wget xclip + xorg.xkill xurls xst + zoom-us libreoffice onlyoffice-bin ]; + programs.nix-ld.enable = true; + + programs.nix-ld.libraries = with pkgs; [ xorg.libxcb ]; fonts.packages = with pkgs; [ corefonts @@ -180,6 +204,7 @@ iosevka-bin jetbrains-mono meslo-lgs-nf + unstable.aporetic ]; programs.zsh.enable = true; @@ -194,7 +219,10 @@ enableSSHSupport = true; }; - programs.vim.defaultEditor = true; + programs.vim = { + enable = true; + defaultEditor = true; + }; services.openssh.enable = true; @@ -203,4 +231,3 @@ system.stateVersion = "21.05"; # Did you read the comment? } - diff --git a/nix-conf/machines/egalmoth/hardware-configuration.nix b/nix-conf/machines/egalmoth/hardware-configuration.nix index 4a5ae74..e5cb5f7 100644 --- a/nix-conf/machines/egalmoth/hardware-configuration.nix +++ b/nix-conf/machines/egalmoth/hardware-configuration.nix @@ -1,31 +1,40 @@ # Do not modify this file! It was generated by ‘nixos-generate-config’ # and may be overwritten by future invocations. Please make changes # to /etc/nixos/configuration.nix instead. -{ config, lib, pkgs, modulesPath, ... }: +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") - ]; + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; - boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ]; + boot.initrd.availableKernelModules = [ + "xhci_pci" + "thunderbolt" + "nvme" + "usb_storage" + "sd_mod" + "rtsx_pci_sdmmc" + ]; boot.initrd.kernelModules = [ ]; boot.kernelModules = [ "kvm-intel" ]; boot.extraModulePackages = [ ]; - fileSystems."/" = - { device = "/dev/disk/by-uuid/b2189909-19fe-4f58-a8ff-4de288199843"; - fsType = "ext4"; - }; + fileSystems."/" = { + device = "/dev/disk/by-uuid/b2189909-19fe-4f58-a8ff-4de288199843"; + fsType = "ext4"; + }; - fileSystems."/boot" = - { device = "/dev/disk/by-uuid/6ED1-F330"; - fsType = "vfat"; - }; + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/6ED1-F330"; + fsType = "vfat"; + }; - swapDevices = - [ { device = "/dev/disk/by-uuid/a130cacb-d7e0-4fb8-a312-a34d19f00796"; } - ]; + swapDevices = [ { device = "/dev/disk/by-uuid/a130cacb-d7e0-4fb8-a312-a34d19f00796"; } ]; powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; } diff --git a/setup-home.sh b/setup-home.sh index 4a417e6..f44f0d5 100755 --- a/setup-home.sh +++ b/setup-home.sh @@ -1,5 +1,7 @@ #!/bin/sh +[ -f ~/.config/sops/age/keys.txt ] || ( echo "Age key not present, aborting." ; exit 1 ) + [ -e ~/dotfiles ] || git clone git@codeberg.org:djm/dotfiles.git if [ -x "$(command -v nixos-version)" ]; then @@ -12,6 +14,8 @@ else nix-channel --add https://nixos.org/channels/nixpkgs-unstable unstable fi +nix-channel --add https://github.com/Mic92/sops-nix/archive/master.tar.gz sops-nix + nix-channel --update export NIX_PATH=$HOME/.nix-defexpr/channels:/nix/var/nix/profiles/per-user/root/channels${NIX_PATH:+:$NIX_PATH} @@ -22,8 +26,6 @@ HOME_CONF="$HOME/dotfiles/nix-conf/home/${CONF:-${HOST}}.nix" ln -sf ~/dotfiles/.p10k.zsh ~/ ln -sf ~/dotfiles/.emacs.d ~/ -echo -n $EMAIL > ~/email.txt - home-manager switch if [ "$(uname 2> /dev/null)" = "Darwin" ]; then |