;;; emacs init --- an init for emacs -*- lexical-binding: t; -*- ;; by C. Duckworth ;; URL: https://git.acdw.net/emacs ;; Bankruptcy: 9 ;; ;; Everyone is permitted to do whatever they like with this software ;; without limitation. This software comes without any warranty ;; whatsoever, but with two pieces of advice: ;; - Be kind to yourself. ;; - Make good choices. (yoke +emacs (require* '+emacs '+window '+lisp) ;; Settings (setf truncate-string-ellipsis "…" ring-bell-function #'ignore read-file-name-completion-ignore-case t comment-auto-fill-only-comments t password-cache t password-cache-expiry (* 60 60) initial-buffer-choice (defun +initial-buffer-choose () (cond ((equal (get-buffer "*Messages*") (other-buffer)) (get-buffer "*scratch*")) (:else (other-buffer))))) ;; "Safe" variables (dolist (var+pred '((browse-url-browser-function ;; All types defined by custom are safe. . (lambda (f) ;; Whooooo boy (memq f (mapcar (lambda (i) (plist-get (cdr i) :value)) (seq-filter (lambda (i) (eq (car i) 'function-item)) (cdr (get 'browse-url-browser-function 'custom-type))))))))) (put (car var+pred) 'safe-local-variable (cdr var+pred))) ;; Keys (define-key* (current-global-map) "C-x C-k" #'kill-current-buffer "C-/" #'undo-only "C-?" #'undo-redo "C-x C-c" (defun delete-frame-or-quit (arg) (interactive "P") (cond (arg (delete-frame nil :force)) ((= 1 (length (frame-list))) (and (yes-or-no-p "Kill emacs? ") (save-buffers-kill-emacs t))) (:else (delete-frame)))) "C-x r q" (defun really-quit-emacs (arg) (interactive "P") (cond (arg (save-buffers-kill-emacs t)) (:else (save-buffers-kill-terminal t)))) "M-SPC" #'+cycle-spacing ;; "M-/" #'hippie-expand ; `hippie-completing-read' "M-=" #'count-words "C-x C-b" #'ibuffer "C-x 4 n" #'clone-buffer "S-" #'mouse-set-mark "C-x 0" #'+delete-window-or-bury-buffer ;; "M-j" nil ; `avy' "" nil "C-z" nil "M-o" #'other-window|switch-buffer "C-M-;" #'+lisp-comment-or-uncomment-sexp "C-x 5 z" #'suspend-frame "M-@" #'dictionary-search) (define-key* text-mode-map "C-M-k" #'kill-paragraph) ;; Hooks (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) (add-hook 'find-file-not-found-functions #'+auto-create-missing-dirs) (add-hook 'text-mode-hook #'abbrev-mode) (add-hook 'find-file-hook #'+vc-off-when-remote) (add-hook 'prog-mode-hook #'auto-fill-mode) ;; Advice (add-function :after after-focus-change-function #'+save-some-buffers-debounce) (define-advice keyboard-escape-quit (:around (fn &rest r) keep-window-open) "Don't close quits on `keyboard-escape-quit'." (let ((buffer-quit-function #'ignore)) (apply fn r))) ;; Themes (load-theme 'modus-operandi) (set-face-attribute 'default nil :family "Comic Code" :height 100) (set-face-attribute 'bold nil :family "Comic Code" :weight 'bold) (set-face-attribute 'variable-pitch nil :family "Comic Code") ;; Modes (winner-mode)) (yoke custom ; This is `cus-edit' but meh (require '+custom) (setf custom-file (private/ "custom.el")) (add-to-list* '+custom-allowed-variables 'safe-local-variable-values 'warning-suppress-types 'ispell-buffer-session-localwords) (eval-after init (+custom-load-some-customizations :noerror))) (yoke time (setf display-time-mail-function (defun +notmuch-new-mail-p () (plist-get (cl-find "inbox+unread" (ignore-errors (notmuch-hello-query-counts notmuch-saved-searches)) :key (lambda (l) (plist-get l :name)) :test #'equal) :count)) display-time-use-mail-icon t read-mail-command #'+notmuch-goto display-time-24hr-format t display-time-day-and-date t display-time-default-load-average nil) (display-time-mode)) (yoke pita (require 'pita) (advice-add 'indent-region :before #'with-region-or-buffer)) (yoke (undo-fu-session "https://codeberg.org/ideasman42/emacs-undo-fu-session") (setf undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'") undo-fu-session-directory (.etc "undo/" t) undo-fu-session-compression (cond ((executable-find "gzip") 'gz) ((executable-find "bzip2") 'bz2) ((executable-find "xz") 'xz) (t nil))) (global-undo-fu-session-mode)) (yoke whitespace (setf whitespace-line-column nil whitespace-style '( face trailing tabs tab-mark indentation space-after-tab space-before-tab)) (defun +whitespace-mode-for-writable-buffers () "Turn on `whitespace-mode' if the buffer is writable, off otherwise." (whitespace-mode (if buffer-read-only -1 t))) (add-hook* '(text-mode-hook prog-mode-hook read-only-mode-hook) #'+whitespace-mode-for-writable-buffers) (add-hook 'before-save-hook #'whitespace-cleanup) (define-advice whitespace-cleanup (:around (fn &rest r) preserve-point) (let ((col (current-column))) (apply fn r) (move-to-column col t) (set-buffer-modified-p nil)))) (yoke elisp-mode (setf eval-expression-print-length nil ; remove ellipses from `eval-expression' eval-expression-print-level nil) (define-key* '(emacs-lisp-mode-map lisp-interaction-mode-map) "C-c C-c" #'eval-defun "C-c C-k" (defun +elisp-eval-region-or-buffer () (interactive) (cond ((region-active-p) (eval-region (region-beginning) (region-end)) (message "Region evaluated.")) (t (eval-buffer) (message "Buffer %s evaluated." (buffer-name))))) "C-c C-z" #'ielm) (define-advice eval-region (:around (fn beg end &rest args) pulse) (apply fn beg end args) (pulse-momentary-highlight-region beg end))) (yoke isearch (define-key* (current-global-map) "C-s" #'isearch-forward-regexp "C-r" #'isearch-backward-regexp "C-M-s" #'isearch-forward "C-M-r" #'isearch-backward)) (yoke ispell (require* '+ispell 'ispell) (add-hook 'before-save-hook #'+ispell-move-buffer-words-to-dir-locals-hook) (setf ispell-program-name (or (executable-find "ispell") (executable-find "aspell"))) (put 'ispell-buffer-session-localwords 'safe-local-variable #'+ispell-safe-local-p)) (yoke mouse ;; Brand new for Emacs 28: see https://ruzkuku.com/texts/emacs-mouse.html ;; Actually, look at this as well: https://www.emacswiki.org/emacs/Mouse3 (when (fboundp 'context-menu-mode) (setf context-menu-functions '(context-menu-ffap context-menu-region context-menu-undo ;; context-menu-dictionary )) (context-menu-mode +1)) (dolist (click '(;; Fix scrolling in the margin wheel-down double-wheel-down triple-wheel-down wheel-up double-wheel-up triple-wheel-up)) (global-set-key (vector 'right-margin click) 'mwheel-scroll) (global-set-key (vector 'left-margin click) 'mwheel-scroll))) (yoke dired (require 'dired-x) (setf dired-recursive-copies 'always dired-recursive-deletes 'always dired-create-destination-dirs 'always dired-do-revert-buffer t dired-hide-details-hide-symlink-targets nil dired-isearch-filenames 'dwim delete-by-moving-to-trash t dired-auto-revert-buffer t dired-listing-switches "-AlF" ls-lisp-dirs-first t dired-ls-F-marks-symlinks t dired-clean-confirm-killing-deleted-buffers nil dired-no-confirm '(byte-compile load chgrp chmod chown copy move hardlink symlink shell touch) dired-dwim-target t) (setq-local-hook dired-mode-hook truncate-lines t) (define-key* (current-global-map) "C-x C-j" #'dired-jump) (eval-after dired (define-key* dired-mode-map "" #'dired-up-directory "C-j" #'dired-up-directory)) (add-hook* 'dired-mode-hook #'dired-hide-details-mode #'hl-line-mode)) (yoke (dired-hacks "https://github.com/Fuco1/dired-hacks") (define-key* dired-mode-map "TAB" #'dired-subtree-sycle "i" #'dired-subtree-toggle) (add-hook* 'dired-mode-hook #'dired-collapse-mode)) (yoke auth-source (setf auth-sources `(default "secrets:passwords")) (setq-local-hook authinfo-mode-hook truncate-lines t)) (yoke (consult "https://github.com/minad/consult") (require 'consult) (setf register-preview-delay 0 register-preview-function #'consult-register-format xref-show-xrefs-function #'consult-xref tab-always-indent 'complete completion-in-region-function #'consult-completion-in-region consult-narrow-key "<" consult--regexp-compiler #'consult--default-regexp-compiler) (advice-add #'register-preview :override #'consult-register-window) (define-key* (current-global-map) ;; Etc "C-x m" #'consult-mode-command ;; C-c bindings (mode-specific-map) "C-c h" #'consult-history "C-c b" #'consult-bookmark "C-c k" #'consult-kmacro ;; C-x bindings (ctl-x-map) "C-x M-:" #'consult-complex-command "C-x b" #'consult-buffer "C-x 4 b" #'consult-buffer-other-window "C-x 5 b" #'consult-buffer-other-frame ;; Custom M-# bindings for fast register access "M-#" #'consult-register-load "M-'" #'consult-register-store "C-M-#" #'consult-register ;; Other custom bindings "M-y" #'consult-yank-pop ;;(" a" . consult-apropos) ;; M-g bindings (goto-map) "M-g e" #'consult-compile-error "M-g f" #'consult-flymake ; or consult-flycheck "M-g g" #'consult-goto-line "M-g M-g" #'consult-goto-line "M-g o" #'consult-outline ; or consult-org-heading "M-g m" #'consult-mark "M-g k" #'consult-global-mark "M-g i" #'consult-imenu "M-g M-i" #'consult-imenu "M-g I" #'consult-imenu-multi ;; M-s bindings (search-map) "M-s f" #'consult-find "M-s F" #'consult-locate "M-s g" #'consult-grep "M-s G" #'consult-git-grep "M-s r" #'consult-ripgrep "M-s l" #'consult-line "M-s L" #'consult-line-multi "M-s m" #'consult-multi-occur "M-s k" #'consult-keep-lines "M-s u" #'consult-focus-lines ;; Isearch integration "M-s e" #'consult-isearch-history) (eval-after isearch-mode (define-key* isearch-mode-map "M-e" #'consult-isearch-history "M-s e" #'consult-isearch-history "M-s l" #'consult-line "M-s L" #'consult-line-multi)) (eval-after org (define-key org-mode-map (kbd "M-g o") #'consult-org-heading)) (eval-after consult-imenu (setf (alist-get ?y (plist-get (alist-get 'emacs-lisp-mode consult-imenu-config) :types)) '("Yoke")))) (yoke (orderless "https://github.com/oantolin/orderless") (require 'orderless) (setf completion-styles '(substring orderless basic) completion-category-defaults nil completion-category-overrides '((file (styles basic partial-completion))) orderless-component-separator #'orderless-escapable-split-on-space)) (yoke (vertico "https://github.com/minad/vertico") (require 'vertico) (setf resize-mini-windows 'grow-only vertico-count-format nil vertico-cycle t) (vertico-mode)) (yoke (embark "https://github.com/oantolin/embark") (require 'embark) (setf prefix-help-command #'embark-prefix-help-command embar-keymap-prompter-key ";") (define-key* (list (current-global-map) 'minibuffer-local-map) "C-." #'embark-act "M-." #'embark-dwim " B" #'embark-bindings) (define-key* embark-file-map "l" #'vlf) (eval-after (embark consult) (require 'embark-consult) (add-hook 'embark-collect-mode-hook #'consult-preview-at-point-mode))) (yoke (marginalia "https://github.com/minad/marginalia/") (marginalia-mode)) (yoke (wgrep "https://github.com/mhayashi1120/Emacs-wgrep") (require 'wgrep)) ;; (yoke (slime "https://github.com/slime/slime") ;; ;; r7rs-swank ;; (let ((r7rsloc (yoke-git "https://github.com/ecraven/r7rs-swank"))) ;; (cond ;; ((executable-find "chibi-scheme") ;; (defun chibi-scheme-start-swank (file encoding) ;; (format "%S\n\n" `(start-swank ,file))) ;; (setq slime-lisp-implementations ;; (cons `(chibi-scheme ;; ("chibi-scheme" ,(format "-A%s" r7rsloc) ;; "-m" "(chibi-swank)") ;; :init chibi-scheme-start-swank) ;; (bound-and-true-p slime-lisp-implementations))) ;; ;; (add-hook* 'scheme-mode-hook #'slime-mode) ;; (setf slime-completion-at-point-functions ;; (delq 'slime-c-p-c-completion-at-point ;; slime-completion-at-point-functions)))))) (yoke (puni "https://github.com/amaikinono/puni") (define-key* puni-mode-map "C-)" #'puni-slurp-forward "C-(" #'puni-slurp-backward "C-}" #'puni-barf-forward "C-{" #'puni-barf-backward "M-(" (defun +puni-open-then-slurp-forward (&optional n) (interactive "p") (insert "()") (backward-char) (puni-slurp-forward n))) (electric-pair-mode) (add-hook* '(prog-mode-hook ielm-mode-hook lisp-interaction-mode-hook lisp-mode-hook scheme-mode-hook) #'puni-mode)) (yoke (hungry-delete "https://github.com/nflath/hungry-delete") (setq hungry-delete-chars-to-skip " \t" hungry-delete-join-reluctantly nil) (eval-after hungry-delete (add-to-list* 'hungry-delete-except-modes #'eshell-mode #'nim-mode #'python-mode)) (defun +hungry-delete-or (hd-fn fn arg) (funcall (if (looking-back (format "[%s]" hungry-delete-chars-to-skip) arg) hd-fn fn) arg)) (define-key* puni-mode-map [remap puni-backward-delete-char] (defun puni@hungry-delete-backward (arg) (interactive "p") (+hungry-delete-or #'hungry-delete-backward #'puni-backward-delete-char arg)) [remap puni-forward-delete-char] (defun puni@hungry-delete-forward (arg) (interactive "p") (+hungry-delete-or #'hungry-delete-forward #'puni-forward-delete-char arg))) (global-hungry-delete-mode)) (yoke (cape "https://github.com/minad/cape") ;; Insinuate in a lot of modes (defvar +capes '(cape-file cape-dabbrev)) (defun +cape-insinuate (hook capf &optional capes) "Insinuate CAPES into a HOOK along with CAPF function. CAPES defaults to `+capes'. CAPF will be made un-exclusive." (setq-local-hook hook completion-at-point-functions (apply #'list (cape-capf-properties capf :exclusive 'no) (or capes +capes)))) (+cape-insinuate 'emacs-lisp-mode-hook #'elisp-completion-at-point)) (yoke (minions "https://github.com/tarsius/minions") (minions-mode)) (yoke (magit "https://github.com/magit/magit" :load "lisp") :depends ((transient "https://github.com/magit/transient" :load "lisp") (dash "https://github.com/magnars/dash.el") (with-editor "https://github.com/magit/with-editor" :load "lisp")) (autoload #'transient--with-suspended-override "transient") (autoload #'magit "magit" nil :interactive) (define-key* (current-global-map) "C-x g" #'magit)) (yoke (git-modes "https://github.com/magit/git-modes") (require 'git-modes)) (yoke (visual-fill-column "https://codeberg.org/joostkremers/visual-fill-column") (setq visual-fill-column-center-text t) (add-hook* 'visual-fill-column-mode-hook #'visual-line-mode) (advice-add 'text-scale-adjust :after #'visual-fill-column-adjust)) (yoke (org "https://git.savannah.gnu.org/git/emacs/org-mode.git" :load "lisp") :depends ((org-contrib "https://git.sr.ht/~bzg/org-contrib" :load "lisp")) ;; DON'T load system org (setq load-path (cl-remove-if (lambda (path) (string-match-p "lisp/org\\'" path)) load-path)) (setq org-adapt-indentation nil org-auto-align-tags t org-archive-mark-done t org-fold-catch-invisible-edits 'show-and-error org-clock-clocked-in-display 'mode-line org-clock-frame-title-format (cons '(t org-mode-line-string) (cons " --- " frame-title-format)) org-clock-string-limit 7 ; just the clock bit ;; org-clock-string-limit 25 ; gives enough information org-clock-persist nil org-confirm-babel-evaluate nil org-cycle-separator-lines 0 org-directory (sync/ "org/" t) org-ellipsis (or truncate-string-ellipsis "…") org-fontify-done-headline t org-fontify-quote-and-verse-blocks t org-fontify-whole-heading-line t org-hide-emphasis-markers t org-html-coding-system 'utf-8-unix org-image-actual-width (list (* (window-font-width) (- fill-column 8))) org-imenu-depth 3 org-indent-indentation-per-level 0 org-indent-mode-turns-on-hiding-stars nil org-insert-heading-respect-content t org-list-demote-modify-bullet '(("-" . "+") ("+" . "-")) org-log-done 'time org-log-into-drawer t org-num-skip-commented t org-num-skip-unnumbered t org-num-skip-footnotes t org-outline-path-complete-in-steps nil org-pretty-entities t org-pretty-entities-include-sub-superscripts nil org-refile-targets '((nil . (:maxlevel . 2)) (org-agenda-files . (:maxlevel . 1))) org-refile-use-outline-path 'file org-special-ctrl-a/e t org-special-ctrl-k t org-src-fontify-natively t org-src-tab-acts-natively t org-src-window-setup 'current-window org-startup-truncated nil org-startup-with-inline-images t org-tags-column -77 ;; (- (- fill-column 1 (length org-ellipsis))) org-todo-keywords '((sequence "TODO(t)" "WAIT(w@/!)" "ONGOING(o@)" "|" "DONE(d!)" "ASSIGNED(a@/!)") (sequence "|" "CANCELED(k@)") (sequence "MEETING(m)")) org-use-speed-commands t org-emphasis-alist '(("*" org-bold) ("/" org-italic) ("_" org-underline) ("=" org-verbatim) ("~" org-code) ("+" org-strikethrough))) (add-hook* 'org-mode-hook #'variable-pitch-mode #'visual-fill-column-mode #'turn-off-auto-fill #'org-indent-mode #'prettify-symbols-mode #'abbrev-mode) (define-local-before-save-hook org-mode (org-hide-drawer-all) (org-align-tags 'all)) (eval-after org (require '+org) (define-key* org-mode-map "C-M-k" #'kill-paragraph "C-M-t" #'transpose-paragraphs "RET" #'+org-return-dwim "S-" #'+org-table-copy-down|+org-return "C-c C-o" #'+org-open-at-point-dwim) (org-clock-persistence-insinuate))) (yoke org-agenda nil (setq org-agenda-skip-deadline-if-done t org-agenda-skip-scheduled-if-done t org-agenda-span 10 org-agenda-block-separator ?─ org-agenda-time-grid '((daily today require-timed) (800 1000 1200 1400 1600 1800 2000) " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄") org-agenda-current-time-string "← now ─────────────────────────────────────────────────" org-agenda-include-diary nil ; I use the org-diary features org-agenda-todo-ignore-deadlines 'near org-agenda-todo-ignore-scheduled 'future org-agenda-include-deadlines t org-deadline-warning-days 0 org-agenda-show-future-repeats 'next org-agenda-window-setup 'current-window) (setq-local-hook org-agenda-mode-hook truncate-lines t electric-pair-pairs (append electric-pair-pairs (mapcar (lambda (e) (let ((ch (string-to-char (car e)))) (cons ch ch))) org-emphasis-alist))) (add-hook* 'org-agenda-mode-hook #'hl-line-mode) (add-hook 'org-agenda-after-show-hook #'org-narrow-to-subtree) (define-key* (current-global-map) "C-c c" #'org-capture "C-c a" #'org-agenda) (eval-after org-capture '+org-capture)) (yoke ox ; org-export (eval-after org (require 'ox)) (eval-after ox (require* '+ox '(ox-md nil t)) (+org-export-pre-hooks-insinuate)) (setq org-export-coding-system 'utf-8-unix org-export-headline-levels 8 org-export-with-drawers nil org-export-with-section-numbers nil org-export-with-smart-quotes t org-export-with-sub-superscripts t org-export-with-toc nil)) (yoke (electric-cursor "https://codeberg.org/acdw/electric-cursor.el") (setq electric-cursor-alist '((overwrite-mode . hbar) (t . bar))) (electric-cursor-mode)) (yoke _work :depends ((bbdb "https://git.savannah.nongnu.org/git/bbdb.git" :load "lisp") (bbdb-vcard "https://github.com/tohojo/bbdb-vcard/")) (setf bbdb-complete-mail-allow-cycling t) (add-hook* '+custom-after-load-hook (defun _work@after-custom () (require* 'private '_work) (require* 'bbdb 'bbdb-message) (bbdb-initialize 'gnus 'message)))) (yoke (org-taskwise "https://codeberg.org/acdw/org-taskwise.el")) (yoke scule (require 'scule) (defvar scule-map (let ((map (make-sparse-keymap))) (define-key map (kbd "M-u") #'scule-upcase) (define-key map (kbd "M-l") #'scule-downcase) (define-key map (kbd "M-c") #'scule-capitalize) map) "Keymap for scule twiddling.") (define-key* (current-global-map) "M-c" scule-map "M-u" #'universal-argument) (define-key universal-argument-map (kbd "M-u") #'universal-argument-more)) (yoke (titlecase "https://codeberg.org/acdw/titlecase.el") (eval-after titlecase (add-to-list* 'titlecase-skip-words-regexps (rx word-boundary (+ (any upper digit)) word-boundary))) (eval-after scule (define-key* scule-map "M-t" #'titlecase-dwim))) (yoke (flyspell-correct "https://github.com/duckwork/flyspell-correct") (eval-after flyspell (require* 'flyspell-correct `(+flyspell-correct ,(locate-user-emacs-file "lisp/+flyspell-correct"))) (define-key* flyspell-mode-map "C-;" #'flyspell-correct-wrapper "" #'+flyspell-correct-buffer "C-," nil "C-." nil)) (add-hook 'org-mode-hook #'flyspell-mode) (setq flyspell-correct--cr-key ";")) (yoke (helpful "https://github.com/Wilfred/helpful") :depends ((dash "https://github.com/magnars/dash.el") (f "https://github.com/rejeep/f.el") (s "https://github.com/magnars/s.el") (elisp-refs "https://github.com/Wilfred/elisp-refs")) (define-key* (current-global-map) " f" #'helpful-callable " v" #'helpful-variable " k" #'helpful-key " ." #'helpful-at-point " o" #'helpful-symbol) (unless (featurep 'info-look) (run-with-idle-timer 1 nil (lambda () (require 'info-look) (let ((inhibit-message t)) (info-lookup-setup-mode 'symbol 'emacs-lisp-mode))))) (setf (alist-get "\\*helpful" display-buffer-alist nil nil #'string=) '((display-buffer-in-side-window) (side . bottom) (window-height . 20)))) (yoke (hippie-completing-read "https://codeberg.org/acdw/hippie-completing-read.el") (define-key* (current-global-map) "M-/" #'hippie-completing-read)) (yoke dictionary ; Comes with Emacs 29! (setq dictionary-server (if (or (executable-find "dictd") (file-exists-p "/usr/sbin/dictd")) ; oh debian "localhost" "dict.org")) (setf (alist-get "^\\*Dictionary\\*" display-buffer-alist nil nil #'string=) '((display-buffer-in-side-window) (side . bottom) (window-height . 20))) (eval-after org (define-key* org-mode-map "M-@" #'dictionary-search)) (eval-after embark (define-key* embark-identifier-map "@" #'dictionary-search))) (yoke (anzu "https://github.com/emacsorphanage/anzu") (global-anzu-mode) (define-key* (current-global-map) [remap query-replace] #'anzu-query-replace-regexp [remap query-replace-regexp] #'anzu-query-replace) (define-key* isearch-mode-map [remap isearch-query-replace] #'anzu-isearch-query-replace-regexp [remap isearch-query-replace-regexp] #'anzu-isearch-query-replace) (defun anzu-qr@window (fn &rest r) "ADVICE to query-replace from the beginning of the window." (let ((scroll-margin 0)) (save-excursion (goto-char (window-start)) (apply fn r)))) (advice-add 'anzu-query-replace-regexp :around #'anzu-qr@window) (advice-add 'anzu-query-replace :around #'anzu-qr@window)) (yoke tempo (require '+tempo)) (yoke (0x0 "https://gitlab.com/willvaughn/emacs-0x0") (setf 0x0-default-server 'ttm) (eval-after embark (define-key* embark-region-map "U" #'0x0-dwim))) (yoke (filldent "https://codeberg.org/acdw/filldent.el") (define-key* (current-global-map) "M-q" #'filldent-unfill-toggle)) (yoke (avy "https://github.com/abo-abo/avy") (require 'avy) (setf avy-background t (alist-get ?. avy-dispatch-alist) (defun avy-action-embark (pt) (unwind-protect (save-excursion (goto-char pt) (embark-act)) (select-window (cdr (ring-ref avy-ring 0)))) t)) (define-key* (current-global-map) "M-j" #'avy-goto-char-timer) (define-key* isearch-mode-map "M-j" #'avy-isearch)) (yoke (frowny "https://codeberg.org/acdw/frowny.el") (setf frowny-eyes (rx (any ":=") (opt "'") (? "-"))) (global-frowny-mode)) (yoke (isearch-mb "https://github.com/astoff/isearch-mb") (eval-after (consult anzu) (require 'isearch-mb) (dolist (spec '((isearch-mb--with-buffer ("M-e" . consult-isearch) ("C-o" . loccur-isearch)) (isearch-mb--after-exit ("M-%" . anzu-isearch-query-replace) ("M-s l" . consult-line)))) (let ((isearch-mb-list (car spec)) (isearch-mb-binds (cdr spec))) (dolist (cell isearch-mb-binds) (let ((key (car cell)) (command (cdr cell))) (when (fboundp command) (add-to-list isearch-mb-list command) (define-key isearch-mb-minibuffer-map (kbd key) command))))))) (isearch-mb-mode)) (yoke (keepassxc-shim "https://codeberg.org/acdw/keepassxc-shim.el") (keepassxc-shim-activate)) (yoke (keychain-environment "https://github.com/tarsius/keychain-environment") :when (executable-find "keychain") (keychain-refresh-environment)) (yoke (sophomore "https://codeberg.org/acdw/sophomore.el") (sophomore-enable #'narrow-to-region) (sophomore-disable #'view-hello-file #'describe-gnu-project) (sophomore-disable-with 'confirm #'save-buffers-kill-terminal)) (yoke (macrostep "https://github.com/joddie/macrostep") (eval-after elisp-mode (require 'macrostep)) (define-key* '(emacs-lisp-mode-map lisp-interaction-mode-map) "C-c e" #'macrostep-expand)) (yoke (embrace "https://github.com/cute-jumper/embrace.el") :depends ((expand-region "https://github.com/magnars/expand-region.el")) (define-key* (current-global-map) "C-=" #'er/expand-region "C-," #'embrace-commander) (eval-after org (define-key* org-mode-map "C-=" #'er/expand-region "C-," #'embrace-commander)) (dolist (fnhook '((org-mode-hook embrace-org-mode-hook) (ruby-mode-hook embrace-ruby-mode-hook) (emacs-lisp-mode-hook embrace-emacs-lisp-mode-hook) (latex-mode-hook embrace-LaTeX-mode-hook))) (apply #'add-hook fnhook)) (eval-after org (defmacro org-insert-or-embrace (char) "Define a function to insert CHAR, or `embrace' the region with it." (let* ((fn-name (intern (format "org-insert-or-embrace-%s" char))) (char (cond ((characterp char) char) ((stringp char) (string-to-char char)) (t (user-error "Bad format for char: %S" char))))) `(defun ,fn-name (n) ,(format "Insert N %ss, or surround the region with them." (char-to-string char)) (interactive "p") (if (region-active-p) (dotimes (_ n) (embrace--add-internal (region-beginning) (region-end) ,char) (forward-char 1)) (self-insert-command n ,char))))) (define-key* org-mode-map "*" (org-insert-or-embrace "*") "/" (org-insert-or-embrace "/") "_" (org-insert-or-embrace "_") "=" (org-insert-or-embrace "=") "~" (org-insert-or-embrace "~") "+" (org-insert-or-embrace "+")))) (yoke (notmuch "~/usr/share/emacs/site-lisp") (eval-after bbdb (require* 'notmuch '+notmuch '+message)) (+define-dir notmuch/ (sync/ "emacs/notmuch") "Notmuch configuration and data.") (setf notmuch-init-file (notmuch/ "notmuch-init.el" t) notmuch-address-save-filename (notmuch/ "addresses" t) notmuch-address-use-company (featurep 'company) notmuch-search-oldest-first nil notmuch-archive-tags '("-inbox" "-unread") notmuch-draft-tags '("+draft" "-inbox" "-unread")) (define-key* (current-global-map) "C-c m" #'notmuch-mua-new-mail "C-c n" #'+notmuch-goto) ;; Reading mail (setf notmuch-show-indent-content nil) (add-hook* '(notmuch-show-mode-hook notmuch-message-mode-hook) #'visual-fill-column-mode) (eval-after notmuch (define-key* notmuch-search-mode-map "RET" #'notmuch-search-show-thread "M-RET" #'notmuch-tree-from-search-thread "!" #'+notmuch-search-mark-spam) (define-key* notmuch-tree-mode-map "!" #'+notmuch-search-mark-spam-then-next)) ;; Writing mail (setf message-kill-buffer-on-exit t message-auto-save-directory nil) ;; Sending mail (setf send-mail-function #'sendmail-send-it mail-specify-envelope-from t message-sendmail-envelope-from 'header message-envelope-from 'header) ;; Extras (eval-after notmuch (require '+notmuch) (load notmuch-init-file :noerror) (add-hook 'message-setup-hook #'+message-signature-setup) (add-hook 'message-send-hook #'+send-mail-dispatch) (advice-add 'notmuch-tag :filter-args #'+notmuch-correct-tags) (setf notmuch-saved-searches (list (list :name "inbox+unread" :query (+notmuch-query-concat "tag:inbox" "tag:unread" "NOT tag:Spam") :key "m" :search-type 'tree) (list :name "inbox" :query (+notmuch-query-concat "tag:inbox" "NOT tag:Spam") :key "i" :search-type 'tree) (list :name "lists+unread" :query (+notmuch-query-concat "tag:/List/" "tag:unread") :key "l" :search-type 'tree) (list :name "lists" :query "tag:/List/" :key "L" :search-type 'tree) (list :name "unread" :query (+notmuch-query-concat "tag:unread" "NOT tag:Spam") :key "u" :search-type 'tree) (list :name "flagged" :query "tag:flagged" :key "f" :search-type 'tree) (list :name "sent" :query "tag:sent" :key "t" :search-type 'tree) (list :name "drafts" :query "tag:draft" :key "d" :search-type 'tree) (list :name "all mail" :query "*" :key "a" :search-type 'tree))))) (yoke (cider "https://github.com/clojure-emacs/cider") :depends ((clojure-mode "http://github.com/clojure-emacs/clojure-mode") (parseedn "https://github.com/clojure-emacs/parseedn/") (parseclj "https://github.com/clojure-emacs/parseclj/") ; parseedn (queue "https://elpa.gnu.org/packages/queue-0.2.el" :type 'http) (spinner "https://github.com/Malabarba/spinner.el") (sesman "https://github.com/vspinu/sesman")) :when (executable-find "clojure"))