summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCase Duckworth2023-04-16 17:06:41 -0500
committerCase Duckworth2023-04-16 17:06:41 -0500
commit2d2cab9d97d3e84e5b7158181523fe2c5bbffe85 (patch)
tree0a433b8997d16db0a4115106bb1c9764e826c4c8
parentapsodfiuadsfoiudsfpaoidsufpaosidufposdifuapsodifuapsodifu (diff)
downloademacs-2d2cab9d97d3e84e5b7158181523fe2c5bbffe85.tar.gz
emacs-2d2cab9d97d3e84e5b7158181523fe2c5bbffe85.zip
uhhh
-rw-r--r--basics.el62
-rw-r--r--early-init.el12
-rw-r--r--history6
-rw-r--r--init.el554
-rw-r--r--lisp/+link-hint.el83
-rw-r--r--lisp/+scratch.el75
-rw-r--r--lisp/acdw-chat.el174
-rw-r--r--lisp/acdw-mail.el113
-rw-r--r--lisp/acdw-org.el77
-rw-r--r--lisp/acdw-web.el101
-rw-r--r--lisp/acdw.el45
-rw-r--r--lisp/ical2org.el56
-rw-r--r--places2
-rw-r--r--recentf17
14 files changed, 1117 insertions, 260 deletions
diff --git a/basics.el b/basics.el index 3905003..15831d3 100644 --- a/basics.el +++ b/basics.el
@@ -192,7 +192,7 @@
192 auto-save-interval 1 192 auto-save-interval 1
193 auto-save-no-message t 193 auto-save-no-message t
194 auto-save-timeout 1 194 auto-save-timeout 1
195 auto-save-visited-interval 1 195 auto-save-visited-interval 10
196 remote-file-name-inhibit-auto-save-visited t) 196 remote-file-name-inhibit-auto-save-visited t)
197(add-to-list 'auto-save-file-name-transforms 197(add-to-list 'auto-save-file-name-transforms
198 `(".*" ,(etc/ "auto-save/" t) t)) 198 `(".*" ,(etc/ "auto-save/" t) t))
@@ -208,7 +208,8 @@
208(setq-default ;; recentf-save-file (etc/ "recentf" t) 208(setq-default ;; recentf-save-file (etc/ "recentf" t)
209 recentf-max-menu-items 500 209 recentf-max-menu-items 500
210 recentf-max-saved-items nil ; Save the whole list 210 recentf-max-saved-items nil ; Save the whole list
211 recentf-auto-cleanup 'mode) 211 recentf-auto-cleanup 'mode
212 recentf-case-fold-search t)
212(add-to-list 'recentf-exclude etc/) 213(add-to-list 'recentf-exclude etc/)
213(add-to-list 'recentf-exclude "-autoloads.el\\'") 214(add-to-list 'recentf-exclude "-autoloads.el\\'")
214(add-hook 'buffer-list-update-hook #'recentf-track-opened-file) 215(add-hook 'buffer-list-update-hook #'recentf-track-opened-file)
@@ -309,13 +310,62 @@ current line."
309 (list (line-beginning-position) 310 (list (line-beginning-position)
310 (line-end-position)))))) 311 (line-end-position))))))
311 312
313(defun +kill-buffer (&optional buffer-or-name)
314 "Kill the current buffer, or BUFFER-OR-NAME.
315When called interactively, prompt the user when given a prefix
316argument."
317 (interactive "P")
318 (cond
319 ((bufferp buffer-or-name)
320 (kill-buffer buffer-or-name))
321 ((null buffer-or-name)
322 (kill-current-buffer))
323 (:else
324 (kill-buffer (read-buffer "Kill: " nil :require-match)))))
325
326(defun +backward-kill-word (arg)
327 "Kill ARG words backward unless at the beginning of a line.
328When at the beginning of a line, delete blank lines before point."
329 (interactive "p")
330 (cond
331 ((bolp)
332 ;; This is the first bit of `delete-blank-lines'. -- acdw
333 (let (thisblank singleblank)
334 (save-excursion
335 (beginning-of-line)
336 (setq thisblank (looking-at "[ \t]*$"))
337 ;; Set singleblank if there is just one blank line here.
338 (setq singleblank
339 (and thisblank
340 (not (looking-at "[ \t]*\n[ \t]*$"))
341 (or (bobp)
342 (progn (forward-line -1)
343 (not (looking-at "[ \t]*$")))))))
344 ;; Delete preceding blank lines, and this one too if it's the only one.
345 (if thisblank
346 (progn
347 (beginning-of-line)
348 (if singleblank (forward-line 1))
349 (delete-region (point)
350 (if (re-search-backward "[^ \t\n]" nil t)
351 (progn (forward-line 1) (point))
352 (point-min)))))
353 (if (or (not thisblank)
354 singleblank)
355 (progn
356 (beginning-of-line)
357 (backward-delete-char 1)))))
358 (:else
359 (backward-kill-word arg))))
360
312(global-set-key [remap eval-expression] #'pp-eval-expression) 361(global-set-key [remap eval-expression] #'pp-eval-expression)
313(global-set-key (kbd "M-o") #'other-window|switch-buffer) 362(global-set-key (kbd "M-o") #'other-window|switch-buffer)
314(global-set-key [remap delete-window] #'delete-window|bury-buffer) 363(global-set-key [remap delete-window] #'delete-window|bury-buffer)
315(global-set-key [remap cycle-spacing] #'+cycle-spacing) 364(global-set-key [remap cycle-spacing] #'+cycle-spacing)
316(global-set-key (kbd "C-x C-k") #'kill-this-buffer) 365(global-set-key (kbd "C-x C-k") #'+kill-buffer)
317(global-set-key [remap comment-dwim] #'+comment-dwim) 366(global-set-key [remap comment-dwim] #'+comment-dwim)
318(global-set-key [remap undo] #'undo-only) 367(global-set-key [remap undo] #'undo-only)
368(global-set-key [remap backward-kill-word] #'+backward-kill-word)
319 369
320(global-set-key [f10] #'tmm-menubar) 370(global-set-key [f10] #'tmm-menubar)
321(advice-add 'tmm-add-prompt :after 'minibuffer-hide-completions) 371(advice-add 'tmm-add-prompt :after 'minibuffer-hide-completions)
@@ -533,6 +583,12 @@ current line."
533 ;; :preview-key (kbd "M-.") 583 ;; :preview-key (kbd "M-.")
534 :preview-key '(:debounce 0.4 any)) 584 :preview-key '(:debounce 0.4 any))
535 585
586 ;; (consult-customize consult-line
587 ;; consult-ripgrep
588 ;; :initial (when (use-region-p)
589 ;; (buffer-substring-no-properties
590 ;; (region-beginning) (region-end))))
591
536 ;; Optionally configure the narrowing key. 592 ;; Optionally configure the narrowing key.
537 ;; Both < and C-+ work reasonably well. 593 ;; Both < and C-+ work reasonably well.
538 (setq consult-narrow-key "<") ;; (kbd "C-+") 594 (setq consult-narrow-key "<") ;; (kbd "C-+")
diff --git a/early-init.el b/early-init.el index e024b50..4b67629 100644 --- a/early-init.el +++ b/early-init.el
@@ -28,7 +28,9 @@
28(setq package-priorities '(("melpa" . 3) 28(setq package-priorities '(("melpa" . 3)
29 ("nongnu" . 2) 29 ("nongnu" . 2)
30 ("gnu" . 1) 30 ("gnu" . 1)
31 ("melpa-stable" . 0))) 31 ("melpa-stable" . 0))
32 package-enable-at-startup nil)
33
32(package-initialize) 34(package-initialize)
33(unless package-archive-contents 35(unless package-archive-contents
34 (package-refresh-contents)) 36 (package-refresh-contents))
@@ -36,9 +38,15 @@
36(setq use-package-enable-imenu-support t 38(setq use-package-enable-imenu-support t
37 use-package-hook-name-suffix nil) 39 use-package-hook-name-suffix nil)
38 40
39(require 'use-package) 41(eval-when-compile
42 (require 'use-package))
40(setq use-package-compute-statistics debug-on-error) 43(setq use-package-compute-statistics debug-on-error)
41 44
45(define-advice use-package (:before (name &rest body) select)
46 "Add NAME to `package-selected-packages'."
47 (when (memq :ensure body)
48 (add-to-list 'package-selected-packages name)))
49
42(use-package use-package-vc 50(use-package use-package-vc
43 :load-path "~/src/emacs/use-package-vc.el/" 51 :load-path "~/src/emacs/use-package-vc.el/"
44 :config 52 :config
diff --git a/history b/history new file mode 100644 index 0000000..4fc776d --- /dev/null +++ b/history
@@ -0,0 +1,6 @@
1;; -*- mode: emacs-lisp; coding: utf-8-unix -*-
2;; Minibuffer history file, automatically generated by ‘savehist’.
3
4(setq savehist-minibuffer-history-variables '(extended-command-history file-name-history))
5(setq extended-command-history '("undo"))
6(setq file-name-history '("~/etc/emacs/init.el"))
diff --git a/init.el b/init.el index c8fb4e7..d6363ea 100644 --- a/init.el +++ b/init.el
@@ -22,18 +22,39 @@
22(use-package emacs ; Misc. config 22(use-package emacs ; Misc. config
23 :config 23 :config
24 (setopt recenter-positions '(top middle bottom) 24 (setopt recenter-positions '(top middle bottom)
25 initial-scratch-message 25 initial-major-mode 'lisp-interaction-mode
26 (format "%s\n\n" 26 initial-scratch-message ";; Emacs!\n\n"
27 (mapconcat (lambda (s) (format ";; %s" s)) 27 ;; (format "%s\n\n"
28 (process-lines "fortune" "-s") 28 ;; (mapconcat (lambda (s) (format ";; %s" s))
29 "\n"))) 29 ;; (process-lines "fortune" "-s")
30 ;; "\n"))
31 eval-expression-print-level nil
32 eval-expression-print-length nil
33 x-select-enable-clipboard-manager nil)
34 ;; TODO: move this ... elsewhere
35 (setopt mode-line-format
36 '("%e"
37 mode-line-front-space
38 ;; (:propertize ("" mode-line-mule-info
39 ;; mode-line-client
40 ;; mode-line-modified
41 ;; mode-line-remote)
42 ;; display (min-width (5.0)))
43 ("" mode-line-mule-info
44 mode-line-client
45 mode-line-modified
46 mode-line-remote)
47 mode-line-frame-identification
48 mode-line-buffer-identification
49 " "
50 mode-line-position
51 (vc-mode vc-mode)
52 " "
53 minions-mode-line-modes
54 mode-line-misc-info
55 mode-line-end-spaces))
30 (keymap-global-unset "C-\\") 56 (keymap-global-unset "C-\\")
31 (keymap-global-unset "<f2>") 57 (keymap-global-unset "<f2>")
32 (add-hook 'kill-buffer-query-functions
33 (defun scratch@immortal ()
34 (if (equal (buffer-name) "*scratch*")
35 (progn (bury-buffer) nil)
36 t)))
37 (setf (alist-get "\\*Compile-Log\\*" display-buffer-alist nil nil #'equal) 58 (setf (alist-get "\\*Compile-Log\\*" display-buffer-alist nil nil #'equal)
38 '(display-buffer-no-window)) 59 '(display-buffer-no-window))
39 (add-hook 'after-init-hook 60 (add-hook 'after-init-hook
@@ -61,20 +82,28 @@
61 (defun first-frame@set-fonts () 82 (defun first-frame@set-fonts ()
62 (remove-hook 'server-after-make-frame-hook 83 (remove-hook 'server-after-make-frame-hook
63 #'first-frame@set-fonts) 84 #'first-frame@set-fonts)
64 (face-spec-set 'fixed-pitch
65 `((t :family ,(find-font "Comic Code"
66 "DejaVu Sans Mono")
67 :height 100)))
68 (face-spec-set 'variable-pitch
69 `((t :family ,(find-font "Atkinson Hyperlegible"
70 "DejaVu Serif")
71 :height 1.4)))
72 (face-spec-set 'default 85 (face-spec-set 'default
73 `((t :family ,(find-font "Comic Code" 86 `((t :family ,(find-font
74 "DejaVu Sans Mono") 87 "Recursive Mono Casual Static"
88 "Comic Code"
89 "DejaVu Sans Mono")
75 :height 100))) 90 :height 100)))
91 (face-spec-set 'fixed-pitch
92 `((t :family ,(find-font
93 "Recursive Mono Casual Static"
94 "Comic Code"
95 "DejaVu Sans Mono")
96 :height 1.0)))
97 (face-spec-set 'variable-pitch
98 `((t :family ,(find-font
99 "Recursive Sans Linear Static"
100 "Atkinson Hyperlegible"
101 "DejaVu Serif")
102 :height 1.0)))
76 (face-spec-set 'font-lock-comment-face 103 (face-spec-set 'font-lock-comment-face
77 `((t :slant italic))) 104 `((t :inherit variable-pitch)))
105 (face-spec-set 'font-lock-string-face
106 `((t :inherit variable-pitch)))
78 ;; Emojis 107 ;; Emojis
79 (cl-loop with ffl = (font-family-list) 108 (cl-loop with ffl = (font-family-list)
80 for font in '("Noto Emoji" "Noto Color Emoji" 109 for font in '("Noto Emoji" "Noto Color Emoji"
@@ -85,27 +114,28 @@
85 do (set-fontset-font t 'symbol font)) 114 do (set-fontset-font t 'symbol font))
86 ;; International scripts 115 ;; International scripts
87 (cl-loop with ffl = (font-family-list) 116 (cl-loop with ffl = (font-family-list)
88 for (charset . font) in '((latin . "Noto Sans") 117 for (charset . font)
89 (han . "Noto Sans CJK SC Regular") 118 in '((latin . "Noto Sans")
90 (kana . "Noto Sans CJK JP Regular") 119 (han . "Noto Sans CJK SC Regular")
91 (hangul . "Noto Sans CJK KR Regular") 120 (kana . "Noto Sans CJK JP Regular")
92 (cjk-misc . "Noto Sans CJK KR Regular") 121 (hangul . "Noto Sans CJK KR Regular")
93 (khmer . "Noto Sans Khmer") 122 (cjk-misc . "Noto Sans CJK KR Regular")
94 (lao . "Noto Sans Lao") 123 (khmer . "Noto Sans Khmer")
95 (burmese . "Noto Sans Myanmar") 124 (lao . "Noto Sans Lao")
96 (thai . "Noto Sans Thai") 125 (burmese . "Noto Sans Myanmar")
97 (ethiopic . "Noto Sans Ethiopic") 126 (thai . "Noto Sans Thai")
98 (hebrew . "Noto Sans Hebrew") 127 (ethiopic . "Noto Sans Ethiopic")
99 (arabic . "Noto Sans Arabic") 128 (hebrew . "Noto Sans Hebrew")
100 (gujarati . "Noto Sans Gujarati") 129 (arabic . "Noto Sans Arabic")
101 (devanagari . "Noto Sans Devanagari") 130 (gujarati . "Noto Sans Gujarati")
102 (kannada . "Noto Sans Kannada") 131 (devanagari . "Noto Sans Devanagari")
103 (malayalam . "Noto Sans Malayalam") 132 (kannada . "Noto Sans Kannada")
104 (oriya . "Noto Sans Oriya") 133 (malayalam . "Noto Sans Malayalam")
105 (sinhala . "Noto Sans Sinhala") 134 (oriya . "Noto Sans Oriya")
106 (tamil . "Noto Sans Tamil") 135 (sinhala . "Noto Sans Sinhala")
107 (telugu . "Noto Sans Telugu") 136 (tamil . "Noto Sans Tamil")
108 (tibetan . "Noto Sans Tibetan")) 137 (telugu . "Noto Sans Telugu")
138 (tibetan . "Noto Sans Tibetan"))
109 if (member font ffl) 139 if (member font ffl)
110 do (set-fontset-font t charset font)))) 140 do (set-fontset-font t charset font))))
111 (unless (daemonp) 141 (unless (daemonp)
@@ -142,14 +172,11 @@
142(use-package ispell 172(use-package ispell
143 :config 173 :config
144 (setopt ispell-program-name (choose-executable "aspell" "ispell")) 174 (setopt ispell-program-name (choose-executable "aspell" "ispell"))
145 (add-hook 'before-save-hook 175 ;; (add-hook 'before-save-hook
146 #'+ispell-move-buffer-words-to-dir-locals-hook) 176 ;; #'+ispell-move-buffer-words-to-dir-locals-hook)
147 (put 'ispell-buffer-session-localwords 'safe-local-variable 177 (put 'ispell-buffer-session-localwords 'safe-local-variable
148 '+ispell-safe-local-p)) 178 '+ispell-safe-local-p))
149 179
150(use-package flyspell
151 :hook org-mode-hook)
152
153(use-package dired 180(use-package dired
154 :bind (("C-x C-j" . dired-jump) 181 :bind (("C-x C-j" . dired-jump)
155 ([remap list-directory] . dired) 182 ([remap list-directory] . dired)
@@ -186,7 +213,16 @@
186 "localhost" 213 "localhost"
187 "dict.org")) 214 "dict.org"))
188 :bind 215 :bind
189 (("C-c d" . dictionary-search))) 216 (("C-c w d" . dictionary-search))
217 :config
218 (setf (alist-get "\\*Dictionary\\*" display-buffer-alist nil nil #'equal)
219 '(display-buffer-in-side-window
220 (window-width . 80)
221 (side . right))))
222
223(use-package calendar
224 :custom
225 (diary-file (private/ "diary")))
190 226
191(use-package mouse 227(use-package mouse
192 :config 228 :config
@@ -261,9 +297,12 @@
261 ;; https://www.masteringemacs.org/article/seamlessly-merge-multiple-documentation-sources-eldoc 297 ;; https://www.masteringemacs.org/article/seamlessly-merge-multiple-documentation-sources-eldoc
262 (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)) 298 (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly))
263 :hook 299 :hook
264 ((bash-ts-mode . eglot)) 300 ((bash-ts-mode . eglot-ensure)
301 (scheme-mode . eglot-ensure))
265 :config 302 :config
266 (add-hook 'eglot-managed-mode . +eglot-eldoc)) 303 (add-to-list 'eglot-server-programs
304 '(scheme-mode . ("chicken-lsp-server")))
305 (add-hook 'eglot-managed-mode #'+eglot-eldoc))
267 306
268(use-package eldoc 307(use-package eldoc
269 :config 308 :config
@@ -273,6 +312,76 @@
273 (window-height . 4))) 312 (window-height . 4)))
274 (eldoc-add-command-completions "paredit-")) 313 (eldoc-add-command-completions "paredit-"))
275 314
315(use-package pulse
316 :config
317 (setopt pulse-flag nil
318 pulse-delay 1
319 pulse-iterations 1))
320
321(use-package flyspell
322 :hook (org-mode-hook))
323
324(use-package display-fill-column-indicator
325 :hook (prog-mode-hook))
326
327(use-package package
328 :config
329 (defun package-update-async-in-progress (&rest _)
330 (message "Package async update in progress."))
331
332 (defun package-update-all-async ()
333 "Update packages asyncronously."
334 (interactive)
335 (let ((message "Package update (async)...")
336 (disable-fns '(package-update
337 package-update-all
338 package-update-all-async)))
339 (dolist (fn disable-fns)
340 (advice-add fn :override #'package-update-async-in-progress))
341 (message "%s" message)
342 (unwind-protect
343 (async-start
344 `(lambda ()
345 (package-initialize)
346 (package-update-all))
347 `(lambda (result)
348 (message "%s %s" ,message result)))
349 (dolist (fn ',disable-fns)
350 (advice-remove fn 'package-update-async-in-progress))))))
351
352(use-package ielm
353 ;; https://www.n16f.net/blog/making-ielm-more-comfortable/
354 :preface
355 (defun +ielm-init-history ()
356 (let ((path (etc/ "ielm/history" t)))
357 (setq-local comint-input-ring-file-name path))
358 (setq-local comint-input-ring-size 10000)
359 (setq-local comint-input-ignoredups t)
360 (ignore-errors (comint-read-input-ring)))
361 (defun +ielm-write-history (&rest _args)
362 (with-file-modes #o600
363 (comint-write-input-ring)))
364 (defun +ielm (&optional buf-name)
365 "Interactively evaluate Emacs Lisp expressions.
366Switches to the buffer named BUF-NAME if provided (`*ielm*' by default),
367or creates it if it does not exist.
368See `inferior-emacs-lisp-mode' for details."
369 (interactive)
370 (let (old-point
371 (buf-name (or buf-name "*ielm*")))
372 (unless (comint-check-proc buf-name)
373 (with-current-buffer (get-buffer-create buf-name)
374 (unless (zerop (buffer-size)) (setq old-point (point)))
375 (inferior-emacs-lisp-mode)))
376 (pop-to-buffer buf-name)
377 (when old-point (push-mark old-point))))
378 :bind (:map emacs-lisp-mode-map
379 ("C-c C-z" . +ielm))
380 :config
381 (add-hook 'ielm-mode-hook #'eldoc-mode)
382 (add-hook 'ielm-mode-hook #'+ielm-init-history)
383 (advice-add 'ielm-send-input :after #'+ielm-write-history))
384
276 385
277;;; Applications 386;;; Applications
278 387
@@ -282,7 +391,9 @@
282 :bind (("C-c n" . +notmuch-goto))) 391 :bind (("C-c n" . +notmuch-goto)))
283 392
284(use-package acdw-org 393(use-package acdw-org
285 :load-path "lisp/") 394 :load-path "lisp/"
395 :config
396 (global-set-key [f8] #'org-clock-out))
286 397
287(use-package acdw-shell 398(use-package acdw-shell
288 :load-path "lisp/") 399 :load-path "lisp/")
@@ -290,12 +401,33 @@
290(use-package acdw-web 401(use-package acdw-web
291 :load-path "lisp/") 402 :load-path "lisp/")
292 403
404(use-package acdw-chat
405 :load-path "lisp/")
406
293(use-package _work 407(use-package _work
294 :load-path "~/Sync/emacs/private/") 408 :load-path "~/sync/emacs/private/")
295 409
296 410
297;;; Locally-developed packages 411;;; Locally-developed packages
298 412
413(use-package +scratch
414 :load-path "lisp/"
415 :config
416 (setopt +scratch-save-dir (sync/ "emacs/scratch.d/" t))
417 (add-hook 'kill-buffer-query-functions #'+scratch@immortal)
418 (add-hook 'kill-emacs-hook #'+scratch-save-on-exit)
419 (with-current-buffer (get-scratch-buffer-create)
420 (local-set-key (kbd "C-x C-s") #'+scratch-save))
421 ;; Save *scratch* every hour
422 (run-at-time t (* 60 60) #'+scratch-save "%FT%H%z")
423 ;; Clean old *scratch* saves every day
424 (run-at-time t (* 60 60 24) #'+scratch-clean))
425
426(use-package pulse-location
427 :load-path "~/src/emacs/pulse-location/"
428 :config
429 (pulse-location-mode))
430
299(use-package dawn 431(use-package dawn
300 :load-path "~/src/emacs/dawn/" 432 :load-path "~/src/emacs/dawn/"
301 :after custom-allowed 433 :after custom-allowed
@@ -303,7 +435,41 @@
303 (add-hook 'custom-allowed-after-load-hook 435 (add-hook 'custom-allowed-after-load-hook
304 (defun dawn-modus () 436 (defun dawn-modus ()
305 (dawn-schedule-themes 'modus-operandi 437 (dawn-schedule-themes 'modus-operandi
306 'modus-vivendi)))) 438 'modus-vivendi)))
439 (setopt modus-themes-mixed-fonts t)
440 (load-theme 'modus-vivendi t)
441 (add-hook 'dawn-after-load-theme-hook
442 (defun +reset-faces ()
443 (dolist (face '(font-lock-regexp-face
444 font-lock-variable-name-face
445 font-lock-preprocessor-face
446 font-lock-remove-face
447 font-lock-delimiter-face
448 font-lock-label-face
449 font-lock-operator-face
450 font-lock-property-face
451 font-lock-builtin-face
452 font-lock-number-face
453 font-lock-set-face
454 font-lock-warning-face
455 font-lock-punctuation-face
456 font-lock-constant-face
457 font-lock-type-face
458 font-lock-function-name-face
459 font-lock-reference-face
460 font-lock-negation-char-face
461 font-lock-misc-punctuation-face
462 font-lock-escape-face
463 font-lock-bracket-face))
464 (face-spec-set face '((t :foreground unspecified
465 :background unspecified))))
466 (face-spec-set 'font-lock-keyword-face
467 '((t :foreground unspecified
468 :background unspecified
469 :weight bold)))
470 (face-spec-set 'font-lock-doc-face
471 '((t :slant italic)))))
472 (+reset-faces))
307 473
308(use-package electric-cursor 474(use-package electric-cursor
309 :load-path "~/src/emacs/electric-cursor/" 475 :load-path "~/src/emacs/electric-cursor/"
@@ -345,18 +511,13 @@ With prefix ARG, toggle the value of
345 (titlecase-region (progn (org-beginning-of-line) (point)) 511 (titlecase-region (progn (org-beginning-of-line) (point))
346 (progn (org-end-of-line) (point))))))) 512 (progn (org-end-of-line) (point)))))))
347 :config 513 :config
348 (keymap-set scule-map "M-t" #'titlecase-dwim)) 514 (with-eval-after-load 'scule
515 (keymap-set scule-map "M-t" #'titlecase-dwim)))
349 516
350(use-package scule 517(use-package scule
351 :load-path "~/src/emacs/scule/" 518 :load-path "~/src/emacs/scule/"
352 :config 519 :bind-keymap ("M-c" . scule-map)
353 (defvar-keymap scule-map 520 :init
354 :doc "Keymap to twiddle scules."
355 :repeat t ; TODO: doesn't work
356 "M-u" #'scule-upcase
357 "M-l" #'scule-downcase
358 "M-c" #'scule-capitalize)
359 (keymap-global-set "M-c" scule-map)
360 ;; Use M-u for prefix keys 521 ;; Use M-u for prefix keys
361 (keymap-global-set "M-u" #'universal-argument) 522 (keymap-global-set "M-u" #'universal-argument)
362 (keymap-set universal-argument-map "M-u" #'universal-argument-more)) 523 (keymap-set universal-argument-map "M-u" #'universal-argument-more))
@@ -372,111 +533,6 @@ With prefix ARG, toggle the value of
372 :config 533 :config
373 (global-frowny-mode)) 534 (global-frowny-mode))
374 535
375(use-package jabber
376 :load-path "~/src/emacs/jabber/"
377 :preface
378 (defvar jabber-prefix-width 10
379 "Width of jabber prompts and other prefixes.")
380 (defun jabber-ui-setup ()
381 "Setup the `jabber' user interface."
382 (visual-fill-column-mode)
383 (electric-pair-local-mode -1)
384 (auto-fill-mode -1)
385 (setq-local wrap-prefix (make-string (+ 3 jabber-prefix-width) #x20)
386 visual-fill-column-extra-text-width `(,(+ 3 jabber-prefix-width)
387 . 1)))
388 :custom-face
389 (jabber-activity-face ((t :inherit jabber-chat-prompt-foreign
390 :foreground unspecified
391 :weight normal)))
392 (jabber-activity-personal-face ((t :inherit jabber-chat-prompt-local
393 :foreground unspecified
394 :weight bold)))
395 (jabber-chat-prompt-local ((t :inherit font-lock-warning-face
396 :foreground unspecified)))
397 (jabber-chat-prompt-foreign ((t :inherit font-lock-constant-face
398 :foreground unspecified)))
399 (jabber-chat-prompt-system ((t :inherit font-lock-doc-face
400 :foreground unspecified)))
401 (jabber-rare-time-face ((t :inherit font-lock-comment-face
402 :foreground unspecified
403 :underline nil)))
404 :bind-keymap ("C-c j" . jabber-global-keymap)
405 :bind (("C-c C-SPC" . jabber-activity-switch-to))
406 :config
407 (setopt jabber-account-list '(("acdw@hmm.st"))
408 jabber-auto-reconnect t
409 jabber-last-read-marker (make-string (- fill-column 8) ?—)
410 jabber-muc-decorate-presence-patterns
411 '(("\\( enters the room ([^)]+)\\| has left the chatroom\\)$" . nil)
412 ("Mode #.*" . jabber-muc-presence-dim)
413 ("." . jabber-muc-presence-dim))
414 jabber-activity-make-strings #'jabber-activity-make-strings-shorten
415 jabber-rare-time-format " - - - - - - %H:%M %F"
416 jabber-muc-header-line-format
417 '(" " (:eval (replace-regexp-in-string "%" "%%"
418 (jabber-jid-displayname
419 jabber-group)))
420 " / " jabber-muc-topic)
421 ;; buffer name formats
422 jabber-chat-buffer-format "*xmpp* %n"
423 jabber-browse-buffer-format "*xmpp-browse* %n"
424 jabber-groupchat-buffer-format "*xmpp-muc* %n"
425 jabber-muc-private-buffer-format "*xmpp-muc-private* %n"
426 ;; "prompt" (speaker) formats
427 jabber-groupchat-prompt-format (format "%%>%dn | " jabber-prefix-width)
428 jabber-chat-local-prompt-format (format "%%>%dn | " jabber-prefix-width)
429 jabber-chat-foreign-prompt-format (format "%%>%dn | " jabber-prefix-width)
430 jabber-muc-private-foreign-prompt-format "\n%g/%n | ")
431 ;; jabber muc nick coloring
432 ;; wgreenhous | I found 1.5 ok for saturation and 2.0 for value (modus)
433 ;; (setopt jabber-muc-nick-value 1.0
434 ;; jabber-muc-nick-saturation 1.0
435 ;; jabber-muc-colorize-local t
436 ;; jabber-muc-colorize-foreign t)
437 ;; When changing the above values, make sure to
438 ;; (setq jabber-muc-participant-colors nil)
439 (add-hook 'jabber-chat-mode-hook #'jabber-ui-setup)
440 (keymap-global-set "C-x C-j" #'dired-jump) ; Extremely annoying fix
441 (require 'jabber-httpupload nil t)
442 (add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons)
443 (remove-hook 'jabber-alert-muc-hooks 'jabber-muc-echo)
444 (remove-hook 'jabber-alert-presence-hooks 'jabber-presence-echo)
445 (add-hook 'jabber-alert-muc-hooks
446 (defun jabber@highlight-acdw (&optional _ _ buf _ _)
447 (when buf
448 (with-current-buffer buf
449 (let ((regexp (rx word-boundary
450 "acdw" ; maybe get from the config?
451 word-boundary)))
452 (hi-lock-unface-buffer regexp)
453 (highlight-regexp regexp 'font-lock-warning-face))))))
454 (add-hook 'jabber-chat-mode-hook
455 (defun jabber-chat@leave-when-kill ()
456 (add-hook 'kill-buffer-hook
457 (defun @jabber-leave@kill ()
458 (ignore-errors
459 (apply #'jabber-muc-leave (jabber-muc-argument-list))))
460 nil :local)))
461 (when (fboundp 'jabber-chat-update-focus)
462 (add-hook 'window-configuration-change-hook #'jabber-chat-update-focus))
463 (with-eval-after-load 'consult
464 (defvar jabber-chat-buffer-source
465 `( :name "Jabber"
466 :hidden nil
467 :narrow ?j
468 :category buffer
469 :state ,#'consult--buffer-state
470 :items ,(lambda ()
471 (mapcar #'buffer-name
472 (seq-filter (lambda (buf)
473 (with-current-buffer buf
474 (eq major-mode 'jabber-chat-mode)))
475 (buffer-list))))))
476 (add-to-list 'consult-buffer-sources 'jabber-chat-buffer-source :append)
477 (consult-customize
478 consult-buffer :preview-key "M-.")))
479
480(use-package keepassxc-shim 536(use-package keepassxc-shim
481 :load-path "~/src/emacs/keepassxc-shim/" 537 :load-path "~/src/emacs/keepassxc-shim/"
482 :config 538 :config
@@ -502,7 +558,7 @@ With prefix ARG, toggle the value of
502 558
503(use-package form-feed 559(use-package form-feed
504 :ensure t 560 :ensure t
505 :hook (emacs-lisp-mode-hook)) 561 :hook (prog-mode-hook))
506 562
507(use-package clean-kill-ring 563(use-package clean-kill-ring
508 :vc (:url "https://github.com/NicholasBHubbard/clean-kill-ring.el") 564 :vc (:url "https://github.com/NicholasBHubbard/clean-kill-ring.el")
@@ -548,10 +604,11 @@ The prefix argument is as in `visual-fill-column-widen' but negated."
548 (visual-fill-column-adjust) 604 (visual-fill-column-adjust)
549 (message "Fill-column: %s" fill-column))) 605 (message "Fill-column: %s" fill-column)))
550 :ensure t 606 :ensure t
551 :init
552 (setopt visual-fill-column-center-text t
553 visual-fill-column-extra-text-width '(3 . 3))
554 :config 607 :config
608 (setopt visual-fill-column-center-text t
609 visual-fill-column-extra-text-width '(3 . 3)
610 visual-fill-column-width (+ fill-column 4))
611 (keymap-set toggle-map "v" #'visual-fill-column-mode)
555 (keymap-set visual-fill-column-mode-map "C-x C->" #'visual-fill-column-widen) 612 (keymap-set visual-fill-column-mode-map "C-x C->" #'visual-fill-column-widen)
556 (keymap-set visual-fill-column-mode-map "C-x C-<" #'visual-fill-column-narrow) 613 (keymap-set visual-fill-column-mode-map "C-x C-<" #'visual-fill-column-narrow)
557 (add-hook 'visual-fill-column-mode-hook #'visual-line-mode) 614 (add-hook 'visual-fill-column-mode-hook #'visual-line-mode)
@@ -590,12 +647,12 @@ The prefix argument is as in `visual-fill-column-widen' but negated."
590 647
591(use-package avy 648(use-package avy
592 :ensure t 649 :ensure t
593 :init
594 (setopt avy-background t
595 avy-keys (string-to-list "asdfghjklqwertyuiopzxcvbnm"))
596 :bind (("M-j" . avy-goto-char-timer) 650 :bind (("M-j" . avy-goto-char-timer)
597 :map isearch-mode-map 651 :map isearch-mode-map
598 ("M-j" . avy-isearch))) 652 ("M-j" . avy-isearch))
653 :config
654 (setopt avy-background t
655 avy-keys (string-to-list "asdfghjklqwertyuiopzxcvbnm")))
599 656
600(use-package zzz-to-char 657(use-package zzz-to-char
601 :ensure t 658 :ensure t
@@ -660,8 +717,9 @@ The prefix argument is as in `visual-fill-column-widen' but negated."
660 (call-interactively 717 (call-interactively
661 (if (derived-mode-p 'lisp-interaction-mode) 718 (if (derived-mode-p 'lisp-interaction-mode)
662 #'eval-print-last-sexp #'paredit-newline)))) 719 #'eval-print-last-sexp #'paredit-newline))))
663 (keymap-set paredit-mode-map "RET" nil) 720 (keymap-unset paredit-mode-map "RET" t)
664 (keymap-set paredit-mode-map "M-s" nil) 721 (keymap-unset paredit-mode-map "M-s" t)
722 (keymap-unset paredit-mode-map "M-r" t)
665 (add-to-list 'paredit-space-for-delimiter-predicates 723 (add-to-list 'paredit-space-for-delimiter-predicates
666 (defun paredit@dont-space-@ (endp delimiter) 724 (defun paredit@dont-space-@ (endp delimiter)
667 "Don't add a space after @ in `paredit-mode'." 725 "Don't add a space after @ in `paredit-mode'."
@@ -717,10 +775,9 @@ The prefix argument is as in `visual-fill-column-widen' but negated."
717 775
718(use-package sly 776(use-package sly
719 :ensure t 777 :ensure t
778 :when inferior-lisp-program
720 :preface 779 :preface
721 (setopt inferior-lisp-program (choose-executable "sbcl")) 780 (setopt inferior-lisp-program (choose-executable "sbcl"))
722 :when inferior-lisp-program
723 :init
724 (defun +sly-start-or-mrepl () 781 (defun +sly-start-or-mrepl ()
725 (interactive) 782 (interactive)
726 (if (ignore-errors (sly-connection)) 783 (if (ignore-errors (sly-connection))
@@ -754,7 +811,11 @@ The prefix argument is as in `visual-fill-column-widen' but negated."
754 "\\.erb\\'" 811 "\\.erb\\'"
755 "\\.mustache\\'" 812 "\\.mustache\\'"
756 "\\.djhtml\\'" 813 "\\.djhtml\\'"
757 "\\.html?\\'")) 814 "\\.html?\\'")
815 :config
816 (add-hook 'web-mode-hook
817 (defun web-mode@setup ()
818 (indent-tabs-mode -1))))
758 819
759(use-package nginx-mode 820(use-package nginx-mode
760 :ensure t 821 :ensure t
@@ -775,6 +836,7 @@ The prefix argument is as in `visual-fill-column-widen' but negated."
775 (pandoc-mode-hook . pandoc-load-default-settings))) 836 (pandoc-mode-hook . pandoc-load-default-settings)))
776 837
777(use-package edit-indirect 838(use-package edit-indirect
839 :ensure
778 :bind (("C-c '" . edit-indirect-region))) 840 :bind (("C-c '" . edit-indirect-region)))
779 841
780(use-package transpose-frame 842(use-package transpose-frame
@@ -842,9 +904,9 @@ With PREFIX, prompt to change the current dictionary."
842 (call-interactively #'ispell-change-dictionary))) 904 (call-interactively #'ispell-change-dictionary)))
843 (flyspell-correct-move (point-min) :forward :rapid)) 905 (flyspell-correct-move (point-min) :forward :rapid))
844 :after flyspell 906 :after flyspell
845 :bind (:map flyspell-mode-map 907 :bind (("<f7>" . +flyspell-correct-buffer)
846 ("C-;" . flyspell-correct-wrapper) 908 (:map flyspell-mode-map
847 ("<f7>" . +flyspell-correct-buffer)) 909 ("C-;" . flyspell-correct-wrapper)))
848 :config 910 :config
849 (setq flyspell-correct--cr-key ";") 911 (setq flyspell-correct--cr-key ";")
850 (keymap-unset flyspell-mode-map "C-," t) 912 (keymap-unset flyspell-mode-map "C-," t)
@@ -871,6 +933,10 @@ With PREFIX, prompt to change the current dictionary."
871 :config 933 :config
872 (setopt dgi-auto-hide-details-p nil)) 934 (setopt dgi-auto-hide-details-p nil))
873 935
936(use-package expand-region ; needed for embrace anyway
937 :ensure t
938 :bind (("C-=" . er/expand-region)))
939
874(use-package embrace 940(use-package embrace
875 :ensure t 941 :ensure t
876 :preface 942 :preface
@@ -961,10 +1027,25 @@ With PREFIX, prompt to change the current dictionary."
961;; (setq start (point))) 1027;; (setq start (point)))
962;; (scheme-send-region-and-go start end)))))) 1028;; (scheme-send-region-and-go start end))))))
963 1029
964(use-package geiser-guile ; Let's try using guile instead 1030(use-package geiser
965 :ensure t 1031 :ensure t
966 :config 1032 :config
967 (keymap-unset scheme-mode-map "M-o" t)) 1033 (use-package geiser-guile :ensure t)
1034 (use-package geiser-chicken :ensure t)
1035 (use-package geiser-chez :ensure t)
1036 (use-package geiser-gambit :ensure t)
1037 (use-package geiser-chibi :ensure t)
1038 (use-package macrostep-geiser
1039 :ensure t
1040 :config
1041 (eval-after-load 'geiser-mode
1042 '(add-hook 'geiser-mode-hook #'macrostep-geiser-setup))
1043 (eval-after-load 'geiser-repl
1044 '(add-hook 'geiser-repl-mode-hook #'macrostep-geiser-setup)))
1045 (with-eval-after-load 'geiser-mode
1046 (keymap-set geiser-mode-map "C-c C-k" #'geiser-eval-buffer-and-go)
1047 (keymap-unset geiser-mode-map "C-." t)
1048 (keymap-unset scheme-mode-map "M-o" t)))
968 1049
969(use-package treesit-auto 1050(use-package treesit-auto
970 ;; XXX: I don't really get the utility of this package, but I spent a ton of 1051 ;; XXX: I don't really get the utility of this package, but I spent a ton of
@@ -984,7 +1065,8 @@ With PREFIX, prompt to change the current dictionary."
984(use-package detached 1065(use-package detached
985 :when (executable-find "dtach") 1066 :when (executable-find "dtach")
986 :ensure t 1067 :ensure t
987 :init (detached-init) 1068 :init
1069 (add-hook 'after-init-hook #'detached-init)
988 :bind (([remap async-shell-command] . detached-shell-command) 1070 :bind (([remap async-shell-command] . detached-shell-command)
989 ([remap compile] . detached-compile) 1071 ([remap compile] . detached-compile)
990 ([remap recompile] . detached-compile-recompile)) 1072 ([remap recompile] . detached-compile-recompile))
@@ -992,3 +1074,103 @@ With PREFIX, prompt to change the current dictionary."
992 (setf detached-terminal-data-command system-type) 1074 (setf detached-terminal-data-command system-type)
993 (with-eval-after-load 'consult 1075 (with-eval-after-load 'consult
994 (global-set-key [remap detached-open-session] #'detached-consult-session))) 1076 (global-set-key [remap detached-open-session] #'detached-consult-session)))
1077
1078(use-package lin
1079 :ensure t
1080 :config
1081 (setopt lin-face 'lin-cyan
1082 lin-mode-hooks
1083 '(dired-mode-hook
1084 ;; bongo-mode-hook
1085 ;; elfeed-search-mode-hook
1086 git-rebase-mode-hook
1087 grep-mode-hook
1088 ibuffer-mode-hook
1089 ilist-mode-hook
1090 ;; ledger-report-mode-hook
1091 log-view-mode-hook
1092 magit-log-mode-hook
1093 ;; mu4e-headers-mode-hook
1094 notmuch-search-mode-hook
1095 notmuch-tree-mode-hook
1096 occur-mode-hook
1097 org-agenda-mode-hook
1098 pdf-outline-buffer-mode-hook
1099 proced-mode-hook
1100 tabulated-list-mode-hook))
1101 (lin-global-mode))
1102
1103(use-package gcmh
1104 :ensure t
1105 :config
1106 (setopt gcmh-idle-delay 'auto
1107 gcmh-verbose nil)
1108 (gcmh-mode))
1109
1110(use-package tmr
1111 :ensure t
1112 :preface
1113 (defun tmr-mode-line ()
1114 (if (seq-find (lambda (tmr)
1115 (not (tmr--timer-finishedp tmr)))
1116 tmr--timers)
1117 (propertize "⏲" 'face 'font-lock-warning-face)
1118 ""))
1119 (add-to-list 'global-mode-string
1120 '("" (:eval (tmr-mode-line)))
1121 'append))
1122
1123;; (use-package elfeed
1124;; :ensure t
1125;; :preface
1126;; ;; https://karthinks.com/software/lazy-elfeed/
1127;; (defun elfeed-scroll-up-command (&optional arg)
1128;; "Scroll up or go to next feed item in Elfeed"
1129;; (interactive "^P")
1130;; (let ((scroll-error-top-bottom nil))
1131;; (condition-case-unless-debug nil
1132;; (scroll-up-command arg)
1133;; (error (elfeed-show-next)))))
1134;; (defun elfeed-scroll-down-command (&optional arg)
1135;; "Scroll up or go to next feed item in Elfeed"
1136;; (interactive "^P")
1137;; (let ((scroll-error-top-bottom nil))
1138;; (condition-case-unless-debug nil
1139;; (scroll-down-command arg)
1140;; (error (elfeed-show-prev)))))
1141;; :bind (("C-c f" . elfeed))
1142;; :config
1143;; (setopt elfeed-enclosure-default-dir "~/var/download/"
1144;; elfeed-db-directory (sync/ "emacs/elfeed/db" t)
1145;; elfeed-curl-max-connections 4)
1146;; (add-hook 'elfeed-search-update-hook #'truncate-lines-local-mode)
1147;; (keymap-set elfeed-show-mode-map "SPC" #'elfeed-scroll-up-command)
1148;; (keymap-set elfeed-show-mode-map "S-SPC" #'elfeed-scroll-down-command)
1149;; (keymap-set elfeed-search-mode-map "a" #'elfeed-search-untag-all-unread)
1150;; (setq elfeed-feeds nil) ; Always reload the feed list from feeds.opml
1151;; (elfeed-load-opml "~/var/feeds.opml"))
1152
1153(use-package iedit ; XXX: is this necessary?
1154 :ensure t
1155 :init
1156 (customize-set-variable 'iedit-toggle-key-default (kbd "C-'")))
1157
1158(use-package dumb-jump
1159 :ensure t
1160 :hook ((xref-backend-functions . dumb-jump-xref-activate)))
1161
1162(use-package le-thesaurus
1163 :ensure t
1164 :bind (("C-c w s" . le-thesaurus-get-synonyms)
1165 ("C-c w a" . le-thesaurus-get-antonyms)))
1166
1167(use-package devdocs
1168 :ensure t
1169 ;; not sure what to bind anything to yet ... so M-x it is
1170 )
1171
1172(use-package comment-dwim-2
1173 :ensure t
1174 :bind (("M-;" . comment-dwim-2)
1175 :map org-mode-map
1176 ("M-;" . org-comment-dwim-2)))
diff --git a/lisp/+link-hint.el b/lisp/+link-hint.el index 469ed15..0e0b9b1 100644 --- a/lisp/+link-hint.el +++ b/lisp/+link-hint.el
@@ -87,33 +87,62 @@ with the KEYWORD."
87 +link-hint-open-secondary-types 87 +link-hint-open-secondary-types
88 :multiple t) 88 :multiple t)
89 89
90(defun +link-hint-open-secondary-setup (&optional types) 90(progn
91 "Define the `:open-secondary' link-hint type for TYPES. 91 (dolist
92If TYPES is nil, define it for `+link-hint-open-secondary-types'." 92 (type
93 (dolist (type (or types +link-hint-open-secondary-types)) 93 '(gnus-w3m-image-url gnus-w3m-url markdown-link mu4e-attachment mu4e-url notmuch-hello nov-link org-link shr-url text-url w3m-link w3m-message-link))
94 (link-hint-define-type type 94 (link-hint-define-type type :download
95 :open-secondary browse-url-secondary-browser-function 95 (function +browse-url-download)
96 :open-secondary-multiple t))) 96 :download-multiple t))
97 97 (defun +link-hint-open:download nil "Download a link to `eww-download-directory'.
98(defun +link-hint-open-secondary () 98
99 "Open a link in the secondary browser." 99Defined by `+link-hint-define'."
100 (interactive) 100 (interactive)
101 (avy-with link-hint-open-link 101 (avy-with link-hint-open-link
102 (link-hint--one :open-secondary))) 102 (link-hint--one :download)))
103 103 (defun +link-hint-open-multiple:download nil "Open multiple links with `+link-hint-open:download'.
104(defun +link-hint-open-chrome-setup (&optional types) 104
105 "Define the `:open-chrome' link-hint type for TYPES. 105Defined by `+link-hint-define'."
106If TYPES is nil, define it for `+link-hint-open-secondary-types'." 106 (avy-with link-hint-open-multiple-links
107 (dolist (type (or types +link-hint-open-secondary-types)) 107 (link-hint--multiple :download)))
108 (link-hint-define-type type 108 (defun +link-hint-open-all:download nil "Open all visible links with `+link-hint-open:download'.
109 :open-chrome #'browse-url-chrome 109
110 :open-chrome-multiple t))) 110Defined by `+link-hint-define'."
111 111 (avy-with link-hint-open-all-links
112(defun +link-hint-open-chrome () 112 (link-hint--all :download))))
113 "Open a link with chrome." 113
114 (interactive) 114;; (defun +link-hint-open-secondary-setup (&optional types)
115 (avy-with link-hint-open-link 115;; "Define the `:open-secondary' link-hint type for TYPES.
116 (link-hint--one :open-chrome))) 116;; If TYPES is nil, define it for `+link-hint-open-secondary-types'."
117;; (dolist (type (or types +link-hint-open-secondary-types))
118;; (link-hint-define-type type
119;; :open-secondary browse-url-secondary-browser-function
120;; :open-secondary-multiple t)))
121
122;; (defun +link-hint-open-secondary ()
123;; "Open a link in the secondary browser."
124;; (interactive)
125;; (avy-with link-hint-open-link
126;; (link-hint--one :open-secondary)))
127
128(+link-hint-define-keyword :chrome #'browse-url-chrome
129 "Open a link with `browse-url-chrome'."
130 +link-hint-open-secondary-types
131 :multiple t)
132
133;; (defun +link-hint-open-chrome-setup (&optional types)
134;; "Define the `:open-chrome' link-hint type for TYPES.
135;; If TYPES is nil, define it for `+link-hint-open-secondary-types'."
136;; (dolist (type (or types +link-hint-open-secondary-types))
137;; (link-hint-define-type type
138;; :open-chrome #'browse-url-chrome
139;; :open-chrome-multiple t)))
140
141;; (defun +link-hint-open-chrome ()
142;; "Open a link with chrome."
143;; (interactive)
144;; (avy-with link-hint-open-link
145;; (link-hint--one :open-chrome)))
117 146
118(defun +link-hint-open-link (prefix) 147(defun +link-hint-open-link (prefix)
119 "Open a link. 148 "Open a link.
diff --git a/lisp/+scratch.el b/lisp/+scratch.el new file mode 100644 index 0000000..5d749c6 --- /dev/null +++ b/lisp/+scratch.el
@@ -0,0 +1,75 @@
1;;; +scratch.el --- *scratch* improvements -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2023 Case Duckworth
4
5;; Author: Case Duckworth <case@acdw.net>
6;; Keywords: convenience
7
8;; This program is free software; you can redistribute it and/or modify
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation, either version 3 of the License, or
11;; (at your option) any later version.
12
13;; This program is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;; GNU General Public License for more details.
17
18;; You should have received a copy of the GNU General Public License
19;; along with this program. If not, see <https://www.gnu.org/licenses/>.
20
21;;; Commentary:
22
23;;
24
25;;; Code:
26
27(defcustom +scratch-save-dir (locate-user-emacs-file "scratch.d")
28 "Where to save scratch files."
29 :type 'file)
30
31(defcustom +scratch-max-age (* 60 60 24 365)
32 "Maximum age of a saved scratch buffer. Default: one year."
33 :type 'natnum)
34
35(defun +scratch@immortal ()
36 "Don't kill *scratch* with `kill-buffer'."
37 (if (equal (buffer-name) "*scratch*")
38 (progn (bury-buffer) nil)
39 t))
40
41(defun +scratch-save (time-format)
42 "Save *scratch* buffer to `+scratch-save-dir'.
43TIME-FORMAT will be used to name the buffer."
44 (interactive (list "%FT%H%z"))
45 (with-current-buffer (get-scratch-buffer-create)
46 (let ((buffer-file-name (expand-file-name (format "%s.%s"
47 (format-time-string
48 time-format)
49 (pcase major-mode
50 ('org-mode "org")
51 ('emacs-lisp-mode "el")
52 (_ "txt")))
53 +scratch-save-dir)))
54 (unless (string-equal (buffer-substring (point-min) (point-max))
55 initial-scratch-message)
56 (save-buffer 0)))))
57
58(defun +scratch-save-on-exit ()
59 (+scratch-save "%FT%T%z")
60 (+scratch-clean))
61
62(defun +scratch-clean ()
63 "Clean up saved scratches.
64Scratch files older than `+scratch-max-age' will be removed."
65 (dolist (f (directory-files +scratch-save-dir))
66 (when (and (not (equal f "."))
67 (not (equal f ".."))
68 (> (time-convert (file-attribute-modification-time
69 (file-attributes f))
70 'integer)
71 +scratch-max-age))
72 (delete-file (expand-file-name f +scratch-save-dir) :trash))))
73
74(provide '+scratch)
75;;; +scratch.el ends here
diff --git a/lisp/acdw-chat.el b/lisp/acdw-chat.el new file mode 100644 index 0000000..62dcf72 --- /dev/null +++ b/lisp/acdw-chat.el
@@ -0,0 +1,174 @@
1;;; acdw-chat.el --- Chat applications (mostly jabber) -*- lexical-binding: t; -*-
2
3;;; Code:
4
5(defcustom jabber-prefix-width 10
6 "Width of jabber prompts and other prefixes."
7 :type 'number
8 :group 'jabber)
9
10(defun jabber-ui-setup ()
11 "Setup the `jabber' user interface."
12 (visual-fill-column-mode)
13 (electric-pair-local-mode -1)
14 (auto-fill-mode -1)
15 (setq-local wrap-prefix (make-string (+ 3 jabber-prefix-width) #x20)
16 visual-fill-column-extra-text-width `(,(+ 3 jabber-prefix-width)
17 . 1)))
18
19(defcustom jabber-biboumi-server "localhost"
20 "Biboumi server for `jabber-biboumi-muc-connect'."
21 :type 'string
22 :group 'jabber)
23
24(defcustom jabber-biboumi-irc-servers '("irc.libera.chat")
25 "IRC servers for the user to choose from with `jabber-biboumi-muc-connect'."
26 :type '(repeat string)
27 :group 'jabber)
28
29(defcustom jabber-biboumi-default-nick ""
30 "Default nick for biboumi rooms."
31 :type 'string
32 :group 'jabber)
33
34(defun jabber-biboumi-muc-connect (channel server nick &optional biboumi-server)
35 "Connect to a biboumi (IRC gateway) server MUC.
36CHANNEL, SERVER, NICK, and BIBOUMI-SERVER are passed to
37`jabber-muc-join'. If BIBOUMI-SERVER isn't given,
38`jabber-biboumi-server' is used."
39 (interactive (list (concat "#" (string-remove-prefix "#" (read-string
40 "Channel: ")))
41 (completing-read "Server: " jabber-biboumi-irc-servers)
42 (read-string (format "Nick [%s]: "
43 jabber-biboumi-default-nick)
44 nil nil jabber-biboumi-default-nick)))
45 (let ((room (format "%s%%%s@%s" channel server (or biboumi-server
46 jabber-biboumi-server))))
47 (if (assoc room *jabber-active-groupchats*)
48 (switch-to-buffer (jabber-muc-get-buffer room))
49 (jabber-muc-join (jabber-read-account)
50 room
51 nick
52 'popup))))
53
54(defun jabber-group-yank-join-url ()
55 "Yank a url for joining the focused group."
56 (interactive)
57 (let ((s (format "xmpp:%s?join" jabber-group)))
58 (kill-new s)
59 (message s)))
60
61
62;;; Packages
63
64(use-package jabber
65 :load-path "~/src/emacs/jabber/"
66 :custom-face
67 (jabber-activity-face ((t :inherit jabber-chat-prompt-foreign
68 :foreground unspecified
69 :weight normal)))
70 (jabber-activity-personal-face ((t :inherit jabber-chat-prompt-local
71 :foreground unspecified
72 :weight bold)))
73 (jabber-chat-prompt-local ((t :inherit minibuffer-prompt
74 :foreground unspecified
75 :weight normal
76 :slant italic)))
77 (jabber-chat-prompt-foreign ((t :inherit warning
78 :foreground unspecified
79 :weight normal)))
80 (jabber-chat-prompt-system ((t :inherit font-lock-doc-face
81 :foreground unspecified)))
82 (jabber-rare-time-face ((t :inherit font-lock-comment-face
83 :foreground unspecified
84 :underline nil)))
85 :bind-keymap ("C-c j" . jabber-global-keymap)
86 :bind (("C-c C-SPC" . jabber-activity-switch-to))
87 :config
88 (setopt jabber-account-list '(("acdw@hmm.st"))
89 jabber-auto-reconnect t
90 jabber-biboumi-server "irc.hmm.st"
91 jabber-biboumi-irc-servers '("irc.libera.chat"
92 "irc.tilde.chat"
93 "tilde.town"
94 "m455.casa"
95 "irc.twitch.tv")
96 jabber-biboumi-default-nick "acdw"
97 jabber-last-read-marker (make-string fill-column ?.)
98 jabber-muc-decorate-presence-patterns
99 '(("\\( enters the room ([^)]+)\\| has left the chatroom\\)$" . nil)
100 ("Mode #.*" . jabber-muc-presence-dim)
101 ("." . jabber-muc-presence-dim))
102 jabber-activity-make-strings #'jabber-activity-make-strings-shorten
103 jabber-rare-time-format " - - - - - - %H:%M %F"
104 jabber-muc-header-line-format
105 '(" " (:eval (replace-regexp-in-string "%" "%%"
106 (jabber-jid-displayname
107 jabber-group)))
108 " / " jabber-muc-topic)
109 ;; buffer name formats
110 jabber-chat-buffer-format "*xmpp* %n"
111 jabber-browse-buffer-format "*xmpp-browse* %n"
112 jabber-groupchat-buffer-format "*xmpp-muc* %n"
113 jabber-muc-private-buffer-format "*xmpp-muc-private* %n"
114 ;; "prompt" (speaker) formats
115 jabber-groupchat-prompt-format (format "%%>%dn . " jabber-prefix-width)
116 jabber-chat-local-prompt-format (format "%%>%dn . " jabber-prefix-width)
117 jabber-chat-foreign-prompt-format (format "%%>%dn . " jabber-prefix-width)
118 jabber-muc-private-foreign-prompt-format "\n%g/%n . ")
119 ;; jabber muc nick coloring
120 ;; wgreenhous | I found 1.5 ok for saturation and 2.0 for value (modus)
121 ;; (setopt jabber-muc-nick-value 1.0
122 ;; jabber-muc-nick-saturation 1.0
123 ;; jabber-muc-colorize-local t
124 ;; jabber-muc-colorize-foreign t)
125 ;; When changing the above values, make sure to
126 ;; (setq jabber-muc-participant-colors nil)
127 (add-hook 'jabber-chat-mode-hook #'jabber-ui-setup)
128 (keymap-global-set "C-x C-j" #'dired-jump) ; Extremely annoying fix
129 ;; For each binding in `jabber-global-keymap', also bind the non-control
130 ;; character (lowercase)
131 (map-keymap (lambda (key command)
132 (define-key jabber-global-keymap (vector (+ key #x60)) command))
133 jabber-global-keymap)
134 (require 'jabber-httpupload nil t)
135 (add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons)
136 (remove-hook 'jabber-alert-muc-hooks 'jabber-muc-echo)
137 (remove-hook 'jabber-alert-presence-hooks 'jabber-presence-echo)
138 (add-hook 'jabber-alert-muc-hooks
139 (defun jabber@highlight-acdw (&optional _ _ buf _ _)
140 (when buf
141 (with-current-buffer buf
142 (let ((regexp (rx word-boundary
143 "acdw" ; maybe get from the config?
144 word-boundary)))
145 (hi-lock-unface-buffer regexp)
146 (highlight-regexp regexp 'jabber-chat-prompt-local))))))
147 (add-hook 'jabber-chat-mode-hook
148 (defun jabber-chat@leave-when-kill ()
149 (add-hook 'kill-buffer-hook
150 (defun @jabber-leave@kill ()
151 (ignore-errors
152 (apply #'jabber-muc-leave (jabber-muc-argument-list))))
153 nil :local)))
154 (when (fboundp 'jabber-chat-update-focus)
155 (add-hook 'window-configuration-change-hook #'jabber-chat-update-focus))
156 (with-eval-after-load 'consult
157 (defvar jabber-chat-buffer-source
158 `( :name "Jabber"
159 :hidden nil
160 :narrow ?j
161 :category buffer
162 :state ,#'consult--buffer-state
163 :items ,(lambda ()
164 (mapcar #'buffer-name
165 (seq-filter (lambda (buf)
166 (with-current-buffer buf
167 (eq major-mode 'jabber-chat-mode)))
168 (buffer-list))))))
169 (add-to-list 'consult-buffer-sources 'jabber-chat-buffer-source :append)
170 (consult-customize
171 consult-buffer :preview-key "M-.")))
172
173(provide 'acdw-chat)
174;;; acdw-chat.el ends here
diff --git a/lisp/acdw-mail.el b/lisp/acdw-mail.el index 2a7d128..f8111e7 100644 --- a/lisp/acdw-mail.el +++ b/lisp/acdw-mail.el
@@ -25,6 +25,10 @@
25(defun +message-send-set-variables () 25(defun +message-send-set-variables ()
26 "Set variables for `message-send' depending on the From: header. 26 "Set variables for `message-send' depending on the From: header.
27Useful in `message-send-hook'." 27Useful in `message-send-hook'."
28 (unless +message-send-dispatch-rules
29 (load notmuch-init-file)
30 (or +message-send-dispatch-rules
31 (error "`+message-send-dispatch-rules' isn't set!")))
28 (let ((from (message-fetch-field "from"))) 32 (let ((from (message-fetch-field "from")))
29 (cl-loop for (var . val) in (cl-loop for (address . bindings) 33 (cl-loop for (var . val) in (cl-loop for (address . bindings)
30 in +message-send-dispatch-rules 34 in +message-send-dispatch-rules
@@ -145,6 +149,112 @@ the saved search as well."
145 ;;(user-error "Feature `async' not found!") 149 ;;(user-error "Feature `async' not found!")
146 (notmuch-poll))) 150 (notmuch-poll)))
147 151
152;;; https://kitchingroup.cheme.cmu.edu/blog/2015/09/04/Checking-for-email-attachments-before-you-send-email/
153
154(defun email-says-attach-p ()
155 "Return t if email suggests there could be an attachment."
156 (save-excursion
157 (goto-char (point-min))
158 (re-search-forward "attach" nil t)))
159
160(defun email-has-attachment-p ()
161 "Return t if the currently open email has an attachment."
162 (save-excursion
163 (goto-char (point-min))
164 (re-search-forward "<#part" nil t)))
165
166(defun email-pre-send-check-attachment ()
167 (when (and (email-says-attach-p)
168 (not (email-has-attachment-p)))
169 (unless
170 (y-or-n-p
171 "Your email suggests an attachment, but none was found. Send anyway?")
172 (error "No attachment. Aborting send."))))
173
174;;; Process ical attachments
175
176(defun notmuch-save-ics ()
177 "Save a .ics file in a message."
178 (interactive)
179 (with-current-notmuch-show-message
180 (notmuch-foreach-mime-part
181 (lambda (part)
182 (message "%S" part)
183 (when (and (listp part)
184 (or (equal "application/ics" (caadr part))
185 ;; (equal "text/calendar" (caadr part))
186 ))
187 (save-window-excursion
188 (let* ((filename "/tmp/notmuch.ics")
189 (buf (find-file-noselect filename)))
190 (delete-file filename)
191 (kill-buffer (get-file-buffer filename))
192 (mm-save-part-to-file part filename)
193 (icalendar-import-file filename diary-file)
194 (kill-buffer buf)))))
195 (mm-dissect-buffer t t))))
196
197
198;;; Fixes
199
200;; https://nmbug.notmuchmail.org/nmweb/show/87bklhricc.fsf%40tethera.net
201
202(defun notmuch--indent-rigidly (start end count)
203 (cond
204 ((zerop count) t)
205 ((< count 0) (indent-rigidly start end count))
206 (t
207 (save-excursion
208 (let ((startpt (progn (goto-char start) (line-beginning-position)))
209 (endpt (progn (goto-char end) (line-end-position)))
210 (spaces (spaces-string count)))
211 (goto-char startpt)
212 (while
213 (progn
214 (insert spaces)
215 (cl-incf endpt count)
216 (and (zerop (forward-line 1)) (bolp)
217 (<= (point) endpt)))))))))
218
219(with-eval-after-load 'notmuch-show
220 ;; Redefine `notmuch-show-lazy-part' --- XXX: this is the most braindead way
221 ;; of doing this
222 (defun notmuch-show-lazy-part (part-args button)
223 ;; Insert the lazy part after the button for the part. We would just
224 ;; move to the start of the new line following the button and insert
225 ;; the part but that point might have text properties (eg colours
226 ;; from a message header etc) so instead we start from the last
227 ;; character of the button by adding a newline and finish by
228 ;; removing the extra newline from the end of the part.
229 (save-excursion
230 (goto-char (button-end button))
231 (insert "\n")
232 (let* ((inhibit-read-only t)
233 ;; We need to use markers for the start and end of the part
234 ;; because the part insertion functions do not guarantee
235 ;; to leave point at the end of the part.
236 (part-beg (copy-marker (point) nil))
237 (part-end (copy-marker (point) t))
238 ;; We have to save the depth as we can't find the depth
239 ;; when narrowed.
240 (depth (notmuch-show-get-depth)))
241 (save-restriction
242 (narrow-to-region part-beg part-end)
243 (delete-region part-beg part-end)
244 (apply #'notmuch-show-insert-bodypart-internal part-args)
245 (notmuch--indent-rigidly part-beg
246 part-end
247 (* notmuch-show-indent-messages-width depth)))
248 (goto-char part-end)
249 (delete-char 1)
250 (notmuch-show-record-part-information (cadr part-args)
251 (button-start button)
252 part-end)
253 ;; Create the overlay. If the lazy-part turned out to be empty/not
254 ;; showable this returns nil.
255 (notmuch-show-create-part-overlays button part-beg part-end))))
256 )
257
148 258
149;;; Packages 259;;; Packages
150 260
@@ -173,7 +283,6 @@ the saved search as well."
173 :preface (defdir notmuch/ (sync/ "emacs/notmuch/") 283 :preface (defdir notmuch/ (sync/ "emacs/notmuch/")
174 "Notmuch configuration directory." 284 "Notmuch configuration directory."
175 :makedir) 285 :makedir)
176 :bind (("C-c m" . notmuch-mua-new-mail))
177 :config 286 :config
178 ;; Options 287 ;; Options
179 (setopt notmuch-init-file (notmuch/ "notmuch-init.el" t) 288 (setopt notmuch-init-file (notmuch/ "notmuch-init.el" t)
@@ -196,6 +305,7 @@ the saved search as well."
196 notmuch-saved-searches nil 305 notmuch-saved-searches nil
197 notmuch-poll-script "~/usr/scripts/syncmail" ; XXX: Deprecated option 306 notmuch-poll-script "~/usr/scripts/syncmail" ; XXX: Deprecated option
198 ) 307 )
308 (load notmuch-init-file)
199 ;; Key bindings 309 ;; Key bindings
200 (keymap-set notmuch-search-mode-map "!" #'+notmuch-search-mark-spam) 310 (keymap-set notmuch-search-mode-map "!" #'+notmuch-search-mark-spam)
201 (keymap-set notmuch-search-mode-map "RET" #'notmuch-search-show-thread) 311 (keymap-set notmuch-search-mode-map "RET" #'notmuch-search-show-thread)
@@ -221,6 +331,7 @@ the saved search as well."
221 (+notmuch-define-saved-search "all mail" "a" 'tree "*") 331 (+notmuch-define-saved-search "all mail" "a" 'tree "*")
222 ;; Hooks and advice 332 ;; Hooks and advice
223 (add-hook 'message-send-hook #'+message-send-set-variables) 333 (add-hook 'message-send-hook #'+message-send-set-variables)
334 (add-hook 'message-send-hook #'email-pre-send-check-attachment)
224 (add-hook 'message-setup-hook #'+message-signature-setup) 335 (add-hook 'message-setup-hook #'+message-signature-setup)
225 (autoload 'visual-fill-column-mode "visual-fill-column" nil t) 336 (autoload 'visual-fill-column-mode "visual-fill-column" nil t)
226 (add-hook 'notmuch-message-mode-hook #'visual-fill-column-mode) 337 (add-hook 'notmuch-message-mode-hook #'visual-fill-column-mode)
diff --git a/lisp/acdw-org.el b/lisp/acdw-org.el index 566deed..f961dda 100644 --- a/lisp/acdw-org.el +++ b/lisp/acdw-org.el
@@ -203,6 +203,16 @@ If LIST is non-nil, return the result as a list instead of a string."
203 (when (org-at-heading-p) (org-align-tags)))))) 203 (when (org-at-heading-p) (org-align-tags))))))
204 204
205 205
206;;; Misc.
207
208(defun org-clock-in-or-out (prefix)
209 "If clocked in, clock out. Otherwise, clock in."
210 (interactive "P")
211 (if (org-clocking-p)
212 (org-clock-out prefix)
213 (org-clock-in prefix)))
214
215
206;;; Faces 216;;; Faces
207 217
208(defface org-bold '((t (:weight bold))) 218(defface org-bold '((t (:weight bold)))
@@ -225,10 +235,12 @@ If LIST is non-nil, return the result as a list instead of a string."
225 :custom-face 235 :custom-face
226 (org-level-1 ((t :inherit fixed-pitch 236 (org-level-1 ((t :inherit fixed-pitch
227 :weight bold 237 :weight bold
228 :height 1.2))) 238 :slant italic
239 :height 1.0)))
229 (org-level-2 ((t :inherit fixed-pitch 240 (org-level-2 ((t :inherit fixed-pitch
230 :weight bold 241 :weight bold
231 :height 1.1))) 242 :slant italic
243 :height 1.0)))
232 (org-level-3 ((t :inherit fixed-pitch 244 (org-level-3 ((t :inherit fixed-pitch
233 :weight bold 245 :weight bold
234 :height 1.0))) 246 :height 1.0)))
@@ -299,17 +311,20 @@ If LIST is non-nil, return the result as a list instead of a string."
299 (sequence "|" "CANCELED(k@)") 311 (sequence "|" "CANCELED(k@)")
300 (sequence "MEETING(m)")) 312 (sequence "MEETING(m)"))
301 org-use-fast-todo-selection 'auto 313 org-use-fast-todo-selection 'auto
302 org-use-speed-commands t) 314 org-use-speed-commands t
315 org-element-use-cache nil)
303 ;; Keys 316 ;; Keys
304 (keymap-set org-mode-map "C-M-k" #'kill-paragraph) 317 (keymap-set org-mode-map "C-M-k" #'kill-paragraph)
305 (keymap-set org-mode-map "C-M-t" #'transpose-paragraphs) 318 (keymap-set org-mode-map "C-M-t" #'transpose-paragraphs)
306 (keymap-set org-mode-map "RET" #'+org-return-dwim) 319 (keymap-set org-mode-map "RET" #'+org-return-dwim)
307 (keymap-set org-mode-map "S-<return>" #'+org-table-copy-down|+org-return-dwim) 320 (keymap-set org-mode-map "S-<return>" #'+org-table-copy-down|+org-return-dwim)
321 (keymap-unset org-mode-map "C-'" t)
322 (keymap-unset org-mode-map "C-," t)
308 ;; Hooks 323 ;; Hooks
309 (add-hook 'org-mode-hook 324 (add-hook 'org-mode-hook
310 (defun org-mode@setup () 325 (defun org-mode@setup ()
311 (when (require 'visual-fill-column nil t) 326 (when (require 'visual-fill-column nil t)
312 (setq-local visual-fill-column-extra-text-width '(8 . 8)) 327 (setq-local visual-fill-column-extra-text-width '(2 . 2))
313 (visual-fill-column-mode)) 328 (visual-fill-column-mode))
314 (variable-pitch-mode) 329 (variable-pitch-mode)
315 (turn-off-auto-fill) 330 (turn-off-auto-fill)
@@ -325,19 +340,17 @@ If LIST is non-nil, return the result as a list instead of a string."
325 'org-mode 340 'org-mode
326 `(;; List markers => org-indent 341 `(;; List markers => org-indent
327 (,(concat 342 (,(concat
328 "^[ ]*\\(\\(?:[-+]\\|\\(?:[0-9]+\\|[A-Za-z]\\)[.)]\\)" 343 "^[ ]*\\(\\(?:[-+]\\|\\(?:[0-9]+\\|[A-Za-z]\\)[.)]\\)"
329 "\\(?:[ ]+\\|$\\)\\)" 344 "\\(?:[ ]+\\|$\\)\\)"
330 "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\]" 345 "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\]"
331 "[ ]*\\)?" 346 "[ ]*\\)?"
332 "\\(?:\\(\\[[ X-]\\]\\)" 347 "\\(?:\\(\\[[ X-]\\]\\)"
333 "\\(?:[ ]+\\|$\\)\\)?") 348 "\\(?:[ ]+\\|$\\)\\)?")
334 0 'org-indent)))) 349 0 'org-indent))))
335 350
336(use-package org-clock 351(use-package org-clock
337 :bind (("M-<f9>" . org-clock-out) 352 :bind (:map org-mode-map
338 :map org-mode-map 353 ("<f8>" . org-clock-in-or-out))
339 ("<f8>" . org-clock-in)
340 ("<f9>" . org-clock-out))
341 :config 354 :config
342 (setopt org-clock-clocked-in-display 'mode-line 355 (setopt org-clock-clocked-in-display 'mode-line
343 global-mode-string 356 global-mode-string
@@ -355,13 +368,11 @@ If LIST is non-nil, return the result as a list instead of a string."
355 org-agenda-skip-scheduled-if-done t 368 org-agenda-skip-scheduled-if-done t
356 org-agenda-span 10 369 org-agenda-span 10
357 org-agenda-block-separator ?─ 370 org-agenda-block-separator ?─
358 org-agenda-time-grid 371 org-agenda-time-grid '((daily today require-timed)
359 '((daily today require-timed) 372 (800 1000 1200 1400 1600 1800 2000)
360 (800 1000 1200 1400 1600 1800 2000) 373 " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
361 " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄") 374 org-agenda-current-time-string "← now ───────────────"
362 org-agenda-current-time-string 375 org-agenda-include-diary t ; I use the org-diary features
363 "← now ─────────────────────────────────────────────────"
364 org-agenda-include-diary nil ; I use the org-diary features
365 org-agenda-todo-ignore-deadlines 'near 376 org-agenda-todo-ignore-deadlines 'near
366 org-agenda-todo-ignore-scheduled 'future 377 org-agenda-todo-ignore-scheduled 'future
367 org-agenda-include-deadlines t 378 org-agenda-include-deadlines t
@@ -371,7 +382,29 @@ If LIST is non-nil, return the result as a list instead of a string."
371 org-agenda-skip-file-regexp "sync-conflict" 382 org-agenda-skip-file-regexp "sync-conflict"
372 org-agenda-inhibit-startup t 383 org-agenda-inhibit-startup t
373 org-agenda-sticky t 384 org-agenda-sticky t
374 org-agenda-follow-indirect t) 385 org-agenda-follow-indirect t
386 org-stuck-projects '("TODO=\"WAIT\""
387 ("TODO" "NEXT")
388 nil
389 "")
390 org-agenda-custom-commands
391 `(("c" "Click Here Digital To-do"
392 ((agenda "" ((org-agenda-overriding-header "Tasks")
393 (org-agenda-span 'fortnight)
394 (org-agenda-start-day "+0")
395 (org-agenda-skip-function
396 '(org-agenda-skip-subtree-if 'todo
397 '("WAIT" "MCKENZIE" "RACHEL")))))
398 (stuck "" ((org-agenda-overriding-header "Waiting"))))
399 ((org-agenda-files ',(list (progn (require 'chd)
400 (chd/ "inbox-chd.org"))))))))
401 ;; Speedup agenda generation
402 ;; https://orgmode.org/manual/Speeding-Up-Your-Agendas.html
403 ;; https://orgmode.org/worg/agenda-optimization.html
404 (setopt org-agenda-dim-blocked-tasks nil
405 org-agenda-inhibit-startup t
406 org-agenda-use-tag-inheritance nil
407 org-agenda-ignore-properties '(effort appt stats category))
375 ;; Hooks and advice 408 ;; Hooks and advice
376 (add-hook 'org-agenda-mode-hook #'truncate-lines-local-mode) 409 (add-hook 'org-agenda-mode-hook #'truncate-lines-local-mode)
377 (add-hook 'org-agenda-mode-hook #'hl-line-mode) 410 (add-hook 'org-agenda-mode-hook #'hl-line-mode)
@@ -440,6 +473,7 @@ effect for exporting link types)."
440 :custom-face 473 :custom-face
441 (org-modern-label ((t :inherit fixed-pitch 474 (org-modern-label ((t :inherit fixed-pitch
442 :height 1.0))) 475 :height 1.0)))
476 :hook (org-mode-hook)
443 :config 477 :config
444 (setopt org-modern-star nil 478 (setopt org-modern-star nil
445 org-modern-list '((43 . "◦") 479 org-modern-list '((43 . "◦")
@@ -449,8 +483,7 @@ effect for exporting link types)."
449 org-modern-hide-stars nil 483 org-modern-hide-stars nil
450 org-tags-column 0 484 org-tags-column 0
451 org-modern-keyword nil 485 org-modern-keyword nil
452 org-modern-table nil) 486 org-modern-table nil))
453 (global-org-modern-mode))
454 487
455(use-package org-taskwise 488(use-package org-taskwise
456 :after org 489 :after org
diff --git a/lisp/acdw-web.el b/lisp/acdw-web.el index 36a5ba4..40e1a3d 100644 --- a/lisp/acdw-web.el +++ b/lisp/acdw-web.el
@@ -114,6 +114,9 @@ regexp that will not be regexp-quoted when matching against a url."
114 (list :tag "Regexp" regexp) 114 (list :tag "Regexp" regexp)
115 (string :tag "Literal string")))) 115 (string :tag "Literal string"))))
116 116
117(with-eval-after-load 'custom-allowed
118 (add-to-list 'custom-allowed-variables '+browse-url-external-domains))
119
117(defun +browse-url-external-url-p (url) 120(defun +browse-url-external-url-p (url)
118 "Return t if URL is a member of `+browse-url-external-domains'. 121 "Return t if URL is a member of `+browse-url-external-domains'.
119This function only tests URL's domain." 122This function only tests URL's domain."
@@ -125,6 +128,29 @@ This function only tests URL's domain."
125 host) 128 host)
126 return t))) 129 return t)))
127 130
131(defun +browse-url-external-domain-add (domain &optional regexp?)
132 "Add DOMAIN to `+browse-url-external-domains'.
133If REGEXP? is non-nil, it will note that the domain is a regexp.
134This function will also save `custom-file' with the updated value."
135 (interactive (pcase current-prefix-arg
136 (`nil
137 (list (read-from-minibuffer "Domain: ")
138 nil))
139 (`(4)
140 (list (read-from-minibuffer "Domain regex: ")
141 t))
142 (_
143 (list (read-from-minibuffer "Domain: ")
144 (y-or-n-p "Regex? ")))))
145 (let ((new (funcall (if regexp? #'list #'identity)
146 domain)))
147 (custom-set-variables
148 `(+browse-url-external-domains
149 ',(add-to-list '+browse-url-external-domains new)))
150 (with-current-buffer (find-file-noselect custom-file)
151 (custom-save-variables))
152 (message "%s added to `+browse-url-external-domains'."
153 domain)))
128 154
129;;; Downloading 155;;; Downloading
130 156
@@ -165,6 +191,34 @@ This function only tests URL's domain."
165;;; Packages 191;;; Packages
166 192
167(use-package eww 193(use-package eww
194 :preface
195 (defun bookmark-eww--make ()
196 "Make eww bookmark record."
197 `((filename . ,(plist-get eww-data :url))
198 (title . ,(plist-get eww-data :title))
199 (time . ,(current-time-string))
200 (handler . ,#'bookmark-eww-handler)
201 (defaults . (,(concat
202 ;; url without the https and path
203 (replace-regexp-in-string
204 "/.*" ""
205 (replace-regexp-in-string
206 "\\`https?://" ""
207 (plist-get eww-data :url)))
208 " - "
209 ;; page title
210 (replace-regexp-in-string
211 "\\` +\\| +\\'" ""
212 (replace-regexp-in-string
213 "[\n\t\r ]+" " "
214 (plist-get eww-data :title))))))))
215 (defun bookmark-eww-handler (bm)
216 "Handler for eww bookmarks."
217 (eww-browse-url (alist-get 'filename bm)))
218 (defun bookmark-eww--setup ()
219 "Setup eww bookmark integration."
220 (setq-local bookmark-make-record-function #'bookmark-eww--make))
221 :commands (eww eww-browse-url)
168 :config 222 :config
169 (setopt eww-use-browse-url ".") 223 (setopt eww-use-browse-url ".")
170 (add-hook 'eww-mode-hook 224 (add-hook 'eww-mode-hook
@@ -181,7 +235,12 @@ This function only tests URL's domain."
181 browse-url-secondary-browser-function 235 browse-url-secondary-browser-function
182 (or url (plist-get eww-data :url))) 236 (or url (plist-get eww-data :url)))
183 (:success (when (null url) (quit-window))) ; Interactive use 237 (:success (when (null url) (quit-window))) ; Interactive use
184 (t (signal (car e) (cdr e))))))) 238 (t (signal (car e) (cdr e))))))
239 (add-hook 'eww-mode-hook #'bookmark-eww--setup)
240 (define-key eww-mode-map "b" #'bookmark-set)
241 (define-key eww-mode-map "B" #'bookmark-jump)
242 (define-key eww-mode-map (kbd "M-n") nil)
243 (define-key eww-mode-map (kbd "M-p") nil))
185 244
186(use-package browse-url 245(use-package browse-url
187 :demand t 246 :demand t
@@ -204,7 +263,8 @@ This function only tests URL's domain."
204 . +browse-url-with-mpv) 263 . +browse-url-with-mpv)
205 ;; Images 264 ;; Images
206 (,(+browse-url-matches "pbs\\.twimg\\.com" 265 (,(+browse-url-matches "pbs\\.twimg\\.com"
207 (rx "." (or "jpeg" "jpg" "png" "bmp" "webp") 266 (rx "." (or "jpeg" "jpg" "png" "pn"
267 "bmp" "webp")
208 eos)) 268 eos))
209 . +browse-url-with-mpv-image) 269 . +browse-url-with-mpv-image)
210 ;; Blobs 270 ;; Blobs
@@ -214,16 +274,18 @@ This function only tests URL's domain."
214 (+browse-url-external-url-p 274 (+browse-url-external-url-p
215 . ,browse-url-secondary-browser-function)) 275 . ,browse-url-secondary-browser-function))
216 ;; External domains 276 ;; External domains
217 +browse-url-external-domains '("github.com" "gitlab.com" "codeberg.org" 277 ;; +browse-url-external-domains
218 "tildegit.org" "git.tilde.town" 278 ;; '("github.com" "gitlab.com" "codeberg.org"
219 "google.com" "imgur.com" "twitch.tv" 279 ;; "tildegit.org" "git.tilde.town"
220 "pixelfed" "instagram.com" 280 ;; "google.com" "imgur.com" "twitch.tv"
221 "bibliogram.art" "reddit.com" 281 ;; "pixelfed" "instagram.com"
222 "teddit.net" "libreddit.de" 282 ;; "bibliogram.art" "reddit.com"
223 "streamable.com" "spotify.com" 283 ;; "teddit.net" "libreddit.de"
224 "hetzner.cloud" "melpa.org" 284 ;; "streamable.com" "spotify.com"
225 "twitter.com" ("^t\\.co$") 285 ;; "hetzner.cloud" "melpa.org"
226 "nitter.snopyta.org" "nitter.net")) 286 ;; "twitter.com" ("^t\\.co$")
287 ;; "nitter.snopyta.org" "nitter.net")
288 )
227 ;; External browsers: firefox > chromium > chrome 289 ;; External browsers: firefox > chromium > chrome
228 (when-let ((firefox (choose-executable "firefox" 290 (when-let ((firefox (choose-executable "firefox"
229 "firefox-esr"))) 291 "firefox-esr")))
@@ -268,14 +330,16 @@ This function only tests URL's domain."
268 :bind 330 :bind
269 (("M-l M-l" . +link-hint-open-link) 331 (("M-l M-l" . +link-hint-open-link)
270 ("M-l l" . +link-hint-open-link) 332 ("M-l l" . +link-hint-open-link)
271 ("M-l M-o" . +link-hint-open-secondary) 333 ("M-l M-o" . +link-hint-open:secondary)
272 ("M-l o" . +link-hint-open-secondary) 334 ("M-l o" . +link-hint-open:secondary)
273 ("M-l M-m" . +link-hint-open-multiple-links) 335 ("M-l M-m" . +link-hint-open-multiple-links)
274 ("M-l m" . +link-hint-open-multiple-links) 336 ("M-l m" . +link-hint-open-multiple-links)
275 ("M-l M-w" . link-hint-copy-link) 337 ("M-l M-w" . link-hint-copy-link)
276 ("M-l w" . link-hint-copy-link) 338 ("M-l w" . link-hint-copy-link)
277 ("M-l M-c" . +link-hint-open-chrome) 339 ("M-l M-c" . +link-hint-open:chrome)
278 ("M-l c" . +link-hint-open-chrome)) 340 ("M-l c" . +link-hint-open:chrome)
341 ("M-l M-d" . +link-hint-open:download)
342 ("M-l d" . +link-hint-open:download))
279 :config 343 :config
280 (require '+link-hint) 344 (require '+link-hint)
281 (setopt link-hint-avy-style 'at-full 345 (setopt link-hint-avy-style 'at-full
@@ -286,8 +350,9 @@ This function only tests URL's domain."
286 ;; another package's configuration, but I don't care enough to fix it. 350 ;; another package's configuration, but I don't care enough to fix it.
287 (setq link-hint-types 351 (setq link-hint-types
288 (delq 'link-hint-completion-list-candidate link-hint-types)) 352 (delq 'link-hint-completion-list-candidate link-hint-types))
289 (+link-hint-open-secondary-setup) 353 ;; (+link-hint-open-secondary-setup)
290 (+link-hint-open-chrome-setup)) 354 ;; (+link-hint-open-chrome-setup)
355 )
291 356
292(provide 'acdw-web) 357(provide 'acdw-web)
293;;; acdw-web.el ends here 358;;; acdw-web.el ends here
diff --git a/lisp/acdw.el b/lisp/acdw.el index 46079f6..63291d3 100644 --- a/lisp/acdw.el +++ b/lisp/acdw.el
@@ -184,7 +184,9 @@ prefix ARG is non-nil; then it just saves them."
184 (user-error "Buffer not attached to file")) 184 (user-error "Buffer not attached to file"))
185 (hack-dir-local-variables) 185 (hack-dir-local-variables)
186 (let ((print-level nil) 186 (let ((print-level nil)
187 (print-length nil)) 187 (print-length nil)
188 (before-save-hook nil)
189 (after-save-hook nil))
188 (when-let ((new-words (cl-remove-if 190 (when-let ((new-words (cl-remove-if
189 (lambda (el) (eq el '\.\.\.)) ; XXX: NO IDEA 191 (lambda (el) (eq el '\.\.\.)) ; XXX: NO IDEA
190 ; where this came from 192 ; where this came from
@@ -330,5 +332,46 @@ include the time. When called with \\[universal-argument]
330 (fill-paragraph-function nil)) 332 (fill-paragraph-function nil))
331 (fill-paragraph))) 333 (fill-paragraph)))
332 334
335(defun fill-with-double-spaced-sentences-dwim (&optional start end)
336 "Fill paragraph or region, double-spacing sentences."
337 (interactive)
338 (let ((sentence-end-double-space t))
339 (unless (region-active-p)
340 (mark-paragraph))
341 (repunctuate-sentences :no-query
342 (region-beginning)
343 (region-end))
344 (fill-region (region-beginning)
345 (region-end))))
346
347(defun fill-with-double-spaced-sentences-dwim (&optional start end)
348 "Fill from START to END, double-spacing sentences.
349If START to END aren't given, or if a region isn't in use, fill
350the current paragraph."
351 (interactive "*r")
352 (let ((sentence-end-double-space t))
353 (save-mark-and-excursion
354 (save-restriction
355 (unless (region-active-p)
356 (setq start (progn (start-of-paragraph-text)
357 (point))
358 end (progn (end-of-paragraph-text)
359 (point))))
360 (narrow-to-region start end)
361 (goto-char (point-min))
362 (repunctuate-sentences :no-query)
363 (fill-region (point-min)
364 (point-max))))))
365
366(defun acdw-elisp-package-prepare (&optional file)
367 "Do all the elisp-package-preparing stuff on FILE.
368If FILE is nil or not given, do it on the current buffer."
369 (with-current-buffer (if file (find-file-noselect file) (current-buffer))
370 (check-parens)
371 (checkdoc)
372 (package-lint-buffer)
373 ;; TODO: use `lm-commentary' to write to README.org
374 ))
375
333(provide 'acdw) 376(provide 'acdw)
334;;; acdw.el ends here 377;;; acdw.el ends here
diff --git a/lisp/ical2org.el b/lisp/ical2org.el new file mode 100644 index 0000000..2716787 --- /dev/null +++ b/lisp/ical2org.el
@@ -0,0 +1,56 @@
1;;; ical2org.el --- Run ical2org in Emacs -*- lexical-binding: t; -*-
2
3;;; Commentary:
4
5;; based on code from this reddit thread:
6;; https://www.reddit.com/r/emacs/comments/8s1ion/ical2org_integrations/
7;;
8;; see also: icalendar.org (converts to diary format, might be all I need)
9;;
10;; XXX: This code currently imports into gnus, which isn't what I want.
11
12;;; Code:
13
14(defun ical2org (&optional replace output-buffer)
15 "Run ical2org on contents of this buffer.
16If REPLACE (interactive prefix argument), replace contents of the
17buffer. If no REPLACE nor OUTPUT-BUFFER, output goes to
18minibuffer."
19 (interactive "P")
20 (shell-command-on-region (point-min) (point-max)
21 "ical2org"
22 output-buffer
23 replace
24 "*ical2org errors*"
25 'display-errors))
26
27(defun ical2org-capture ()
28 "Run `ical2org' on this buffer, then `org-capture' the result.
29Leaves current buffer as-was afterwards."
30 (interactive)
31 (let ((buf (current-buffer))
32 (ics (buffer-string)))
33 (ical2org 'replace)
34 (mark-whole-buffer)
35 (call-interactively #'org-capture)
36 (with-current-buffer buf
37 (delete-region (point-min) (point-max))
38 (insert ics))))
39
40(defun my-gnus-org-capture-icalendar ()
41 "Capture any text/calendar invites with org."
42 (interactive)
43 (with-current-buffer gnus-article-buffer ;;; XXX
44 (save-excursion
45 (dolist (part gnus-article-mime-handle-alist)
46 (when (and (>= (length part) 3)
47 (listp (caddr part))
48 (or (equal "application/ics" (caaddr part))
49 (equal "text/calendar" (caaddr part))))
50 (save-window-excursion
51 (gnus-mime-copy-part (cdr part))
52 (ical2org-capture)))))))
53(add-hook 'gnus-article-prepare-hook #'my-gnus-org-capture-icalendar)
54
55(provide 'ical2org)
56;;; ical2org.el ends here
diff --git a/places b/places new file mode 100644 index 0000000..f53c6e7 --- /dev/null +++ b/places
@@ -0,0 +1,2 @@
1;;; -*- coding: utf-8; mode: lisp-data -*-
2(("/home/case/etc/emacs/init.el" . 35321))
diff --git a/recentf b/recentf new file mode 100644 index 0000000..0df1f93 --- /dev/null +++ b/recentf
@@ -0,0 +1,17 @@
1;;; Automatically generated by ‘recentf’ on Mon Mar 20 17:05:48 2023.
2
3(setq recentf-list
4 '(
5 "~/sync/Click Here Digital/inbox-chd.org"
6 "~/sync/Click Here Digital/chd-clients.json"
7 "~/sync/Click Here Digital/chd-employees.json"
8 "~/sync/Click Here Digital/all-tasks.json"
9 "~/etc/emacs/init.el"
10 ))
11
12(setq recentf-filter-changer-current 'nil)
13
14
15;; Local Variables:
16;; coding: utf-8-emacs
17;; End: