diff options
-rw-r--r-- | basics.el | 62 | ||||
-rw-r--r-- | early-init.el | 12 | ||||
-rw-r--r-- | history | 6 | ||||
-rw-r--r-- | init.el | 554 | ||||
-rw-r--r-- | lisp/+link-hint.el | 83 | ||||
-rw-r--r-- | lisp/+scratch.el | 75 | ||||
-rw-r--r-- | lisp/acdw-chat.el | 174 | ||||
-rw-r--r-- | lisp/acdw-mail.el | 113 | ||||
-rw-r--r-- | lisp/acdw-org.el | 77 | ||||
-rw-r--r-- | lisp/acdw-web.el | 101 | ||||
-rw-r--r-- | lisp/acdw.el | 45 | ||||
-rw-r--r-- | lisp/ical2org.el | 56 | ||||
-rw-r--r-- | places | 2 | ||||
-rw-r--r-- | recentf | 17 |
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. | ||
315 | When called interactively, prompt the user when given a prefix | ||
316 | argument." | ||
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. | ||
328 | When 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. | ||
366 | Switches to the buffer named BUF-NAME if provided (`*ielm*' by default), | ||
367 | or creates it if it does not exist. | ||
368 | See `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 |
92 | If 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." | 99 | Defined 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. | 105 | Defined by `+link-hint-define'." |
106 | If 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))) | 110 | Defined 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'. | ||
43 | TIME-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. | ||
64 | Scratch 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. | ||
36 | CHANNEL, 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. |
27 | Useful in `message-send-hook'." | 27 | Useful 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'. |
119 | This function only tests URL's domain." | 122 | This 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'. | ||
133 | If REGEXP? is non-nil, it will note that the domain is a regexp. | ||
134 | This 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. | ||
349 | If START to END aren't given, or if a region isn't in use, fill | ||
350 | the 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. | ||
368 | If 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. | ||
16 | If REPLACE (interactive prefix argument), replace contents of the | ||
17 | buffer. If no REPLACE nor OUTPUT-BUFFER, output goes to | ||
18 | minibuffer." | ||
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. | ||
29 | Leaves 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: | ||