summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--init.el2343
-rw-r--r--lisp/acdw.el19
2 files changed, 1198 insertions, 1164 deletions
diff --git a/init.el b/init.el index 60caeaf..4326433 100644 --- a/init.el +++ b/init.el
@@ -16,42 +16,12 @@
16 16
17;;; Code: 17;;; Code:
18 18
19;;; Built-ins
20;; NOTE that some of the names in `setup' forms are arbitrary. 19;; NOTE that some of the names in `setup' forms are arbitrary.
21 20
22(setup (:require auth-source) 21(setup (:straight (0x0
23 (:option auth-sources '("~/.authinfo" "~/.authinfo.gpg"))) 22 :host gitlab
24 23 :repo "willvaughn/emacs-0x0"))
25(setup (:require recentf) 24 (:option 0x0-default-server 'ttm))
26 (:option recentf-save-file (acdw/dir "recentf.el")
27 recentf-max-menu-items 100
28 recentf-max-saved-items nil
29 recentf-auto-cleanup 'mode
30 (append recentf-exclude) (acdw/dir))
31
32 (advice-add 'dired-rename-file :after #'rjs/recentf-rename-notify)
33
34 (recentf-mode +1))
35
36(setup (:require savehist)
37 (:option history-length t
38 history-delete-duplicates t
39 savehist-autosave-interval 60
40 savehist-file (acdw/dir "savehist.el"))
41
42 (dolist (var '(extended-command-history
43 global-mark-ring
44 kill-ring
45 regexp-search-ring
46 search-ring
47 mark-ring))
48 (add-to-list 'savehist-additional-variables var))
49
50 (savehist-mode +1))
51
52(setup (:require server)
53 (unless (server-running-p)
54 (server-start)))
55 25
56(setup Info 26(setup Info
57 (:hook variable-pitch-mode 27 (:hook variable-pitch-mode
@@ -73,12 +43,83 @@
73 43
74 (when-let ((default-directory 44 (when-let ((default-directory
75 (expand-file-name-exists-p "pkg/" user-emacs-directory))) 45 (expand-file-name-exists-p "pkg/" user-emacs-directory)))
76 (normal-top-level-add-subdirs-to-load-path))) 46 (normal-top-level-add-subdirs-to-load-path))
47
48 (defun acdw/sort-setups ()
49 "Sort `setup' forms in the current buffer.
50Actually sorts all forms, but based on the logic of `setup'.
51AKA, DO NOT USE THIS FUNCTION!!!"
52 (save-excursion
53 (sort-sexps (point-min) (point-max)
54 (lambda (sexp)
55 (let ((name (cadr sexp)))
56 (symbol-name (if (listp name) ; this is /terrible/!
57 (if (keywordp (car name))
58 (let ((feature (cadr name)))
59 (if (listp feature)
60 (car feature)
61 feature))
62 (car name))
63 name))))))))
64
65(setup (:straight-if affe
66 (and (or (executable-find "fd")
67 (executable-find "find"))
68 (executable-find "rg")))
69 ;; Keys are bound in `acdw/sensible-grep' and `acdw/sensible-find'
70 (:option affe-regexp-compiler
71 (defun affe-orderless-regexp-compiler (input _type)
72 (setq input (orderless-pattern-compiler input))
73 (cons input (lambda (str) (orderless--highlight input str))))))
74
75(setup (:straight-if ahk-mode
76 (acdw/system :work)))
77
78(setup (:straight alert)
79 (:option alert-default-style (acdw/system
80 (:home 'libnotify)
81 (_ 'message))))
82
83(setup (:straight (apheleia
84 :host github
85 :repo "raxod502/apheleia"))
86
87 (apheleia-global-mode +1)
88
89 ;; Use a dumb formatter on modes that `apheleia' doesn't work for.
90 (add-hook 'before-save-hook
91 (defun before-save@dumb-auto-format ()
92 (setq stupid-modes '(makefile-mode
93 org-mode))
94 ;; If there's no apheleia formatter for the mode, just indent the
95 ;; buffer.
96 (unless (or (apply #'derived-mode-p stupid-modes)
97 (and (fboundp 'apheleia--get-formatter-command)
98 (apheleia--get-formatter-command)))
99 (indent-region (point-min) (point-max))))))
100
101(setup (:straight async)
102 (dired-async-mode +1)
103
104 (:with-feature dired
105 (:hook (defun dired@disable-dired-async-mode-line ()
106 (autoload 'dired-async--modeline-mode "dired-async" nil t)
107 (dired-async--modeline-mode -1)))))
108
109(setup (:require auth-source)
110 (:option auth-sources '("~/.authinfo" "~/.authinfo.gpg")))
77 111
78(setup autorevert 112(setup autorevert
79 (:option global-auto-revert-non-file-buffers t) 113 (:option global-auto-revert-non-file-buffers t)
80 (global-auto-revert-mode +1)) 114 (global-auto-revert-mode +1))
81 115
116(setup (:straight avy)
117 (:global "C-:" #'avy-goto-char-timer
118 "C-c C-j" #'avy-resume)
119
120 (:with-feature isearch
121 (:bind "C-'" #'avy-isearch)))
122
82(setup browse-url 123(setup browse-url
83 (:require acdw-browse-url) 124 (:require acdw-browse-url)
84 125
@@ -127,6 +168,106 @@
127(setup calendar 168(setup calendar
128 (:option calendar-week-start-day 1)) 169 (:option calendar-week-start-day 1))
129 170
171(setup (:straight circe)
172 (require 'circe)
173 (require 'acdw-irc)
174
175 (:option acdw-irc/left-margin 12
176 acdw-irc/post-my-nick "-> "
177 circe-channel-killed-confirmation nil
178 circe-color-nicks-everywhere t
179 circe-default-nick "acdw"
180 circe-default-part-message "See You, Space Cowpokes . . ."
181 circe-default-user "acdw"
182 circe-format-action
183 (lambda (&rest plist)
184 (concat
185 (acdw-irc/margin-format "" "*" "*" t)
186 " " (plist-get plist :nick) " " (plist-get plist :body)))
187 circe-format-say
188 (lambda (&rest plist)
189 (concat
190 (acdw-irc/margin-format (plist-get plist :nick) "" " |" t)
191 " " (plist-get plist :body)))
192 circe-format-self-action
193 (lambda (&rest plist)
194 (concat
195 (acdw-irc/margin-format "" "-*" " *" t)
196 " " (plist-get plist :nick) " " (plist-get plist :body)))
197 circe-format-self-say
198 (lambda (&rest plist)
199 (concat
200 (acdw-irc/margin-format (plist-get plist :nick) "-" " >" t)
201 " " (plist-get plist :body)))
202 circe-highlight-nick-type 'sender
203 circe-network-options
204 `(("Libera Chat"
205 :channels ("#emacs" "#systemcrafters" "##webpals")
206 :sasl-username circe-default-nick
207 :sasl-password ,(acdw/make-password-fetcher
208 :host "libera.chat"))
209 ("Tilde Chat" :host "irc.tilde.chat" :port 6697 :use-tls t
210 :channels ("#meta" "#bread" "#dadjokes" "#team")
211 :sasl-username circe-default-nick
212 :sasl-password ,(acdw/make-password-fetcher
213 :host "tilde.chat"))
214 ("Casa" :host "m455.casa" :port 6697 :use-tls t
215 :channels ("#basement")
216 :sasl-username circe-default-nick
217 :sasl-password ,(acdw/make-password-fetcher
218 :host "m455.casa"))
219 ("Piss" :host "piss.hmm.st" :port 6697 :use-tls t))
220 circe-reduce-lurker-spam t
221 circe-server-auto-join-default-type :after-auth)
222
223 (custom-set-faces '(circe-nick-highlight-face
224 ((t (:inherit (modus-themes-hl-line))))
225 :now))
226
227 (:bind "C-c C-p" #'circe-command-PART)
228
229 (:advise circe-command-PART :after
230 (defun circe-command-PART@kill-buffer (&rest _)
231 (let ((circe-channel-killed-confirmation nil))
232 (kill-buffer))))
233
234 (:with-mode circe-chat-mode
235 (:hook #'acdw/stop-paren-annoyances
236 (defun circe-chat@setup ()
237 (lui-set-prompt
238 (concat (propertize (acdw-irc/margin-format (buffer-name)
239 ""
240 ">")
241 'face 'circe-prompt-face
242 'read-only t 'intangible t
243 'cursor-intangible t)
244 " "))
245 (enable-circe-color-nicks)
246 (enable-circe-display-images)
247 (enable-circe-new-day-notifier))))
248
249 (autoload 'circe-nick-color-reset "circe-color-nicks")
250 (add-hook 'modus-themes-after-load-theme-hook
251 #'circe-nick-color-reset)
252
253 (:with-mode lui-mode
254 (:option lui-fill-column fill-column
255 lui-fill-type (repeat-string acdw-irc/left-margin " ")
256 lui-time-stamp-position 'right-margin
257 lui-time-stamp-format "%H:%M"
258 lui-track-behavior 'before-switch-to-buffer
259 lui-track-indicator 'fringe)
260
261 (:hook (defun lui-mode@setup ()
262 (setq-local fringes-outside-margins t
263 right-margin-width 5
264 scroll-margin 0
265 word-wrap t
266 wrap-prefix (repeat-string
267 acdw-irc/left-margin " ")
268 line-number-mode nil)
269 (enable-lui-track)))))
270
130(setup completion 271(setup completion
131 (:option completion-ignore-case t 272 (:option completion-ignore-case t
132 read-buffer-completion-ignore-case t 273 read-buffer-completion-ignore-case t
@@ -137,6 +278,154 @@
137 278
138 (:global "M-/" #'hippie-expand)) 279 (:global "M-/" #'hippie-expand))
139 280
281(setup (:straight (consult
282 :host github
283 :repo "minad/consult"))
284 (require 'acdw-consult)
285
286 (setq consult--regexp-compiler #'consult--orderless-regexp-compiler)
287
288 ;; Bindings
289 (:global
290 ;; C-c bindings (`mode-specific-map')
291 ;; I don't use any of these right now.
292 ;; "C-c h" #'consult-history
293 ;; "C-c m" #'consult-mode-command
294 ;; "C-c b" #'consult-bookmark
295 ;; "C-c k" #'consult-kmacro
296 ;; C-x bindings (`ctl-x-map')
297 "C-x M-:" #'consult-complex-command
298 "C-x b" #'consult-buffer
299 "C-x 4 b" #'consult-buffer-other-window
300 "C-x 5 b" #'consult-buffer-other-frame
301 ;; Custom M-# bindings for fast register access
302 "M-#" #'consult-register-load
303 "M-'" #'consult-register-store
304 "C-M-#" #'consult-register
305 ;; M-g bindings (`goto-map')
306 "M-g e" #'consult-compile-error
307 "M-g g" #'consult-goto-line
308 "M-g M-g" #'consult-goto-line
309 "M-g o" #'consult-outline
310 "M-g m" #'consult-mark
311 "M-g k" #'consult-global-mark
312 "M-g i" #'consult-imenu
313 "M-g I" #'consult-project-imenu
314 ;; M-s bindings (`search-map')
315 "M-s g" #'acdw-consult/sensible-grep
316 "M-s f" #'acdw-consult/sensible-find
317 "M-s l" #'consult-line
318 "M-s m" #'consult-multi-occur
319 "M-s k" #'consult-keep-lines
320 "M-s u" #'consult-focus-lines
321 ;; Other bindings
322 "M-y" #'consult-yank-pop
323 "<help> a" #'consult-apropos
324 ;; Isearch integration
325 "M-s e" #'consult-isearch)
326 (:with-map isearch-mode-map
327 (:bind "M-e" #'consult-isearch
328 "M-s e" #'consult-isearch
329 "M-s l" #'consult-line))
330
331 ;; see https://github.com/oantolin/completing-history
332 (defmacro consult-history-to-modes (map-hook-alist)
333 (let (defuns)
334 (dolist (map-hook map-hook-alist)
335 (let ((map-name (symbol-name (car map-hook)))
336 (key-defs `(progn (define-key
337 ,(car map-hook)
338 (kbd "M-r")
339 (function consult-history))
340 (define-key ,(car map-hook)
341 (kbd "M-s") nil))))
342 (push (if (cdr map-hook)
343 `(add-hook ',(cdr map-hook)
344 (defun
345 ,(intern (concat map-name
346 "@consult-history-bind"))
347 nil
348 ,(concat
349 "Bind `consult-history' to M-r in "
350 map-name ".\n"
351 "Defined by `consult-history-to-modes'.")
352 ,key-defs))
353 key-defs)
354 defuns)))
355 `(progn ,@ (nreverse defuns))))
356
357 (consult-history-to-modes ((minibuffer-local-map . nil)
358 (shell-mode-map . shell-mode-hook)
359 (term-mode-map . term-mode-hook)
360 (term-raw-map . term-mode-hook)
361 (comint-mode-map . comint-mode-hook)
362 (sly-mrepl-mode-map . sly-mrepl-hook)))
363
364
365
366 ;; Registers
367 (:autoload consult-register-preview)
368 (:option register-preview-delay 0
369 register-preview-function #'consult-register-format)
370 (:advise register-preview :override #'consult-register-window)
371
372 ;; Xref
373 (:option xref-show-xrefs-function #'consult-xref
374 xref-show-definitions-function #'consult-xref)
375
376 ;; Projects
377 (:option consult-project-root-function #'vc-root-dir)
378
379 ;; Competion-at-point (complete-region)
380 (:option completion-in-region-function #'acdw-consult/complete-in-region
381 completion-cycle-threshold 3
382 tab-always-indent 'complete)
383
384 ;; Completing-read-multple
385 (if (fboundp #'consult-completing-read-multiple)
386 (:advise completing-read-multple
387 :override #'consult-completing-read-multiple)
388 ;; else
389 (defun crm-indicator (args)
390 (cons (concat "[CRM] " (car args)) (cdr args)))
391 (:advise completing-read-multiple
392 :filter-args #'crm-indicator))
393
394 (with-eval-after-loads (vertico consult)
395 (when (boundp 'consult-crm-map)
396 (define-key consult-crm-map "\r" #'+vertico-crm-exit)
397 (define-key consult-crm-map "\t" #'vertico-exit)
398 (defun +vertico-crm-exit ()
399 (interactive)
400 (run-at-time 0 nil #'vertico-exit)
401 (funcall #'vertico-exit)))))
402
403(setup (:straight crux)
404
405 (:global "C-x o" #'acdw/other-window-or-switch-buffer
406 "C-o" #'crux-smart-open-line
407 "M-o" #'crux-smart-open-line-above
408 "C-M-\\" #'crux-cleanup-buffer-or-region
409 "C-x 4 t" #'crux-transpose-windows)
410
411 (when (fboundp 'repeat-mode)
412 (unless (boundp 'other-window-repeat-map)
413 (defvar other-window-repeat-map (make-sparse-keymap)
414 "A map for repeating `other-window' keys."))
415
416 (define-key other-window-repeat-map "o"
417 #'acdw/other-window-or-switch-buffer)
418 (define-key other-window-repeat-map "O"
419 (defun acdw/other-window-or-switch-buffer-backward ()
420 (interactive)
421 (setq repeat-map 'other-window-repeat-map)
422 (acdw/other-window-or-switch-buffer -1)))
423
424 (put 'acdw/other-window-or-switch-buffer
425 'repeat-map 'other-window-repeat-map))
426
427 (crux-reopen-as-root-mode +1))
428
140(setup cursor 429(setup cursor
141 (:option cursor-type 'bar 430 (:option cursor-type 'bar
142 cursor-in-non-selected-windows 'hollow 431 cursor-in-non-selected-windows 'hollow
@@ -280,10 +569,56 @@
280 (:option ediff-window-setup-function #'ediff-setup-windows-plain 569 (:option ediff-window-setup-function #'ediff-setup-windows-plain
281 ediff-split-window-function #'split-window-horizontally)) 570 ediff-split-window-function #'split-window-horizontally))
282 571
572;; requires extension:
573;; https://addons.mozilla.org/en-US/firefox/addon/edit-with-emacs1/
574(setup (:straight edit-server)
575 (when (and (daemonp)
576 (require 'edit-server nil :noerror))
577 (edit-server-start)
578
579 (:advise edit-server-make-frame :before
580 (defun edit-server@set-a-variable (&rest _)
581 (setq-local edit-server-frame-p t)))))
582
283(setup eldoc 583(setup eldoc
284 (:option eldoc-idle-delay 0.1 584 (:option eldoc-idle-delay 0.1
285 eldoc-echo-area-use-multiline-p nil)) 585 eldoc-echo-area-use-multiline-p nil))
286 586
587(setup (:straight (electric-cursor
588 :host github
589 :repo "duckwork/electric-cursor"))
590 (electric-cursor-mode +1))
591
592(setup (:straight elfeed
593 elfeed-protocol)
594 (:option elfeed-use-curl t
595 elfeed-feeds `(("fever+https://acdw@mf.acdw.net"
596 :api-url "https://mf.acdw.net/fever/"
597 :password ,(acdw/make-password-fetcher
598 :host "mf.acdw.net"))))
599
600 (elfeed-protocol-enable)
601
602 (:with-mode elfeed-show-mode
603 (:hook (defun elfeed-show@setup ()
604 (acdw/reading-mode)))
605
606 ;; see https://irreal.org/blog/?p=8885
607 (:bind "SPC" (defun elfeed-scroll-up-command (&optional arg)
608 "Scroll up or go to next feed item in Elfeed"
609 (interactive "^P")
610 (let ((scroll-error-top-bottom nil))
611 (condition-case-unless-debug nil
612 (scroll-up-command arg)
613 (error (elfeed-show-next)))))
614 "S-SPC" (defun elfeed-scroll-down-command (&optional arg)
615 "Scroll up or go to next feed item in Elfeed"
616 (interactive "^P")
617 (let ((scroll-error-top-bottom nil))
618 (condition-case-unless-debug nil
619 (scroll-down-command arg)
620 (error (elfeed-show-prev))))))))
621
287(setup elisp-mode 622(setup elisp-mode
288 (:option eval-expression-print-length nil 623 (:option eval-expression-print-length nil
289 eval-expression-print-level nil 624 eval-expression-print-level nil
@@ -297,9 +632,9 @@
297 (setq-local lexical-binding t)) 632 (setq-local lexical-binding t))
298 633
299 (defun emacs-lisp@imenu-add-setup () 634 (defun emacs-lisp@imenu-add-setup ()
300 (add-to-list 'imenu-generic-expression 635 (:option (append imenu-generic-expression)
301 '("Setup" 636 '("Setup"
302 "\\(^\\s-*(setup +(?\\)\\(\\_<.+\\_>\\)" 2)))) 637 "\\(^\\s-*(setup +(?\\)\\(\\_<.+\\_>\\)" 2))))
303 638
304 ;; Emulate slime's eval binds 639 ;; Emulate slime's eval binds
305 (:bind "C-c C-c" #'eval-defun 640 (:bind "C-c C-c" #'eval-defun
@@ -312,6 +647,57 @@
312 (pulse-momentary-highlight-region beg end) 647 (pulse-momentary-highlight-region beg end)
313 (apply fn start end args)))) 648 (apply fn start end args))))
314 649
650(setup (:straight elisp-slime-nav)
651 (:hook-into emacs-lisp-mode
652 ielm-mode))
653
654(setup (:straight (elpher
655 :host nil
656 :repo "git://thelambdalab.xyz/elpher.git"))
657 (:option elpher-ipv4-always t
658 elpher-certificate-directory (acdw/dir "elpher/")
659 elpher-gemini-max-fill-width fill-column)
660
661 (:bind "n" #'elpher-next-link
662 "p" #'elpher-prev-link
663 "o" #'elpher-follow-current-link
664 "G" #'elpher-go-current)
665
666 (:hook acdw/reading-mode)
667
668 (:autoload (elpher-bookmarks :interactive t)
669 (elpher-go :interactive t))
670
671 ;; Make `eww' gemini/gopher aware. From Emacswiki.
672 ;; (define-advice eww-browse-url (:around (fn url &rest args) gemini-elpher)
673 ;; (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
674 ;; (require 'elpher)
675 ;; (elpher-go url))
676 ;; (t (apply fn url args))))
677 )
678
679(setup (:straight embark)
680 (:global "C-." #'embark-act)
681 (:option prefix-help-command #'embark-prefix-help-command
682 (append display-buffer-alist)
683 '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
684 nil
685 (window-parameters (mode-line-format . none)))
686 embark-prompter #'embark-keymap-prompter
687 embark-verbose-indicator-display-action
688 '(display-buffer-at-bottom (window-height . fit-window-to-buffer)))
689
690 (setq embark-action-indicator
691 (lambda (map _target)
692 (which-key--show-keymap "Embark" map nil nil 'no-paging)
693 #'which-key--hide-popup-ignore-command)
694 embark-become-indicator embark-action-indicator)
695
696 (with-eval-after-loads (embark consult)
697 (:straight embark-consult)
698 (add-hook 'embark-collect-mode-hook
699 #'consult-preview-at-point-mode)))
700
315(setup encoding 701(setup encoding
316 (:option locale-coding-system 'utf-8-unix 702 (:option locale-coding-system 'utf-8-unix
317 coding-system-for-read 'utf-8-unix 703 coding-system-for-read 'utf-8-unix
@@ -336,6 +722,60 @@
336 (_ (set-selection-coding-system 'utf-8) 722 (_ (set-selection-coding-system 'utf-8)
337 (set-clipboard-coding-system 'utf-8)))) 723 (set-clipboard-coding-system 'utf-8))))
338 724
725(setup (:straight epithet)
726 (dolist (hook '(Info-selection-hook
727 eww-after-render-hook
728 help-mode-hook
729 occur-mode-hook))
730 (add-hook hook #'epithet-rename-buffer)))
731
732;; TODO: look into emms or something related for this
733(setup (:straight-if eradio
734 (executable-find "mpv"))
735 (:option
736 eradio-player '("mpv" "--no-video" "--no-terminal")
737 eradio-channels `(("KLSU" .
738 "http://130.39.238.143:8010/stream.mp3")
739 ("Soma FM Synphaera" .
740 "https://somafm.com/synphaera256.pls")
741 ("SomaFM BAGel Radio" .
742 "https://somafm.com/bagel.pls")
743 ("SomaFM Boot Liquor" .
744 "https://somafm.com/bootliquor320.pls")
745 ("SomaFM Deep Space One" .
746 "https://somafm.com/deepspaceone.pls")
747 ("SomaFM Fluid" .
748 "https://somafm.com/fluid.pls")
749 ("SomaFM Underground 80s" .
750 "https://somafm.com/u80s256.pls")
751 ("WBRH: Jazz & More" .
752 "http://wbrh.streamguys1.com/wbrh-mp3")
753 ("KBRH Blues & Rhythm Hits" .
754 "http://wbrh.streamguys1.com/kbrh-mp3")
755 ("WRKF HD-2" .
756 ,(concat "https://playerservices.streamtheworld.com/"
757 "api/livestream-redirect/WRKFHD2.mp3"))
758 ("WRKF: NPR for the Capital Region" .
759 ,(concat "https://playerservices.streamtheworld.com/"
760 "api/livestream-redirect/WRKFFM.mp3"))
761 ("BadRadio: 24/7 PHONK" .
762 "https://s2.radio.co/s2b2b68744/listen")
763 ("tilderadio" .
764 "https://radio.tildeverse.org/radio/8000/radio.ogg")
765 ("vantaradio" .
766 "https://vantaa.black/radio")))
767 (:global "C-c r r" #'eradio-play ; mnemonic: radio
768 "C-c r s" #'eradio-stop ; mnemonic: stop
769 "C-c r p" #'eradio-toggle ; mnemonic: play/pause
770 ))
771
772(setup (:straight eros)
773 (:hook-into emacs-lisp-mode))
774
775(setup (:straight esh-autosuggest)
776 (:autoload esh-autosuggest-mode)
777 (:hook-into eshell-mode))
778
339(setup eshell 779(setup eshell
340 (:also-load acdw-eshell 780 (:also-load acdw-eshell
341 em-smart) 781 em-smart)
@@ -371,6 +811,41 @@
371 811
372 (:hook acdw/reading-mode)) 812 (:hook acdw/reading-mode))
373 813
814(setup (:straight-if exec-path-from-shell
815 (acdw/system :home))
816 (when (daemonp)
817 (exec-path-from-shell-initialize)))
818
819(setup (:straight expand-region)
820 (:global "C-=" #'er/expand-region
821 "C-SPC"
822 (defun acdw/set-mark-or-expand-region (arg)
823 "Set mark at point and activate, jump to mark, or expand region.
824See `set-mark-command' and `expand-region'.
825
826With no prefix argument, either run `set-mark-command' on first
827invocation and `er/expand-region' on each successive invocation.
828
829With any prefix argument
830(e.g., \\[universal-argument] \\[set-mark-command]), act as with
831`set-mark-command' (i.e., pop the mark). Don't care about
832successive invocations."
833 (interactive "P")
834 (cond
835 ((or arg
836 (and set-mark-command-repeat-pop
837 (eq last-command 'pop-to-mark-command)))
838 (setq this-command 'set-mark-command)
839 (set-mark-command arg))
840 ((eq last-command 'acdw/set-mark-or-expand-region)
841 (er/expand-region 1))
842 (t (set-mark-command arg))))))
843
844(setup (:straight-if fennel-mode
845 (executable-find "fennel"))
846 (:autoload (fennel-repl :interactive t))
847 (:file-match (rx ".fnl" eos)))
848
374(setup files 849(setup files
375 (:option 850 (:option
376 auto-save-file-name-transforms `((".*" ,(acdw/dir "auto-save/" t) t)) 851 auto-save-file-name-transforms `((".*" ,(acdw/dir "auto-save/" t) t))
@@ -400,6 +875,12 @@
400(setup flyspell 875(setup flyspell
401 (add-hook 'text-mode-hook #'flyspell-mode)) 876 (add-hook 'text-mode-hook #'flyspell-mode))
402 877
878(setup (:straight flyspell-correct)
879 (:with-mode flyspell-mode
880 (:hook (defun flyspell@correct ()
881 (:bind "C-;" #'flyspell-correct-wrapper)
882 (:unbind "C-," "C-." "C-M-i")))))
883
403(setup frames 884(setup frames
404 (:option frame-title-format '("%b@" 885 (:option frame-title-format '("%b@"
405 (:eval 886 (:eval
@@ -412,11 +893,87 @@
412 893
413 (add-hook 'unfocused-hook #'garbage-collect)) 894 (add-hook 'unfocused-hook #'garbage-collect))
414 895
896(setup (:straight gcmh)
897 (:option gcmh-idle-delay 'auto)
898 (gcmh-mode +1))
899
900(setup (:straight-if geiser
901 (progn
902 (defvar acdw/schemes
903 (let (schemes)
904 (dolist (scheme '(("scheme" . geiser-chez) ; chez
905 ("petite" . geiser-chez) ; petite
906 ("csi" . geiser-chez) ; chicken
907 ("gsi" . geiser-gambit)
908 ("gosh" . geiser-gauche)
909 ("guile" . geiser-guile)
910 ("kawa" . geiser-kawa)
911 ("mit-scheme" . geiser-mit)
912 ("racket" . geiser-racket)
913 ("stklos" . geiser-stklos)))
914 (when-let (binary (executable-find (car scheme)))
915 (push binary schemes)
916 ;; and install the proper helper package
917 (straight-use-package (cdr scheme))))
918 (nreverse schemes)))
919 acdw/schemes))
920 (:file-match (rx ".rkt" eos)
921 (rx ".scm" eos)))
922
923(setup (:straight (gemini-mode
924 :host nil
925 :repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
926 (:file-match (rx (seq "." (or "gemini" "gmi") eos)))
927 (:hook turn-off-auto-fill))
928
929(setup (:straight (gemini-write
930 :host nil
931 :repo "https://alexschroeder.ch/cgit/gemini-write"
932 :branch "main"))
933 (with-eval-after-load 'elpher
934 (require 'gemini-write)))
935
936(setup (:require gforth)
937 (:autoload forth-mode
938 forth-block-mode)
939 (add-to-list 'auto-mode-alist '("\\.fs\\'" . forth-mode))
940 (add-to-list 'auto-mode-alist '("\\.fb\\'" . forth-block-mode)))
941
415(setup goto-addr 942(setup goto-addr
416 (if (fboundp #'global-goto-address-mode) 943 (if (fboundp #'global-goto-address-mode)
417 (global-goto-address-mode) 944 (global-goto-address-mode)
418 (add-hook 'after-change-major-mode-hook #'goto-address-mode))) 945 (add-hook 'after-change-major-mode-hook #'goto-address-mode)))
419 946
947
948;; TODO: figure out a popper.el / shackle.el ... thing to fix this
949(setup (:straight helpful)
950 (:option helpful-max-buffers 5)
951 (:global "<help> f" #'helpful-callable
952 "<help> v" #'helpful-variable
953 "<help> k" #'helpful-key
954 "<help> o" #'helpful-symbol))
955
956(setup (:straight hungry-delete)
957 (:option hungry-delete-chars-to-skip " \t"
958 hungry-delete-join-reluctantly nil)
959
960 (global-hungry-delete-mode +1)
961
962 (:with-feature paredit
963 (:bind [remap paredit-backward-delete]
964 (defun acdw/paredit-hungry-delete-backward (arg)
965 (interactive "P")
966 (if (looking-back "[ \t]" 1)
967 (hungry-delete-backward (or arg 1))
968 (paredit-backward-delete arg)))
969
970 [remap paredit-forward-delete]
971 (defun acdw/paredit-hungry-delete-forward (arg)
972 (interactive "P")
973 (if (looking-at "[ \t]")
974 (hungry-delete-forward (or arg 1))
975 (paredit-forward-delete arg))))))
976
420(setup ibuffer 977(setup ibuffer
421 (:also-load ibuf-ext) 978 (:also-load ibuf-ext)
422 (:option ibuffer-expert t 979 (:option ibuffer-expert t
@@ -464,9 +1021,21 @@
464(setup imenu 1021(setup imenu
465 (:option imenu-auto-rescan t)) 1022 (:option imenu-auto-rescan t))
466 1023
1024(setup (:straight iscroll)
1025 (define-globalized-minor-mode global-iscroll-mode iscroll-mode
1026 (lambda () (iscroll-mode +1)))
1027
1028 (global-iscroll-mode +1))
1029
467(setup isearch 1030(setup isearch
468 (:option search-default-mode t)) 1031 (:option search-default-mode t))
469 1032
1033(setup (:straight lacarte)
1034 (:global "<f10>" #'lacarte-execute-menu-command))
1035
1036(setup (:straight-if ledger-mode
1037 (executable-find "ledger")))
1038
470(setup lines 1039(setup lines
471 (:option fill-column 79 1040 (:option fill-column 79
472 word-wrap t 1041 word-wrap t
@@ -490,556 +1059,68 @@
490 (delete-indentation 1) 1059 (delete-indentation 1)
491 (apply fn args))))) 1060 (apply fn args)))))
492 1061
493(setup minibuffer 1062(setup (:straight link-hint)
494 (:option enable-recursive-minibuffers t 1063 ;; Browse web URLs with a browser with a prefix argument.
495 file-name-shadow-properties '(invisible t intangible t) 1064 (dolist (type '(gnus-w3m-image-url
496 minibuffer-eldef-shorten-default t 1065 gnus-w3m-url
497 minibuffer-prompt-properties 1066 markdown-link
498 '(read-only t cursor-intangible t face minibuffer-prompt) 1067 mu4e-attachment
499 read-answer-short t 1068 mu4e-url
500 read-extended-command-predicate ; used on >28 1069 notmuch-hello
501 #'command-completion-default-include-p) 1070 nov-link
502 1071 org-link
503 (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) 1072 shr-url
504 1073 text-url
505 (add-hook 'minibuffer-setup-hook #'acdw/gc-disable) 1074 w3m-link
506 (add-hook 'minibuffer-exit-hook #'acdw/gc-enable) 1075 w3m-message-link))
507 1076 (link-hint-define-type type
508 (minibuffer-depth-indicate-mode +1) 1077 :open-secondary browse-url-secondary-browser-function))
509 (file-name-shadow-mode +1)
510 (minibuffer-electric-default-mode +1)
511 (fset 'yes-or-no-p #'y-or-n-p))
512
513(setup page
514 (:option page-delimiter
515 (rx bol (or "\f" ";;;")
516 (not (any "#")) (* not-newline) "\n"
517 (* (* blank) (opt ";" (* not-newline)) "\n")))
518
519 (defun recenter-to-top (&rest _)
520 "Recenter the cursor to the top of the window."
521 (when (called-interactively-p 'any)
522 (recenter (if (or (null scroll-margin)
523 (zerop scroll-margin))
524 3
525 scroll-margin))))
526
527 (:advise forward-page :after #'recenter-to-top
528 backward-page :after #'recenter-to-top)
529
530 ;; I'm not sure where this is in /my/ version of Emacs
531 (defvar page-navigation-repeat-map
532 (let ((map (make-sparse-keymap)))
533 (define-key map "]" #'forward-page)
534 (define-key map "[" #'backward-page)
535 map)
536 "Keymap to repeat page navigation key sequences. Used in `repeat-mode'.")
537
538 (put 'forward-page 'repeat-map 'page-navigation-repeat-map)
539 (put 'backward-page 'repeat-map 'page-navigation-repeat-map))
540
541(setup prog
542 (:option show-paren-delay 0
543 show-paren-style 'mixed
544 show-paren-when-point-inside-paren t
545 show-paren-when-point-in-periphery t
546 smie-indent-basic tab-width)
547
548 (:hook show-paren-mode
549 electric-pair-local-mode
550 acdw/setup-fringes
551
552 (defun flymake-mode-except ()
553 "Turn on flymake mode, except in some modes."
554 (let ((no-flymake-modes '(emacs-lisp-mode)))
555 (unless (or (member major-mode no-flymake-modes)
556 (apply #'derived-mode-p no-flymake-modes))
557 (flymake-mode-on))))
558 1078
559 (defun prog-mode@auto-fill () 1079 (:option link-hint-avy-style 'at)
560 (setq-local comment-auto-fill-only-comments t) 1080 (:global "C-;"
561 (turn-on-auto-fill))) 1081 (defun acdw/link-hint-open-link (arg)
1082 "Open a link using `link-hint-open-link', prefix-aware.
1083That is, a prefix argument (\\[universal-argument]) will open the
1084browser defined in `browse-url-secondary-browser-function'."
1085 (interactive "P")
1086 (avy-with link-hint-open-link
1087 (link-hint--one (if arg :open-secondary :open))))))
562 1088
563 (add-hook 'after-save-hook 1089(setup (:straight lua-mode)
564 #'executable-make-buffer-file-executable-if-script-p)) 1090 (:file-match (rx ".lua" eos)))
565 1091
566(setup repeat 1092(setup (:straight macrostep)
567 ;; new for Emacs 28!
568 (:only-if (fboundp #'repeat-mode))
569 1093
570 (:option repeat-exit-key "g" 1094 (:with-mode emacs-lisp-mode
571 repeat-exit-timeout 5) 1095 (:bind "C-c e" #'macrostep-expand)))
572
573 (repeat-mode +1))
574 1096
575(setup saveplace 1097(setup (:straight magit)
576 (:option save-place-file (acdw/dir "places.el") 1098 (:global "C-c g" #'magit-status)
577 save-place-forget-unreadable-files (acdw/system :home))
578
579 (save-place-mode +1))
580 1099
581(setup scratch 1100 (:option magit-display-buffer-function
582 (:option inhibit-startup-screen t 1101 (defun magit-display-buffer-same-window (buffer)
583 initial-buffer-choice t 1102 "Display BUFFER in the selected window like God intended."
584 initial-scratch-message "" 1103 (display-buffer buffer '(display-buffer-same-window)))
585 ;; (concat ";; Howdy, " 1104 magit-popup-display-buffer-action '((display-buffer-same-window))
586 ;; (nth 0 (split-string 1105 magit-refresh-status-buffer nil))
587 ;; user-full-name))
588 ;; "! "
589 ;; "Welcome to GNU Emacs.\n\n")
590 initial-major-mode 'emacs-lisp-mode)
591
592 (add-hook 'kill-buffer-query-functions
593 (defun kill-buffer-query@immortal-scratch ()
594 (if (eq (current-buffer) (get-buffer "*scratch*"))
595 (progn (bury-buffer)
596 nil)
597 t))))
598 1106
599(setup scrolling 1107(setup (:straight marginalia)
600 (:option auto-window-vscroll nil 1108 (:option marginalia-annotators '(marginalia-annotators-heavy
601 fast-but-imprecise-scrolling t 1109 marginalia-annotators-light))
602 scroll-margin 3 1110 (marginalia-mode +1))
603 scroll-conservatively 101
604 scroll-preserve-screen-position 1))
605 1111
606(setup selection 1112(setup (:straight markdown-mode)
607 (:option save-interprogram-paste-before-kill t 1113 (:file-match (rx ".md" eos)
608 yank-pop-change-selection t 1114 (rx ".markdown" eos))
609 x-select-enable-clipboard t
610 x-select-enable-primary t
611 mouse-drag-copy-region t
612 kill-do-not-save-duplicates t)
613 1115
614 (delete-selection-mode +1)) 1116 (:with-mode gfm-mode
1117 (:file-match (rx "README.md" eos)))
615 1118
616(setup sh-mode 1119 (when (executable-find "markdownfmt")
617 (:option sh-basic-offset tab-width
618 sh-indent-after-case 0
619 sh-indent-for-case-alt '+
620 sh-indent-for-case-label 0)
621
622 (:local-set indent-tabs-mode t)
623
624 (when (executable-find "shfmt")
625 (with-eval-after-load 'apheleia 1120 (with-eval-after-load 'apheleia
626 (:option (append apheleia-formatters) '(shfmt . ("shfmt")) 1121 (:option (append apheleia-formatters) '(markdownfmt . ("markdownfmt"))
627 (append apheleia-mode-alist) '(sh-mode . shfmt)))) 1122 (append apheleia-mode-alist) '(markdown-mode . markdownfmt)
628 1123 (append apheleia-mode-alist) '(gfm-mode . markdownfmt)))))
629 (when (executable-find "shellcheck")
630 (:straight flymake-shellcheck)
631 (:hook flymake-mode
632 flymake-shellcheck-load)))
633
634(setup shell-command
635 (:option shell-command-switch (acdw/system
636 ;; I should be testing on some variable
637 (:home "-csi")
638 (:work "-c"))
639 shell-command-prompt-show-cwd t
640 shell-command-default-error-buffer "*shell-command-errors*"))
641
642(setup shr
643 (:option shr-width fill-column
644 shr-max-width fill-column
645 shr-max-image-proportion 0.6
646 shr-image-animate t
647 shr-discard-aria-hidden t
648 shr-folding-mode t))
649
650(setup text
651 (:hook turn-on-auto-fill
652 acdw/setup-fringes))
653
654(setup uniquify
655 (:option uniquify-buffer-name-style 'forward
656 uniquify-separator path-separator
657 uniquify-after-kill-buffer-p t
658 uniquify-ignore-buffers-re "^\\*"))
659
660(setup variable-pitch-mode
661
662 ;; I might want to change this to `buffer-face-mode-hook'...
663 (advice-add 'variable-pitch-mode :after
664 (defun variable-pitch-mode@setup (&rest _)
665 "Set up `variable-pitch-mode' with my customizations."
666 (display-fill-column-indicator-mode (if buffer-face-mode
667 -1
668 +1)))))
669
670(setup view
671 (:option view-read-only t)
672
673 (:hook (defun acdw/read-view-mode ()
674 (acdw/reading-mode (if view-mode +1 -1)))))
675
676(setup w32
677 (:option w32-allow-system-shell t
678 w32-pass-lwindow-to-system nil
679 w32-lwindow-modifier 'super
680 w32-pass-rwindow-to-system nil
681 w32-rwindow-modifier 'super
682 w32-pass-apps-to-system nil
683 w32-apps-modifier 'hyper))
684
685(setup whitespace
686 (:option whitespace-style
687 '(empty indentation space-before-tab space-after-tab)
688 indent-tabs-mode nil
689 tab-width 4
690 backward-delete-char-untabify-method 'hungry)
691
692 (:global "M-SPC" #'cycle-spacing))
693
694(setup windmove
695 (:option windmove-wrap-around t)
696 (:global
697 ;; moving
698 "C-x 4 <left>" #'windmove-left
699 "C-x 4 <right>" #'windmove-right
700 "C-x 4 <up>" #'windmove-up
701 "C-x 4 <down>" #'windmove-down
702 ;; swapping
703 "C-x 4 S-<left>" #'windmove-swap-states-left
704 "C-x 4 S-<right>" #'windmove-swap-states-right
705 "C-x 4 S-<up>" #'windmove-swap-states-up
706 "C-x 4 S-<down>" #'windmove-swap-states-down)
707
708 (when (fboundp 'repeat-mode)
709 (defvar windmove-repeat-map
710 (let ((map (make-sparse-keymap)))
711 ;; moving
712 (define-key map [left] #'windmove-left)
713 (define-key map [right] #'windmove-right)
714 (define-key map [up] #'windmove-up)
715 (define-key map [down] #'windmove-down)
716 ;; swapping
717 (define-key map [S-left] #'windmove-swap-states-left)
718 (define-key map [S-right] #'windmove-swap-states-right)
719 (define-key map [S-up] #'windmove-swap-states-up)
720 (define-key map [S-down] #'windmove-swap-states-down)
721 map)
722 "Keymap to repeat various `windmove' sequences. Used in `repeat-mode'.")
723
724 (dolist (sym '(windmove-left
725 windmove-right
726 windmove-up
727 windmove-down
728 windmove-swap-states-left
729 windmove-swap-states-right
730 windmove-swap-states-up
731 windmove-swap-states-down))
732 (put sym 'repeat-map 'windmove-repeat-map))))
733
734(setup window
735 (require 'acdw-bell)
736 (:option Man-notify-method 'pushy
737 display-buffer-alist ; from FrostyX
738 '(("shell.*" (display-buffer-same-window) ())
739 (".*" (display-buffer-reuse-window
740 display-buffer-same-window)
741 (reusable-frames . t)))
742 recenter-positions '(top middle bottom)
743 ring-bell-function (lambda ()
744 (acdw-bell/flash-mode-line
745 (acdw/system :home)))
746 tab-bar-show 1
747 use-dialog-box nil
748 use-file-dialog nil
749 visible-bell nil)
750
751 (tooltip-mode -1))
752
753(setup winner
754 ;; see https://lists.gnu.org/archive/html/emacs-devel/2021-08/msg00888.html
755 (:global "C-x 4 C-/" #'winner-undo
756 "C-x 4 /" #'winner-undo
757 "C-x 4 C-?" #'winner-redo
758 "C-x 4 ?" #'winner-redo)
759
760 ;; add `winner-undo' and `winner-redo' to `repeat-mode'
761 (when (fboundp 'repeat-mode)
762 (defvar winner-mode-repeat-map
763 (let ((map (make-sparse-keymap)))
764 (define-key map "/" #'winner-undo)
765 (define-key map "?" #'winner-redo)
766 map)
767 "Keymap to repeat `winner-mode' sequences. Used in `repeat-mode'.")
768
769 (put 'winner-undo 'repeat-map 'winner-mode-repeat-map)
770 (put 'winner-redo 'repeat-map 'winner-mode-repeat-map))
771
772 (winner-mode +1))
773
774(setup x-emacs
775 ;; "Et cetera" settings
776 ;; This should stay as /minimal/ as possible. Anything that can go somewhere
777 ;; else /should/ go there.
778 (:option
779 attempt-orderly-shutdown-on-fatal-signal nil
780 attempt-stack-overflow-recovery nil
781 echo-keystrokes 0.01
782 find-function-C-source-directory (acdw/find-emacs-source)
783 kill-read-only-ok t
784 load-prefer-newer t
785 native-comp-async-report-warnings-errors nil
786 set-mark-command-repeat-pop t)
787
788 (when (fboundp 'command-completion-default-include-p)
789 (setq read-extended-command-predicate
790 #'command-completion-default-include-p))
791
792 (defvar case-map (make-sparse-keymap)
793 "A keymap for setting case in various ways.")
794 (global-set-key (kbd "C-c c") case-map)
795
796 (defvar lookup-map (make-sparse-keymap)
797 "A keymap for looking up things.")
798 (global-set-key (kbd "C-c l") lookup-map)
799
800 (:global "M-=" #'count-words
801 "C-w" #'kill-region-or-backward-word
802 "C-c c c" #'capitalize-dwim
803 "C-c c t" #'titlecase-dwim
804 "C-c c u" #'upcase-dwim
805 "C-c c l" #'downcase-dwim
806 "C-c d" #'acdw/insert-iso-date
807 "M-`" nil)
808
809 ;; toggle bindings
810 (defvar toggle-map (make-sparse-keymap)
811 "A keymap for toggling!")
812 (global-set-key (kbd "C-c t") toggle-map)
813
814 (:with-map toggle-map
815 (:bind "c" #'column-number-mode
816 "l" #'display-line-numbers-mode
817 "d" #'toggle-debug-on-error))
818
819 (defalias 'forward-word-with-case 'forward-word
820 "Alias for `forward-word' for use in `case-repeat-map'.")
821 (defalias 'backward-word-with-case 'backward-word
822 "Alias for `backward-word for use in `case-repeat-map'.")
823
824 (defvar case-repeat-map
825 (let ((map (make-sparse-keymap)))
826 (define-key map "c" #'capitalize-word)
827 (define-key map "u" #'upcase-word)
828 (define-key map "l" #'downcase-word)
829 ;; movement
830 (define-key map "f" #'forward-word-with-case)
831 (define-key map "b" #'backward-word-with-case)
832 map)
833 "A map to repeat word-casing commands. For use with `repeat-mode'.")
834
835 (dolist (command '(capitalize-word
836 capitalize-dwim
837 upcase-word
838 upcase-dwim
839 downcase-word
840 downcase-dwim
841 forward-word-with-case
842 backward-word-with-case))
843 (put command 'repeat-map 'case-repeat-map))
844
845 (add-hook 'after-make-frame-functions
846 (defun after-make-frame@maximize (frame)
847 (unless (bound-and-true-p edit-server-frame-p)
848 (toggle-frame-maximized frame)))))
849
850
851;;; Packages
852
853(setup (:require gforth)
854 (:autoload forth-mode
855 forth-block-mode)
856 (add-to-list 'auto-mode-alist '("\\.fs\\'" . forth-mode))
857 (add-to-list 'auto-mode-alist '("\\.fb\\'" . forth-block-mode)))
858
859(setup (:straight (0x0 :host gitlab
860 :repo "willvaughn/emacs-0x0"))
861 (:option 0x0-default-server 'ttm))
862
863(setup (:straight (apheleia :host github
864 :repo "raxod502/apheleia"))
865
866 (apheleia-global-mode +1)
867
868 ;; Use a dumb formatter on modes that `apheleia' doesn't work for.
869 (add-hook 'before-save-hook
870 (defun before-save@dumb-auto-format ()
871 (setq stupid-modes '(makefile-mode
872 org-mode))
873 ;; If there's no apheleia formatter for the mode, just indent the
874 ;; buffer.
875 (unless (or (apply #'derived-mode-p stupid-modes)
876 (and (fboundp 'apheleia--get-formatter-command)
877 (apheleia--get-formatter-command)))
878 (indent-region (point-min) (point-max))))))
879
880(setup (:straight (consult
881 :host github
882 :repo "minad/consult"))
883 (require 'acdw-consult)
884
885 (setq consult--regexp-compiler #'consult--orderless-regexp-compiler)
886
887 ;; Bindings
888 (:global
889 ;; C-c bindings (`mode-specific-map')
890 ;; I don't use any of these right now.
891 ;; "C-c h" #'consult-history
892 ;; "C-c m" #'consult-mode-command
893 ;; "C-c b" #'consult-bookmark
894 ;; "C-c k" #'consult-kmacro
895 ;; C-x bindings (`ctl-x-map')
896 "C-x M-:" #'consult-complex-command
897 "C-x b" #'consult-buffer
898 "C-x 4 b" #'consult-buffer-other-window
899 "C-x 5 b" #'consult-buffer-other-frame
900 ;; Custom M-# bindings for fast register access
901 "M-#" #'consult-register-load
902 "M-'" #'consult-register-store
903 "C-M-#" #'consult-register
904 ;; M-g bindings (`goto-map')
905 "M-g e" #'consult-compile-error
906 "M-g g" #'consult-goto-line
907 "M-g M-g" #'consult-goto-line
908 "M-g o" #'consult-outline
909 "M-g m" #'consult-mark
910 "M-g k" #'consult-global-mark
911 "M-g i" #'consult-imenu
912 "M-g I" #'consult-project-imenu
913 ;; M-s bindings (`search-map')
914 "M-s g" #'acdw-consult/sensible-grep
915 "M-s f" #'acdw-consult/sensible-find
916 "M-s l" #'consult-line
917 "M-s m" #'consult-multi-occur
918 "M-s k" #'consult-keep-lines
919 "M-s u" #'consult-focus-lines
920 ;; Other bindings
921 "M-y" #'consult-yank-pop
922 "<help> a" #'consult-apropos
923 ;; Isearch integration
924 "M-s e" #'consult-isearch)
925 (:with-map isearch-mode-map
926 (:bind "M-e" #'consult-isearch
927 "M-s e" #'consult-isearch
928 "M-s l" #'consult-line))
929
930 ;; see https://github.com/oantolin/completing-history
931 (defmacro consult-history-to-modes (map-hook-alist)
932 (let (defuns)
933 (dolist (map-hook map-hook-alist)
934 (let ((map-name (symbol-name (car map-hook)))
935 (key-defs `(progn (define-key
936 ,(car map-hook)
937 (kbd "M-r")
938 (function consult-history))
939 (define-key ,(car map-hook)
940 (kbd "M-s") nil))))
941 (push (if (cdr map-hook)
942 `(add-hook ',(cdr map-hook)
943 (defun
944 ,(intern (concat map-name
945 "@consult-history-bind"))
946 nil
947 ,(concat
948 "Bind `consult-history' to M-r in "
949 map-name ".\n"
950 "Defined by `consult-history-to-modes'.")
951 ,key-defs))
952 key-defs)
953 defuns)))
954 `(progn ,@ (nreverse defuns))))
955
956 (consult-history-to-modes ((minibuffer-local-map . nil)
957 (shell-mode-map . shell-mode-hook)
958 (term-mode-map . term-mode-hook)
959 (term-raw-map . term-mode-hook)
960 (comint-mode-map . comint-mode-hook)
961 (sly-mrepl-mode-map . sly-mrepl-hook)))
962
963
964
965 ;; Registers
966 (:autoload consult-register-preview)
967 (:option register-preview-delay 0
968 register-preview-function #'consult-register-format)
969 (:advise register-preview :override #'consult-register-window)
970
971 ;; Xref
972 (:option xref-show-xrefs-function #'consult-xref
973 xref-show-definitions-function #'consult-xref)
974
975 ;; Projects
976 (:option consult-project-root-function #'vc-root-dir)
977
978 ;; Competion-at-point (complete-region)
979 (:option completion-in-region-function #'acdw-consult/complete-in-region
980 completion-cycle-threshold 3
981 tab-always-indent 'complete)
982
983 ;; Completing-read-multple
984 (if (fboundp #'consult-completing-read-multiple)
985 (:advise completing-read-multple
986 :override #'consult-completing-read-multiple)
987 ;; else
988 (defun crm-indicator (args)
989 (cons (concat "[CRM] " (car args)) (cdr args)))
990 (:advise completing-read-multiple
991 :filter-args #'crm-indicator))
992
993 (with-eval-after-loads (vertico consult)
994 (when (boundp 'consult-crm-map)
995 (define-key consult-crm-map "\r" #'+vertico-crm-exit)
996 (define-key consult-crm-map "\t" #'vertico-exit)
997 (defun +vertico-crm-exit ()
998 (interactive)
999 (run-at-time 0 nil #'vertico-exit)
1000 (funcall #'vertico-exit)))))
1001
1002(setup (:straight (electric-cursor
1003 :host github
1004 :repo "duckwork/electric-cursor"))
1005 (electric-cursor-mode +1))
1006
1007(setup (:straight (elpher :host nil
1008 :repo "git://thelambdalab.xyz/elpher.git"))
1009 (:option elpher-ipv4-always t
1010 elpher-certificate-directory (acdw/dir "elpher/")
1011 elpher-gemini-max-fill-width fill-column)
1012
1013 (:bind "n" #'elpher-next-link
1014 "p" #'elpher-prev-link
1015 "o" #'elpher-follow-current-link
1016 "G" #'elpher-go-current)
1017
1018 (:hook acdw/reading-mode)
1019
1020 (:autoload (elpher-bookmarks :interactive t)
1021 (elpher-go :interactive t))
1022
1023 ;; Make `eww' gemini/gopher aware. From Emacswiki.
1024 ;; (define-advice eww-browse-url (:around (fn url &rest args) gemini-elpher)
1025 ;; (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
1026 ;; (require 'elpher)
1027 ;; (elpher-go url))
1028 ;; (t (apply fn url args))))
1029 )
1030
1031(setup (:straight (gemini-mode
1032 :host nil
1033 :repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
1034 (:file-match (rx (seq "." (or "gemini" "gmi") eos)))
1035 (:hook turn-off-auto-fill))
1036
1037(setup (:straight (gemini-write
1038 :host nil
1039 :repo "https://alexschroeder.ch/cgit/gemini-write"
1040 :branch "main"))
1041 (with-eval-after-load 'elpher
1042 (require 'gemini-write)))
1043 1124
1044(setup (:straight (mastodon 1125(setup (:straight (mastodon
1045 :host github 1126 :host github
@@ -1052,6 +1133,26 @@
1052 (:hook #'hl-line-mode 1133 (:hook #'hl-line-mode
1053 #'acdw/reading-mode)) 1134 #'acdw/reading-mode))
1054 1135
1136(setup minibuffer
1137 (:option enable-recursive-minibuffers t
1138 file-name-shadow-properties '(invisible t intangible t)
1139 minibuffer-eldef-shorten-default t
1140 minibuffer-prompt-properties
1141 '(read-only t cursor-intangible t face minibuffer-prompt)
1142 read-answer-short t
1143 read-extended-command-predicate ; used on >28
1144 #'command-completion-default-include-p)
1145
1146 (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
1147
1148 (add-hook 'minibuffer-setup-hook #'acdw/gc-disable)
1149 (add-hook 'minibuffer-exit-hook #'acdw/gc-enable)
1150
1151 (minibuffer-depth-indicate-mode +1)
1152 (file-name-shadow-mode +1)
1153 (minibuffer-electric-default-mode +1)
1154 (fset 'yes-or-no-p #'y-or-n-p))
1155
1055(setup (:straight (modus-themes 1156(setup (:straight (modus-themes
1056 :host gitlab 1157 :host gitlab
1057 :repo "protesilaos/modus-themes")) 1158 :repo "protesilaos/modus-themes"))
@@ -1066,6 +1167,24 @@
1066 (acdw/sunrise-sunset #'modus-themes-load-operandi 1167 (acdw/sunrise-sunset #'modus-themes-load-operandi
1067 #'modus-themes-load-vivendi)) 1168 #'modus-themes-load-vivendi))
1068 1169
1170(setup (:straight mwim)
1171 (:global "C-a" #'mwim-beginning
1172 "C-e" #'mwim-end))
1173
1174(setup (:straight nov)
1175 (:option nov-text-width fill-column)
1176 (:file-match (rx ".epub" eos)))
1177
1178(setup (:straight olivetti)
1179 (:option olivetti-body-width (+ fill-column 4)
1180 olivetti-minimum-body-width fill-column)
1181
1182 (:hook (defun olivetti-mode@setup ()
1183 (if olivetti-mode
1184 (setq-local indicate-empty-lines nil
1185 indicate-buffer-boundaries nil)
1186 (acdw/setup-fringes)))))
1187
1069(setup (:straight (orderless 1188(setup (:straight (orderless
1070 :host github 1189 :host github
1071 :repo "oantolin/orderless")) 1190 :repo "oantolin/orderless"))
@@ -1123,434 +1242,6 @@
1123 ((string-suffix-p "~" pattern) 1242 ((string-suffix-p "~" pattern)
1124 `(orderless-flex . ,(substring pattern 0 -1)))))) 1243 `(orderless-flex . ,(substring pattern 0 -1))))))
1125 1244
1126(setup (:straight (topsy
1127 :host github
1128 :repo "alphapapa/topsy.el"))
1129 (:hook-into prog-mode))
1130
1131(setup (:straight (unfocused
1132 :host github
1133 :repo "duckwork/unfocused"))
1134 (unfocused-mode +1))
1135
1136(setup (:straight (vertico
1137 :host github
1138 :repo "minad/vertico"
1139 :files ("*" "extensions/*"
1140 (:exclude ".git"))))
1141
1142 (:option resize-mini-windows 'grow-only
1143 vertico-count-format nil
1144 vertico-cycle t)
1145
1146 (:with-map vertico-map
1147 (:bind "<C-backspace>"
1148 (defun up-directory (arg)
1149 "Move up a directory (delete backwards to /)."
1150 (interactive "p")
1151 (if (string-match-p "/." (minibuffer-contents))
1152 (zap-up-to-char (- arg) ?/)
1153 (backward-kill-word arg)))))
1154
1155 (if (boundp 'comp-deferred-compilation-deny-list)
1156 (add-to-list 'comp-deferred-compilation-deny-list "vertico"))
1157
1158 (vertico-mode +1)
1159
1160 ;; Extensions!
1161 (:also-load vertico-mouse)
1162 (vertico-mouse-mode +1)
1163
1164 ;; Prefix the current candidate with "> ". From Vertico wiki.
1165
1166 (:advise vertico--format-candidate :around
1167 (defun vertico-format@add-arrow (orig cand pref suf index start)
1168 (setq cand (funcall orig cand pref suf index start))
1169 (concat (if (= vertico--index index)
1170 (propertize "> " 'face 'vertico-current)
1171 " ")
1172 cand))))
1173
1174(setup (:straight alert)
1175 (:option alert-default-style (acdw/system
1176 (:home 'libnotify)
1177 (_ 'message))))
1178
1179(setup (:straight async)
1180 (:autoload (dired-async-mode :interactive t))
1181 (dired-async-mode +1)
1182
1183 (add-hook 'dired-mode
1184 (defun dired@disable-dired-async-mode-line ()
1185 (autoload 'dired-async--modeline-mode "dired-async.el" nil t)
1186 (dired-async--modeline-mode -1))))
1187
1188(setup (:straight avy)
1189 (:global "C-:" #'avy-goto-char-timer
1190 "C-c C-j" #'avy-resume)
1191
1192 (:with-feature isearch
1193 (:bind "C-'" #'avy-isearch)))
1194
1195(setup (:straight circe)
1196 (require 'circe)
1197 (require 'acdw-irc)
1198
1199 (:option acdw-irc/left-margin 12
1200 acdw-irc/post-my-nick "-> "
1201 circe-channel-killed-confirmation nil
1202 circe-color-nicks-everywhere t
1203 circe-default-nick "acdw"
1204 circe-default-part-message "See You, Space Cowpokes . . ."
1205 circe-default-user "acdw"
1206 circe-format-action
1207 (lambda (&rest plist)
1208 (concat
1209 (acdw-irc/margin-format "" "*" "*" t)
1210 " " (plist-get plist :nick) " " (plist-get plist :body)))
1211 circe-format-say
1212 (lambda (&rest plist)
1213 (concat
1214 (acdw-irc/margin-format (plist-get plist :nick) "" " |" t)
1215 " " (plist-get plist :body)))
1216 circe-format-self-action
1217 (lambda (&rest plist)
1218 (concat
1219 (acdw-irc/margin-format "" "-*" " *" t)
1220 " " (plist-get plist :nick) " " (plist-get plist :body)))
1221 circe-format-self-say
1222 (lambda (&rest plist)
1223 (concat
1224 (acdw-irc/margin-format (plist-get plist :nick) "-" " >" t)
1225 " " (plist-get plist :body)))
1226 circe-highlight-nick-type 'sender
1227 circe-network-options
1228 `(("Libera Chat"
1229 :channels ("#emacs" "#systemcrafters" "##webpals")
1230 :sasl-username circe-default-nick
1231 :sasl-password ,(acdw/make-password-fetcher
1232 :host "libera.chat"))
1233 ("Tilde Chat" :host "irc.tilde.chat" :port 6697 :use-tls t
1234 :channels ("#meta" "#bread" "#dadjokes" "#team")
1235 :sasl-username circe-default-nick
1236 :sasl-password ,(acdw/make-password-fetcher
1237 :host "tilde.chat"))
1238 ("Casa" :host "m455.casa" :port 6697 :use-tls t
1239 :channels ("#basement")
1240 :sasl-username circe-default-nick
1241 :sasl-password ,(acdw/make-password-fetcher
1242 :host "m455.casa"))
1243 ("Piss" :host "piss.hmm.st" :port 6697 :use-tls t))
1244 circe-reduce-lurker-spam t
1245 circe-server-auto-join-default-type :after-auth)
1246
1247 (custom-set-faces '(circe-nick-highlight-face
1248 ((t (:inherit (modus-themes-hl-line))))
1249 :now))
1250
1251 (:bind "C-c C-p" #'circe-command-PART)
1252
1253 (:advise circe-command-PART :after
1254 (defun circe-command-PART@kill-buffer (&rest _)
1255 (let ((circe-channel-killed-confirmation nil))
1256 (kill-buffer))))
1257
1258 (:with-mode circe-chat-mode
1259 (:hook #'acdw/stop-paren-annoyances
1260 (defun circe-chat@setup ()
1261 (lui-set-prompt
1262 (concat (propertize (acdw-irc/margin-format (buffer-name)
1263 ""
1264 ">")
1265 'face 'circe-prompt-face
1266 'read-only t 'intangible t
1267 'cursor-intangible t)
1268 " "))
1269 (enable-circe-color-nicks)
1270 (enable-circe-display-images)
1271 (enable-circe-new-day-notifier))))
1272
1273 (autoload 'circe-nick-color-reset "circe-color-nicks")
1274 (add-hook 'modus-themes-after-load-theme-hook
1275 #'circe-nick-color-reset)
1276
1277 (:with-mode lui-mode
1278 (:option lui-fill-column fill-column
1279 lui-fill-type (repeat-string acdw-irc/left-margin " ")
1280 lui-time-stamp-position 'right-margin
1281 lui-time-stamp-format "%H:%M"
1282 lui-track-behavior 'before-switch-to-buffer
1283 lui-track-indicator 'fringe)
1284
1285 (:hook (defun lui-mode@setup ()
1286 (setq-local fringes-outside-margins t
1287 right-margin-width 5
1288 scroll-margin 0
1289 word-wrap t
1290 wrap-prefix (repeat-string
1291 acdw-irc/left-margin " ")
1292 line-number-mode nil)
1293 (enable-lui-track)))))
1294
1295(setup (:straight crux)
1296
1297 (:global "C-x o" #'acdw/other-window-or-switch-buffer
1298 "C-o" #'crux-smart-open-line
1299 "M-o" #'crux-smart-open-line-above
1300 "C-M-\\" #'crux-cleanup-buffer-or-region
1301 "C-x 4 t" #'crux-transpose-windows)
1302
1303 (when (fboundp 'repeat-mode)
1304 (unless (boundp 'other-window-repeat-map)
1305 (defvar other-window-repeat-map (make-sparse-keymap)
1306 "A map for repeating `other-window' keys."))
1307
1308 (define-key other-window-repeat-map "o"
1309 #'acdw/other-window-or-switch-buffer)
1310 (define-key other-window-repeat-map "O"
1311 (defun acdw/other-window-or-switch-buffer-backward ()
1312 (interactive)
1313 (setq repeat-map 'other-window-repeat-map)
1314 (acdw/other-window-or-switch-buffer -1)))
1315
1316 (put 'acdw/other-window-or-switch-buffer
1317 'repeat-map 'other-window-repeat-map))
1318
1319 (crux-reopen-as-root-mode +1))
1320
1321;; requires extension:
1322;; https://addons.mozilla.org/en-US/firefox/addon/edit-with-emacs1/
1323(setup (:straight edit-server)
1324 (when (and (daemonp)
1325 (require 'edit-server nil :noerror))
1326 (edit-server-start)
1327
1328 (:advise edit-server-make-frame :before
1329 (defun edit-server@set-a-variable (&rest _)
1330 (setq-local edit-server-frame-p t)))))
1331
1332(setup (:straight elfeed
1333 elfeed-protocol)
1334 (:option elfeed-use-curl t
1335 elfeed-feeds `(("fever+https://acdw@mf.acdw.net"
1336 :api-url "https://mf.acdw.net/fever/"
1337 :password ,(acdw/make-password-fetcher
1338 :host "mf.acdw.net"))))
1339
1340 (elfeed-protocol-enable)
1341
1342 (:with-mode elfeed-show-mode
1343 (:hook (defun elfeed-show@setup ()
1344 (acdw/reading-mode)))
1345
1346 ;; see https://irreal.org/blog/?p=8885
1347 (:bind "SPC" (defun elfeed-scroll-up-command (&optional arg)
1348 "Scroll up or go to next feed item in Elfeed"
1349 (interactive "^P")
1350 (let ((scroll-error-top-bottom nil))
1351 (condition-case-unless-debug nil
1352 (scroll-up-command arg)
1353 (error (elfeed-show-next)))))
1354 "S-SPC" (defun elfeed-scroll-down-command (&optional arg)
1355 "Scroll up or go to next feed item in Elfeed"
1356 (interactive "^P")
1357 (let ((scroll-error-top-bottom nil))
1358 (condition-case-unless-debug nil
1359 (scroll-down-command arg)
1360 (error (elfeed-show-prev))))))))
1361
1362(setup (:straight elisp-slime-nav)
1363 (:hook-into emacs-lisp-mode
1364 ielm-mode))
1365
1366(setup (:straight embark)
1367 (:global "C-." #'embark-act)
1368 (:option prefix-help-command #'embark-prefix-help-command
1369 (append display-buffer-alist)
1370 '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
1371 nil
1372 (window-parameters (mode-line-format . none)))
1373 embark-prompter #'embark-keymap-prompter
1374 embark-verbose-indicator-display-action
1375 '(display-buffer-at-bottom (window-height . fit-window-to-buffer)))
1376
1377 (setq embark-action-indicator
1378 (lambda (map _target)
1379 (which-key--show-keymap "Embark" map nil nil 'no-paging)
1380 #'which-key--hide-popup-ignore-command)
1381 embark-become-indicator embark-action-indicator)
1382
1383 (with-eval-after-loads (embark consult)
1384 (:straight embark-consult)
1385 (add-hook 'embark-collect-mode-hook
1386 #'consult-preview-at-point-mode)))
1387
1388(setup (:straight epithet)
1389 (dolist (hook '(Info-selection-hook
1390 eww-after-render-hook
1391 help-mode-hook
1392 occur-mode-hook))
1393 (add-hook hook #'epithet-rename-buffer)))
1394
1395(setup (:straight eros)
1396 (:hook-into emacs-lisp-mode))
1397
1398(setup (:straight esh-autosuggest)
1399 (:autoload esh-autosuggest-mode)
1400 (:hook-into eshell-mode))
1401
1402(setup (:straight expand-region)
1403 (:global "C-=" #'er/expand-region
1404 "C-SPC"
1405 (defun acdw/set-mark-or-expand-region (arg)
1406 "Set mark at point and activate, jump to mark, or expand region.
1407See `set-mark-command' and `expand-region'.
1408
1409With no prefix argument, either run `set-mark-command' on first
1410invocation and `er/expand-region' on each successive invocation.
1411
1412With any prefix argument
1413(e.g., \\[universal-argument] \\[set-mark-command]), act as with
1414`set-mark-command' (i.e., pop the mark). Don't care about
1415successive invocations."
1416 (interactive "P")
1417 (cond
1418 ((or arg
1419 (and set-mark-command-repeat-pop
1420 (eq last-command 'pop-to-mark-command)))
1421 (setq this-command 'set-mark-command)
1422 (set-mark-command arg))
1423 ((eq last-command 'acdw/set-mark-or-expand-region)
1424 (er/expand-region 1))
1425 (t (set-mark-command arg))))))
1426
1427(setup (:straight flyspell-correct)
1428 (:with-mode flyspell-mode
1429 (:hook (defun flyspell@correct ()
1430 (:bind "C-;" #'flyspell-correct-wrapper)
1431 (:unbind "C-," "C-." "C-M-i")))))
1432
1433(setup (:straight gcmh)
1434 (:option gcmh-idle-delay 'auto)
1435 (gcmh-mode +1))
1436
1437;; TODO: figure out a popper.el / shackle.el ... thing to fix this
1438(setup (:straight helpful)
1439 (:option helpful-max-buffers 5)
1440 (:global "<help> f" #'helpful-callable
1441 "<help> v" #'helpful-variable
1442 "<help> k" #'helpful-key
1443 "<help> o" #'helpful-symbol))
1444
1445(setup (:straight hungry-delete)
1446 (:option hungry-delete-chars-to-skip " \t"
1447 hungry-delete-join-reluctantly nil)
1448
1449 (global-hungry-delete-mode +1)
1450
1451 (:with-feature paredit
1452 (:bind [remap paredit-backward-delete]
1453 (defun acdw/paredit-hungry-delete-backward (arg)
1454 (interactive "P")
1455 (if (looking-back "[ \t]" 1)
1456 (hungry-delete-backward (or arg 1))
1457 (paredit-backward-delete arg)))
1458
1459 [remap paredit-forward-delete]
1460 (defun acdw/paredit-hungry-delete-forward (arg)
1461 (interactive "P")
1462 (if (looking-at "[ \t]")
1463 (hungry-delete-forward (or arg 1))
1464 (paredit-forward-delete arg))))))
1465
1466(setup (:straight iscroll)
1467 (define-globalized-minor-mode global-iscroll-mode iscroll-mode
1468 (lambda () (iscroll-mode +1)))
1469
1470 (global-iscroll-mode +1))
1471
1472(setup (:straight lacarte)
1473 (:global "<f10>" #'lacarte-execute-menu-command))
1474
1475(setup (:straight link-hint)
1476 ;; Browse web URLs with a browser with a prefix argument.
1477 (dolist (type '(gnus-w3m-image-url
1478 gnus-w3m-url
1479 markdown-link
1480 mu4e-attachment
1481 mu4e-url
1482 notmuch-hello
1483 nov-link
1484 org-link
1485 shr-url
1486 text-url
1487 w3m-link
1488 w3m-message-link))
1489 (link-hint-define-type type
1490 :open-secondary browse-url-secondary-browser-function))
1491
1492 (:option link-hint-avy-style 'at)
1493 (:global "C-;"
1494 (defun acdw/link-hint-open-link (arg)
1495 "Open a link using `link-hint-open-link', prefix-aware.
1496That is, a prefix argument (\\[universal-argument]) will open the
1497browser defined in `browse-url-secondary-browser-function'."
1498 (interactive "P")
1499 (avy-with link-hint-open-link
1500 (link-hint--one (if arg :open-secondary :open))))))
1501
1502(setup (:straight lua-mode)
1503 (:file-match (rx ".lua" eos)))
1504
1505(setup (:straight macrostep)
1506 (:with-mode emacs-lisp-mode
1507 (:bind "C-c e" #'macrostep-expand)))
1508
1509(setup (:straight magit)
1510 (:global "C-c g" #'magit-status)
1511
1512 (:option magit-display-buffer-function
1513 (defun magit-display-buffer-same-window (buffer)
1514 "Display BUFFER in the selected window like God intended."
1515 (display-buffer buffer '(display-buffer-same-window)))
1516 magit-popup-display-buffer-action '((display-buffer-same-window))
1517 magit-refresh-status-buffer nil))
1518
1519(setup (:straight marginalia)
1520 (:option marginalia-annotators '(marginalia-annotators-heavy
1521 marginalia-annotators-light))
1522 (marginalia-mode +1))
1523
1524(setup (:straight markdown-mode)
1525 (dolist (cell '(("README\\.md\\'" . gfm-mode)
1526 ("\\.md\\'" . markdown-mode)
1527 ("\\.markdown\\'" . markdown-mode)))
1528 (add-to-list 'auto-mode-alist cell))
1529
1530 (when (executable-find "markdownfmt")
1531 (with-eval-after-load 'apheleia
1532 (:option (append apheleia-formatters) '(markdownfmt . ("markdownfmt"))
1533 (append apheleia-mode-alist) '(markdown-mode . markdownfmt)
1534 (append apheleia-mode-alist) '(gfm-mode . markdownfmt)))))
1535
1536(setup (:straight mwim)
1537 (:global "C-a" #'mwim-beginning
1538 "C-e" #'mwim-end))
1539
1540(setup (:straight nov)
1541 (:option nov-text-width fill-column)
1542 (:file-match (rx ".epub" eos)))
1543
1544(setup (:straight olivetti)
1545 (:option olivetti-body-width (+ fill-column 4)
1546 olivetti-minimum-body-width fill-column)
1547
1548 (:hook (defun olivetti-mode@setup ()
1549 (if olivetti-mode
1550 (setq-local indicate-empty-lines nil
1551 indicate-buffer-boundaries nil)
1552 (acdw/setup-fringes)))))
1553
1554(setup (:straight org 1245(setup (:straight org
1555 org-contrib) 1246 org-contrib)
1556 (:also-load 'acdw-org) ; so I don't clutter up init.el 1247 (:also-load 'acdw-org) ; so I don't clutter up init.el
@@ -1598,8 +1289,8 @@ browser defined in `browse-url-secondary-browser-function'."
1598 "C-c C-p" #'acdw/org-previous-heading-widen) 1289 "C-c C-p" #'acdw/org-previous-heading-widen)
1599 1290
1600 (with-eval-after-load 'org-export 1291 (with-eval-after-load 'org-export
1601 (add-to-list 'org-export-filter-final-output-functions 1292 (:option (append org-export-filter-final-output-functions)
1602 #'org-export-remove-zero-width-spaces)) 1293 #'org-export-remove-zero-width-spaces))
1603 1294
1604 (:hook variable-pitch-mode 1295 (:hook variable-pitch-mode
1605 olivetti-mode 1296 olivetti-mode
@@ -1626,6 +1317,34 @@ browser defined in `browse-url-secondary-browser-function'."
1626 1317
1627(setup (:straight package-lint-flymake)) 1318(setup (:straight package-lint-flymake))
1628 1319
1320(setup page
1321 (:option page-delimiter
1322 (rx bol (or "\f" ";;;")
1323 (not (any "#")) (* not-newline) "\n"
1324 (* (* blank) (opt ";" (* not-newline)) "\n")))
1325
1326 (defun recenter-to-top (&rest _)
1327 "Recenter the cursor to the top of the window."
1328 (when (called-interactively-p 'any)
1329 (recenter (if (or (null scroll-margin)
1330 (zerop scroll-margin))
1331 3
1332 scroll-margin))))
1333
1334 (:advise forward-page :after #'recenter-to-top
1335 backward-page :after #'recenter-to-top)
1336
1337 ;; I'm not sure where this is in /my/ version of Emacs
1338 (defvar page-navigation-repeat-map
1339 (let ((map (make-sparse-keymap)))
1340 (define-key map "]" #'forward-page)
1341 (define-key map "[" #'backward-page)
1342 map)
1343 "Keymap to repeat page navigation key sequences. Used in `repeat-mode'.")
1344
1345 (put 'forward-page 'repeat-map 'page-navigation-repeat-map)
1346 (put 'backward-page 'repeat-map 'page-navigation-repeat-map))
1347
1629(setup (:straight page-break-lines) 1348(setup (:straight page-break-lines)
1630 (global-page-break-lines-mode +1)) 1349 (global-page-break-lines-mode +1))
1631 1350
@@ -1652,6 +1371,13 @@ browser defined in `browse-url-secondary-browser-function'."
1652 (dolist (mode lispy-modes) 1371 (dolist (mode lispy-modes)
1653 (add-hook (intern (concat (symbol-name mode) "-hook")) #'paren-face-mode))) 1372 (add-hook (intern (concat (symbol-name mode) "-hook")) #'paren-face-mode)))
1654 1373
1374(setup (:straight-if (pdf-tools
1375 :host github
1376 :repo "vedang/pdf-tools")
1377 (acdw/system :home))
1378 (:file-match (rx ".pdf" eos))
1379 (pdf-loader-install))
1380
1655(setup (:straight persistent-scratch) 1381(setup (:straight persistent-scratch)
1656 (:option persistent-scratch-backup-directory (acdw/dir "scratch" t) 1382 (:option persistent-scratch-backup-directory (acdw/dir "scratch" t)
1657 persistent-scratch-keep-n-newest-backups 12) 1383 persistent-scratch-keep-n-newest-backups 12)
@@ -1664,19 +1390,171 @@ browser defined in `browse-url-secondary-browser-function'."
1664 (persistent-scratch-mode +1)))) 1390 (persistent-scratch-mode +1))))
1665 (buffer-list))) 1391 (buffer-list)))
1666 1392
1393(setup (:straight-if pkgbuild-mode
1394 (executable-find "makepkg"))
1395 (:file-match "PKGBUILD"))
1396
1667(setup (:straight powerthesaurus) 1397(setup (:straight powerthesaurus)
1668 (:global "C-c l t" #'powerthesaurus-lookup-word-dwim)) 1398 (:global "C-c l t" #'powerthesaurus-lookup-word-dwim))
1669 1399
1400(setup prog
1401 (:option show-paren-delay 0
1402 show-paren-style 'mixed
1403 show-paren-when-point-inside-paren t
1404 show-paren-when-point-in-periphery t
1405 smie-indent-basic tab-width)
1406
1407 (:hook show-paren-mode
1408 electric-pair-local-mode
1409 acdw/setup-fringes
1410
1411 (defun flymake-mode-except ()
1412 "Turn on flymake mode, except in some modes."
1413 (let ((no-flymake-modes '(emacs-lisp-mode)))
1414 (unless (or (member major-mode no-flymake-modes)
1415 (apply #'derived-mode-p no-flymake-modes))
1416 (flymake-mode-on))))
1417
1418 (defun prog-mode@auto-fill ()
1419 (setq-local comment-auto-fill-only-comments t)
1420 (turn-on-auto-fill)))
1421
1422 (add-hook 'after-save-hook
1423 #'executable-make-buffer-file-executable-if-script-p))
1424
1425(setup (:require recentf)
1426 (:option recentf-save-file (acdw/dir "recentf.el")
1427 recentf-max-menu-items 100
1428 recentf-max-saved-items nil
1429 recentf-auto-cleanup 'mode
1430 (append recentf-exclude) (acdw/dir))
1431
1432 (:advise dired-rename-file :after #'rjs/recentf-rename-notify)
1433
1434 (recentf-mode +1))
1435
1436(setup repeat
1437 ;; new for Emacs 28!
1438 (:only-if (fboundp #'repeat-mode))
1439
1440 (:option repeat-exit-key "g"
1441 repeat-exit-timeout 5)
1442
1443 (repeat-mode +1))
1444
1670(setup (:straight restart-emacs) 1445(setup (:straight restart-emacs)
1671 (defun emacs-upgrade (&optional update-packages) 1446 (defun emacs-upgrade (&optional update-packages)
1672 "Pull config, upgrade packages, restart Emacs." 1447 "Pull config, upgrade packages, restart Emacs."
1673 (interactive "P") 1448 (interactive "P")
1674 (emacs-git-pull-config) 1449 (emacs-git-pull-config)
1675 (when update-packages 1450 (when update-packages
1676 (require 'straight) 1451 (require 'straight-x)
1677 (straight-pull-all)) 1452 (straight-x-pull-all))
1678 (restart-emacs))) 1453 (restart-emacs)))
1679 1454
1455(setup (:require savehist)
1456 (:option history-length t
1457 history-delete-duplicates t
1458 savehist-autosave-interval 60
1459 savehist-file (acdw/dir "savehist.el"))
1460
1461 (dolist (var '(extended-command-history
1462 global-mark-ring
1463 kill-ring
1464 regexp-search-ring
1465 search-ring
1466 mark-ring))
1467 (:option (append savehist-additional-variables) var))
1468
1469 (savehist-mode +1))
1470
1471(setup saveplace
1472 (:option save-place-file (acdw/dir "places.el")
1473 save-place-forget-unreadable-files (acdw/system :home))
1474
1475 (save-place-mode +1))
1476
1477(setup scratch
1478 (:option inhibit-startup-screen t
1479 initial-buffer-choice t
1480 initial-scratch-message ""
1481 ;; (concat ";; Howdy, "
1482 ;; (nth 0 (split-string
1483 ;; user-full-name))
1484 ;; "! "
1485 ;; "Welcome to GNU Emacs.\n\n")
1486 initial-major-mode 'emacs-lisp-mode)
1487
1488 (add-hook 'kill-buffer-query-functions
1489 (defun kill-buffer-query@immortal-scratch ()
1490 (if (eq (current-buffer) (get-buffer "*scratch*"))
1491 (progn (bury-buffer)
1492 nil)
1493 t))))
1494
1495(setup scrolling
1496 (:option auto-window-vscroll nil
1497 fast-but-imprecise-scrolling t
1498 scroll-margin 3
1499 scroll-conservatively 101
1500 scroll-preserve-screen-position 1))
1501
1502(setup selection
1503 (:option save-interprogram-paste-before-kill t
1504 yank-pop-change-selection t
1505 x-select-enable-clipboard t
1506 x-select-enable-primary t
1507 mouse-drag-copy-region t
1508 kill-do-not-save-duplicates t)
1509
1510 (delete-selection-mode +1))
1511
1512(setup (:require server)
1513 (unless (server-running-p)
1514 (server-start)))
1515
1516(setup sh-mode
1517 (:option sh-basic-offset tab-width
1518 sh-indent-after-case 0
1519 sh-indent-for-case-alt '+
1520 sh-indent-for-case-label 0)
1521
1522 (:local-set indent-tabs-mode t)
1523
1524 (when (executable-find "shfmt")
1525 (with-eval-after-load 'apheleia
1526 (:option (append apheleia-formatters) '(shfmt . ("shfmt"))
1527 (append apheleia-mode-alist) '(sh-mode . shfmt))))
1528
1529 (when (executable-find "shellcheck")
1530 (:straight flymake-shellcheck)
1531 (:hook flymake-mode
1532 flymake-shellcheck-load)))
1533
1534(setup shell-command
1535 (:option shell-command-switch (acdw/system
1536 ;; I should be testing on some variable
1537 (:home "-csi")
1538 (:work "-c"))
1539 shell-command-prompt-show-cwd t
1540 shell-command-default-error-buffer "*shell-command-errors*"))
1541
1542(setup (:straight (shell-command+
1543 :host nil
1544 :repo "https://git.sr.ht/~pkal/shell-command-plus"))
1545 (:option shell-command-prompt "$ ")
1546 (:with-feature dired
1547 (:bind "M-!" shell-command+))
1548 (:global "M-!" shell-command+))
1549
1550(setup shr
1551 (:option shr-width fill-column
1552 shr-max-width fill-column
1553 shr-max-image-proportion 0.6
1554 shr-image-animate t
1555 shr-discard-aria-hidden t
1556 shr-folding-mode t))
1557
1680(setup (:straight simple-modeline 1558(setup (:straight simple-modeline
1681 minions) 1559 minions)
1682 (:also-load acdw-modeline) 1560 (:also-load acdw-modeline)
@@ -1716,15 +1594,60 @@ browser defined in `browse-url-secondary-browser-function'."
1716 1594
1717 (simple-modeline-mode +1)) 1595 (simple-modeline-mode +1))
1718 1596
1597(setup (:straight-if sly
1598 (progn
1599 (defvar acdw/lisps
1600 (let (lisps)
1601 (dolist (lisp '("sbcl" ; TODO: add more lisps
1602 "clisp"))
1603 (when-let (binary (executable-find lisp))
1604 (push binary lisps)))
1605 (nreverse lisps)))
1606 acdw/lisps))
1607 (:also-load sly-autoloads)
1608 (:straight clhs)
1609
1610 (:option inferior-lisp-program acdw/lisp-bin
1611 sly-kill-without-query-p t)
1612
1613 (:with-feature sly-mrepl
1614 (defun sly-mrepl-return-at-end ()
1615 (interactive)
1616 (if (<= (point-max) (point))
1617 (sly-mrepl-return)
1618 (if (bound-and-true-p paredit-mode)
1619 (paredit-newline)
1620 (electric-newline-and-maybe-indent))))
1621
1622 (dolist (key '("RET" "<return>"))
1623 (:bind key #'sly-mrepl-return-at-end))
1624
1625 (:bind "C-c C-c" #'sly-mrepl-return)))
1626
1719(setup (:straight ssh-config-mode) 1627(setup (:straight ssh-config-mode)
1720 (dolist (spec '(("/\\.ssh/config\\'" . ssh-config-mode) 1628 (:file-match (rx "/.ssh/config" eos)
1721 ("/sshd?_config\\'" . ssh-config-mode) 1629 (rx "/ssh" (? "d") "_config" eos))
1722 ("/knownhosts\\'" . ssh-known-hosts-mode) 1630
1723 ("/authorized_keys2?\\'" . ssh-authorized-keys-mode))) 1631 (:with-mode ssh-known-hosts-mode
1724 (add-to-list 'auto-mode-alist spec)) 1632 (:file-match (rx "/knownhosts" eos)))
1633
1634 (:with-mode ssh-authorized-keys-mode
1635 (:file-match (rx "/authorized_keys" (? "2") eos)))
1725 1636
1726 (:hook #'turn-on-font-lock)) 1637 (:hook #'turn-on-font-lock))
1727 1638
1639(setup (:straight-if systemd
1640 (executable-find "systemd")))
1641
1642(setup text
1643 (:hook turn-on-auto-fill
1644 acdw/setup-fringes))
1645
1646(setup (:straight (topsy
1647 :host github
1648 :repo "alphapapa/topsy.el"))
1649 (:hook-into prog-mode))
1650
1728(setup (:straight typo) 1651(setup (:straight typo)
1729 1652
1730 ;; Enable C-c 8 map in all buffers 1653 ;; Enable C-c 8 map in all buffers
@@ -1747,7 +1670,6 @@ browser defined in `browse-url-secondary-browser-function'."
1747 ;; consideration, not an input consideration. (I suppose you could make 1670 ;; consideration, not an input consideration. (I suppose you could make
1748 ;; the argument that all of these are typographical considerations, but 1671 ;; the argument that all of these are typographical considerations, but
1749 ;; .. bleh.) 1672 ;; .. bleh.)
1750
1751 (:bind "'" (define-typo-cycle typo-cycle-apostrophe 1673 (:bind "'" (define-typo-cycle typo-cycle-apostrophe
1752 "Cycle through apostrophe-like graphemes. 1674 "Cycle through apostrophe-like graphemes.
1753If used with a numeric prefix argument N, N apostrophes will be inserted." 1675If used with a numeric prefix argument N, N apostrophes will be inserted."
@@ -1771,11 +1693,85 @@ If used with a numeric prefix argument N, N backticks will be inserted."
1771 1693
1772(setup (:straight unfill)) 1694(setup (:straight unfill))
1773 1695
1696(setup (:straight (unfocused
1697 :host github
1698 :repo "duckwork/unfocused"))
1699 (unfocused-mode +1))
1700
1701(setup uniquify
1702 (:option uniquify-buffer-name-style 'forward
1703 uniquify-separator path-separator
1704 uniquify-after-kill-buffer-p t
1705 uniquify-ignore-buffers-re "^\\*"))
1706
1707(setup variable-pitch-mode
1708 ;; I might want to change this to `buffer-face-mode-hook'...
1709 (:advise variable-pitch-mode :after
1710 (defun variable-pitch-mode@setup (&rest _)
1711 "Set up `variable-pitch-mode' with my customizations."
1712 (display-fill-column-indicator-mode (if buffer-face-mode
1713 -1
1714 +1)))))
1715
1716(setup (:straight (vertico
1717 :host github
1718 :repo "minad/vertico"
1719 :files ("*" "extensions/*"
1720 (:exclude ".git"))))
1721
1722 (:option resize-mini-windows 'grow-only
1723 vertico-count-format nil
1724 vertico-cycle t)
1725
1726 (:with-map vertico-map
1727 (:bind "<C-backspace>"
1728 (defun up-directory (arg)
1729 "Move up a directory (delete backwards to /)."
1730 (interactive "p")
1731 (if (string-match-p "/." (minibuffer-contents))
1732 (zap-up-to-char (- arg) ?/)
1733 (backward-kill-word arg)))))
1734
1735 (when (boundp 'native-comp-deferred-compilation-deny-list)
1736 (add-to-list 'native-comp-deferred-compilation-deny-list "vertico"))
1737
1738 (vertico-mode +1)
1739
1740 ;; Extensions!
1741 (:also-load vertico-mouse)
1742 (vertico-mouse-mode +1)
1743
1744 ;; Prefix the current candidate with "> ". From Vertico wiki.
1745 (:advise vertico--format-candidate :around
1746 (defun vertico-format@add-arrow (orig cand pref suf index start)
1747 (setq cand (funcall orig cand pref suf index start))
1748 (concat (if (= vertico--index index)
1749 (propertize "> " 'face 'vertico-current)
1750 " ")
1751 cand))))
1752
1753(setup view
1754 (:option view-read-only t)
1755
1756 (:hook (defun acdw/read-view-mode ()
1757 (acdw/reading-mode (if view-mode +1 -1)))))
1758
1774(setup (:straight visual-regexp) 1759(setup (:straight visual-regexp)
1775 (:global "M-%" #'vr/query-replace)) 1760 (:global "M-%" #'vr/query-replace))
1776 1761
1777(setup (:straight wc-mode) ; TODO: move some of this stuff around 1762(setup (:straight-if vterm
1763 (acdw/system :home)))
1778 1764
1765(setup w32
1766 (:option w32-allow-system-shell t
1767 w32-pass-lwindow-to-system nil
1768 w32-lwindow-modifier 'super
1769 w32-pass-rwindow-to-system nil
1770 w32-rwindow-modifier 'super
1771 w32-pass-apps-to-system nil
1772 w32-apps-modifier 'hyper))
1773
1774(setup (:straight wc-mode)
1779 (:option wc-modeline-format "[%tww]" 1775 (:option wc-modeline-format "[%tww]"
1780 wc-idle-wait 2) 1776 wc-idle-wait 2)
1781 1777
@@ -1786,13 +1782,14 @@ If used with a numeric prefix argument N, N backticks will be inserted."
1786 js-indent-level 2 1782 js-indent-level 2
1787 sgml-indent-offset 2) 1783 sgml-indent-offset 2)
1788 1784
1789 (:file-match "\\.\\(p\\|dj\\)?html\\'" 1785 (:file-match (rx ".htm" (? "l") eos)
1790 "\\.html?\\'" 1786 (rx "." (? "tpl.") "php" eos)
1791 "\\.\\(tpl\\.\\)?php\\'" 1787 (rx "." (| "asp" "gsp" "jsp") eos)
1792 "\\.[agj]sp\\'" 1788 (rx "." (| "ascx" "aspx") eos)
1793 "\\.as[cp]x\\'" 1789 (rx ".erb" eos)
1794 "\\.erb\\'" 1790 (rx ".mustache" eos)))
1795 "\\.mustache\\'")) 1791
1792(setup (:straight wgrep))
1796 1793
1797(setup (:straight which-key) 1794(setup (:straight which-key)
1798 (:option which-key-show-early-on-C-h t 1795 (:option which-key-show-early-on-C-h t
@@ -1805,9 +1802,98 @@ If used with a numeric prefix argument N, N backticks will be inserted."
1805 (which-key-setup-side-window-right-bottom) 1802 (which-key-setup-side-window-right-bottom)
1806 (which-key-mode +1)) 1803 (which-key-mode +1))
1807 1804
1805(setup whitespace
1806 (:option whitespace-style
1807 '(empty indentation space-before-tab space-after-tab)
1808 indent-tabs-mode nil
1809 tab-width 4
1810 backward-delete-char-untabify-method 'hungry)
1811
1812 (:global "M-SPC" #'cycle-spacing))
1813
1808(setup (:straight whitespace-cleanup-mode) 1814(setup (:straight whitespace-cleanup-mode)
1809 (global-whitespace-cleanup-mode +1)) 1815 (global-whitespace-cleanup-mode +1))
1810 1816
1817(setup windmove
1818 (:option windmove-wrap-around t)
1819 (:global
1820 ;; moving
1821 "C-x 4 <left>" #'windmove-left
1822 "C-x 4 <right>" #'windmove-right
1823 "C-x 4 <up>" #'windmove-up
1824 "C-x 4 <down>" #'windmove-down
1825 ;; swapping
1826 "C-x 4 S-<left>" #'windmove-swap-states-left
1827 "C-x 4 S-<right>" #'windmove-swap-states-right
1828 "C-x 4 S-<up>" #'windmove-swap-states-up
1829 "C-x 4 S-<down>" #'windmove-swap-states-down)
1830
1831 (when (fboundp 'repeat-mode)
1832 (defvar windmove-repeat-map
1833 (let ((map (make-sparse-keymap)))
1834 ;; moving
1835 (define-key map [left] #'windmove-left)
1836 (define-key map [right] #'windmove-right)
1837 (define-key map [up] #'windmove-up)
1838 (define-key map [down] #'windmove-down)
1839 ;; swapping
1840 (define-key map [S-left] #'windmove-swap-states-left)
1841 (define-key map [S-right] #'windmove-swap-states-right)
1842 (define-key map [S-up] #'windmove-swap-states-up)
1843 (define-key map [S-down] #'windmove-swap-states-down)
1844 map)
1845 "Keymap to repeat various `windmove' sequences. Used in `repeat-mode'.")
1846
1847 (dolist (sym '(windmove-left
1848 windmove-right
1849 windmove-up
1850 windmove-down
1851 windmove-swap-states-left
1852 windmove-swap-states-right
1853 windmove-swap-states-up
1854 windmove-swap-states-down))
1855 (put sym 'repeat-map 'windmove-repeat-map))))
1856
1857(setup window
1858 (require 'acdw-bell)
1859 (:option Man-notify-method 'pushy
1860 display-buffer-alist ; from FrostyX
1861 '(("shell.*" (display-buffer-same-window) ())
1862 (".*" (display-buffer-reuse-window
1863 display-buffer-same-window)
1864 (reusable-frames . t)))
1865 recenter-positions '(top middle bottom)
1866 ring-bell-function (lambda ()
1867 (acdw-bell/flash-mode-line
1868 (acdw/system :home)))
1869 tab-bar-show 1
1870 use-dialog-box nil
1871 use-file-dialog nil
1872 visible-bell nil)
1873
1874 (tooltip-mode -1))
1875
1876(setup winner
1877 ;; see https://lists.gnu.org/archive/html/emacs-devel/2021-08/msg00888.html
1878 (:global "C-x 4 C-/" #'winner-undo
1879 "C-x 4 /" #'winner-undo
1880 "C-x 4 C-?" #'winner-redo
1881 "C-x 4 ?" #'winner-redo)
1882
1883 ;; add `winner-undo' and `winner-redo' to `repeat-mode'
1884 (when (fboundp 'repeat-mode)
1885 (defvar winner-mode-repeat-map
1886 (let ((map (make-sparse-keymap)))
1887 (define-key map "/" #'winner-undo)
1888 (define-key map "?" #'winner-redo)
1889 map)
1890 "Keymap to repeat `winner-mode' sequences. Used in `repeat-mode'.")
1891
1892 (put 'winner-undo 'repeat-map 'winner-mode-repeat-map)
1893 (put 'winner-redo 'repeat-map 'winner-mode-repeat-map))
1894
1895 (winner-mode +1))
1896
1811(setup (:straight winum) 1897(setup (:straight winum)
1812 (:option winum-scope 'frame-local 1898 (:option winum-scope 'frame-local
1813 winum-auto-setup-mode-line nil 1899 winum-auto-setup-mode-line nil
@@ -1834,154 +1920,93 @@ If used with a numeric prefix argument N, N backticks will be inserted."
1834 1920
1835 (winum-mode +1)) 1921 (winum-mode +1))
1836 1922
1837(setup (:straight xr)) 1923(setup x-emacs
1838 1924 ;; "Et cetera" settings
1839(setup (:straight zzz-to-char) 1925 ;; This should stay as /minimal/ as possible. Anything that can go somewhere
1840 1926 ;; else /should/ go there.
1841 (:global "M-z"
1842 (defun acdw/zzz-up-to-char (prefix)
1843 "Call `zzz-up-to-char' or `zzz-to-char', PREFIX-depending."
1844 (interactive "P")
1845 (if prefix
1846 (call-interactively #'zzz-to-char)
1847 (call-interactively #'zzz-up-to-char)))))
1848
1849(setup (:straight-if (pdf-tools
1850 :host github
1851 :repo "vedang/pdf-tools")
1852 (acdw/system :home))
1853 (:file-match (rx ".pdf" eos))
1854 (pdf-loader-install))
1855
1856(setup (:straight-if affe
1857 (and (or (executable-find "fd")
1858 (executable-find "find"))
1859 (executable-find "rg")))
1860 ;; Keys are bound in `acdw/sensible-grep' and `acdw/sensible-find'
1861 (:option affe-regexp-compiler
1862 (defun affe-orderless-regexp-compiler (input _type)
1863 (setq input (orderless-pattern-compiler input))
1864 (cons input (lambda (str) (orderless--highlight input str))))))
1865
1866(setup (:straight-if ahk-mode
1867 (acdw/system :work)))
1868
1869;; TODO: look into emms or something related for this
1870(setup (:straight-if eradio
1871 (executable-find "mpv"))
1872 (:option 1927 (:option
1873 eradio-player '("mpv" "--no-video" "--no-terminal") 1928 attempt-orderly-shutdown-on-fatal-signal nil
1874 eradio-channels `(("KLSU" . 1929 attempt-stack-overflow-recovery nil
1875 "http://130.39.238.143:8010/stream.mp3") 1930 echo-keystrokes 0.01
1876 ("Soma FM Synphaera" . 1931 find-function-C-source-directory (acdw/find-emacs-source)
1877 "https://somafm.com/synphaera256.pls") 1932 kill-read-only-ok t
1878 ("SomaFM BAGel Radio" . 1933 load-prefer-newer t
1879 "https://somafm.com/bagel.pls") 1934 native-comp-async-report-warnings-errors nil
1880 ("SomaFM Boot Liquor" . 1935 set-mark-command-repeat-pop t)
1881 "https://somafm.com/bootliquor320.pls")
1882 ("SomaFM Deep Space One" .
1883 "https://somafm.com/deepspaceone.pls")
1884 ("SomaFM Fluid" .
1885 "https://somafm.com/fluid.pls")
1886 ("SomaFM Underground 80s" .
1887 "https://somafm.com/u80s256.pls")
1888 ("WBRH: Jazz & More" .
1889 "http://wbrh.streamguys1.com/wbrh-mp3")
1890 ("KBRH Blues & Rhythm Hits" .
1891 "http://wbrh.streamguys1.com/kbrh-mp3")
1892 ("WRKF HD-2" .
1893 ,(concat "https://playerservices.streamtheworld.com/"
1894 "api/livestream-redirect/WRKFHD2.mp3"))
1895 ("WRKF: NPR for the Capital Region" .
1896 ,(concat "https://playerservices.streamtheworld.com/"
1897 "api/livestream-redirect/WRKFFM.mp3"))
1898 ("BadRadio: 24/7 PHONK" .
1899 "https://s2.radio.co/s2b2b68744/listen")
1900 ("tilderadio" .
1901 "https://radio.tildeverse.org/radio/8000/radio.ogg")
1902 ("vantaradio" .
1903 "https://vantaa.black/radio")))
1904 (:global "C-c r r" #'eradio-play ; mnemonic: radio
1905 "C-c r s" #'eradio-stop ; mnemonic: stop
1906 "C-c r p" #'eradio-toggle ; mnemonic: play/pause
1907 ))
1908 1936
1909(setup (:straight-if exec-path-from-shell 1937 (when (fboundp 'command-completion-default-include-p)
1910 (acdw/system :home)) 1938 (setq read-extended-command-predicate
1911 (when (daemonp) 1939 #'command-completion-default-include-p))
1912 (exec-path-from-shell-initialize)))
1913 1940
1914(setup (:straight-if fennel-mode 1941 (defvar case-map (make-sparse-keymap)
1915 (executable-find "fennel")) 1942 "A keymap for setting case in various ways.")
1916 (:autoload (fennel-repl :interactive t)) 1943 (global-set-key (kbd "C-c c") case-map)
1917 (:file-match (rx ".fnl" eos)))
1918 1944
1919(setup (:straight-if geiser 1945 (defvar lookup-map (make-sparse-keymap)
1920 (progn 1946 "A keymap for looking up things.")
1921 (defvar acdw/schemes 1947 (global-set-key (kbd "C-c l") lookup-map)
1922 (let (schemes) 1948
1923 (dolist (scheme '(("scheme" . geiser-chez) ; chez 1949 (:global "M-=" #'count-words
1924 ("petite" . geiser-chez) ; petite 1950 "C-w" #'kill-region-or-backward-word
1925 ("csi" . geiser-chez) ; chicken 1951 "C-c c c" #'capitalize-dwim
1926 ("gsi" . geiser-gambit) 1952 "C-c c t" #'titlecase-dwim
1927 ("gosh" . geiser-gauche) 1953 "C-c c u" #'upcase-dwim
1928 ("guile" . geiser-guile) 1954 "C-c c l" #'downcase-dwim
1929 ("kawa" . geiser-kawa) 1955 "C-c d" #'acdw/insert-iso-date
1930 ("mit-scheme" . geiser-mit) 1956 "M-`" nil)
1931 ("racket" . geiser-racket)
1932 ("stklos" . geiser-stklos)))
1933 (when-let (binary (executable-find (car scheme)))
1934 (push binary schemes)
1935 ;; and install the proper helper package
1936 (straight-use-package (cdr scheme))))
1937 (nreverse schemes)))
1938 acdw/schemes))
1939 (:file-match (rx ".rkt" eos)
1940 (rx ".scm" eos)))
1941 1957
1942(setup (:straight-if ledger-mode 1958 ;; toggle bindings
1943 (executable-find "ledger"))) 1959 (defvar toggle-map (make-sparse-keymap)
1960 "A keymap for toggling!")
1961 (global-set-key (kbd "C-c t") toggle-map)
1944 1962
1945(setup (:straight-if pkgbuild-mode 1963 (:with-map toggle-map
1946 (executable-find "makepkg")) 1964 (:bind "c" #'column-number-mode
1947 (:file-match "PKGBUILD")) 1965 "l" #'display-line-numbers-mode
1966 "d" #'toggle-debug-on-error))
1948 1967
1949(setup (:straight-if sly 1968 (defalias 'forward-word-with-case 'forward-word
1950 (progn 1969 "Alias for `forward-word' for use in `case-repeat-map'.")
1951 (defvar acdw/lisps 1970 (defalias 'backward-word-with-case 'backward-word
1952 (let (lisps) 1971 "Alias for `backward-word for use in `case-repeat-map'.")
1953 (dolist (lisp '("sbcl" ; TODO: add more lisps
1954 "clisp"))
1955 (when-let (binary (executable-find lisp))
1956 (push binary lisps)))
1957 (nreverse lisps)))
1958 acdw/lisps))
1959 (:also-load sly-autoloads)
1960 (:straight clhs)
1961
1962 (:option inferior-lisp-program acdw/lisp-bin
1963 sly-kill-without-query-p t)
1964 1972
1965 (defun sly-mrepl-return-at-end () 1973 (defvar case-repeat-map
1966 (interactive) 1974 (let ((map (make-sparse-keymap)))
1967 (if (<= (point-max) (point)) 1975 (define-key map "c" #'capitalize-word)
1968 (sly-mrepl-return) 1976 (define-key map "u" #'upcase-word)
1969 (if (bound-and-true-p paredit-mode) 1977 (define-key map "l" #'downcase-word)
1970 (paredit-newline) 1978 ;; movement
1971 (electric-newline-and-maybe-indent)))) 1979 (define-key map "f" #'forward-word-with-case)
1980 (define-key map "b" #'backward-word-with-case)
1981 map)
1982 "A map to repeat word-casing commands. For use with `repeat-mode'.")
1972 1983
1973 (:with-feature sly-mrepl 1984 (dolist (command '(capitalize-word
1974 (dolist (key '("RET" "<return>")) 1985 capitalize-dwim
1975 (:bind key #'sly-mrepl-return-at-end)) 1986 upcase-word
1976 (:bind "C-c C-c" #'sly-mrepl-return))) 1987 upcase-dwim
1988 downcase-word
1989 downcase-dwim
1990 forward-word-with-case
1991 backward-word-with-case))
1992 (put command 'repeat-map 'case-repeat-map))
1977 1993
1978(setup (:straight-if systemd 1994 (add-hook 'after-make-frame-functions
1979 (executable-find "systemd"))) 1995 (defun after-make-frame@maximize (frame)
1996 (unless (bound-and-true-p edit-server-frame-p)
1997 (toggle-frame-maximized frame)))))
1980 1998
1981(setup (:straight-if vterm 1999(setup (:straight xr))
1982 (acdw/system :home)))
1983 2000
1984(setup (:straight wgrep)) 2001(setup (:straight zzz-to-char)
2002
2003 (:global "M-z"
2004 (defun acdw/zzz-up-to-char (prefix)
2005 "Call `zzz-up-to-char' or `zzz-to-char', PREFIX-depending."
2006 (interactive "P")
2007 (if prefix
2008 (call-interactively #'zzz-to-char)
2009 (call-interactively #'zzz-up-to-char)))))
1985 2010
1986 2011
1987;;; init.el ends here 2012;;; init.el ends here
diff --git a/lisp/acdw.el b/lisp/acdw.el index 8db7fea..cf8914f 100644 --- a/lisp/acdw.el +++ b/lisp/acdw.el
@@ -19,7 +19,9 @@
19;; functions for me, acdw. 19;; functions for me, acdw.
20 20
21;;; Code: 21;;; Code:
22 22
23(require 'cl-lib)
24
23;;; Variables 25;;; Variables
24 26
25(defconst acdw/system 27(defconst acdw/system
@@ -242,10 +244,12 @@ With a prefix argument N, (un)comment that many sexps."
242 244
243;;; Sort sexps 245;;; Sort sexps
244;; from https://github.com/alphapapa/unpackaged.el#sort-sexps 246;; from https://github.com/alphapapa/unpackaged.el#sort-sexps
247;; and https://github.com/alphapapa/unpackaged.el/issues/20
245 248
246(defun sort-sexps (beg end) 249(defun sort-sexps (beg end &optional key)
247 "Sort sexps in region. 250 "Sort sexps in region.
248Comments stay with the code below." 251Comments stay with the code below. KEY is a function to sort by,
252e.g. (lambda (sexp) (symbol-name (car sexp)))"
249 (interactive "r") 253 (interactive "r")
250 (cl-flet ((skip-whitespace () (while (looking-at (rx (1+ (or space "\n")))) 254 (cl-flet ((skip-whitespace () (while (looking-at (rx (1+ (or space "\n"))))
251 (goto-char (match-end 0)))) 255 (goto-char (match-end 0))))
@@ -270,11 +274,16 @@ Comments stay with the code below."
270 for end = (point-marker) 274 for end = (point-marker)
271 while sexp 275 while sexp
272 ;; Collect the real string, then one used for sorting. 276 ;; Collect the real string, then one used for sorting.
273 collect (cons (buffer-substring (marker-position start) (marker-position end)) 277 collect (cons (buffer-substring (marker-position start)
278 (marker-position end))
274 (save-excursion 279 (save-excursion
275 (goto-char (marker-position start)) 280 (goto-char (marker-position start))
276 (skip-both) 281 (skip-both)
277 (buffer-substring (point) (marker-position end)))) 282 (if key
283 (funcall key sexp)
284 (buffer-substring
285 (point)
286 (marker-position end)))))
278 into sexps 287 into sexps
279 collect (cons start end) 288 collect (cons start end)
280 into markers 289 into markers