summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--README.md1395
-rw-r--r--config.org601
2 files changed, 768 insertions, 1228 deletions
diff --git a/README.md b/README.md index f725e84..02029dc 100644 --- a/README.md +++ b/README.md
@@ -1,11 +1,19 @@
1Let’s configure Emacs using Org mode, they said. It’ll be fun, they said. 1Why the hell not, let’s do this again.
2 2
3 3
4# Pave the way 4# Basics
5
6
7## About me
8
9 (setq user-full-name "Case Duckworth"
10 user-mail-address "acdw@acdw.net")
5 11
6 12
7## Correct `exec-path` 13## Correct `exec-path`
8 14
15Straight depends on Git, so I need to tell Emacs where different paths are.
16
9 (let ((win-downloads "c:/Users/aduckworth/Downloads")) 17 (let ((win-downloads "c:/Users/aduckworth/Downloads"))
10 (dolist (path (list 18 (dolist (path (list
11 ;; Linux 19 ;; Linux
@@ -34,30 +42,36 @@ Let’s configure Emacs using Org mode, they said. It’ll be fun, they said.
34 42
35### Straight.el 43### Straight.el
36 44
37Since for whatever reason, Straight can't bootstrap itself on Windows 45Straight can't bootstrap itself on Windows, so I've wrapped the
38– I've wrapped it in a function here and added the direct git command 46bootstrap code from straight's repo in a function.
39when it errors.
40 47
41 (defun acdw/bootstrap-straight () 48 (defun acdw/bootstrap-straight ()
49 "Bootstrap straight.el."
42 (defvar bootstrap-version) 50 (defvar bootstrap-version)
43 (let ((bootstrap-file 51 (let ((bootstrap-file
44 (expand-file-name 52 (expand-file-name
45 "straight/repos/straight.el/bootstrap.el" 53 "straight/repos/straight.el/bootstrap.el"
46 user-emacs-directory)) 54 user-emacs-directory))
47 (bootstrap-version 5)) 55 (bootstrap-version 5))
48 (unless (file-exists-p bootstrap-file) 56 (unless (file-exists-p bootstrap-file)
49 (with-current-buffer 57 (with-current-buffer
50 (url-retrieve-synchronously 58 (url-retrieve-synchronously
51 (concat "https://raw.githubusercontent.com/" 59 (concat
52 "raxod502/straight.el/develop/install.el") 60 "https://raw.githubusercontent.com/"
53 'silent 'inhibit-cookies) 61 "raxod502/straight.el/"
54 (goto-char (point-max)) 62 "develop/install.el")
55 (eval-print-last-sexp))) 63 'silent 'inhibit-cookies)
56 (load bootstrap-file nil 'nomessage))) 64 (goto-char (point-max))
57 65 (eval-print-last-sexp)))
66 (load bootstrap-file nil 'nomessage)))
67
68Now, I'll *try* running it regular-style, ignoring the errors. If it
69doesn't work, I'll call git directly and clone the repo myself.
70
58 (unless (ignore-errors (acdw/bootstrap-straight)) 71 (unless (ignore-errors (acdw/bootstrap-straight))
59 (message "Straight.el didn't bootstrap correctly. Cloning directly...") 72 (message "Straight.el didn't bootstrap correctly. Cloning directly...")
60 (call-process "git" nil (get-buffer-create "*bootstrap-straight-messages*") nil 73 (call-process "git" nil
74 (get-buffer-create "*bootstrap-straight-messages*") nil
61 "clone" 75 "clone"
62 "https://github.com/raxod502/straight.el" 76 "https://github.com/raxod502/straight.el"
63 (expand-file-name "straight/repos/straight.el" 77 (expand-file-name "straight/repos/straight.el"
@@ -65,317 +79,226 @@ when it errors.
65 (acdw/bootstrap-straight)) 79 (acdw/bootstrap-straight))
66 80
67 81
68### Use-package 82## Customize macro
69
70 (setq straight-use-package-by-default t)
71 (setq use-package-hook-name-suffix nil)
72 (straight-use-package 'use-package)
73
74
75### Extra use-package keywords
76
771. :custom-update
78
79 (straight-use-package
80 '(use-package-custom-update
81 :host github
82 :repo "a13/use-package-custom-update"))
83
84 (require 'use-package-custom-update)
85
86
87## Customize variables
88
89
90### Put customizations in a separate file
91
92 (setq custom-file
93 (expand-file-name "custom.el" user-emacs-directory))
94
95
96### A macro for ease of customization
97 83
98 (defmacro cuss (var val &optional docstring) 84 (defmacro cuss (var val &optional docstring)
99 "Basically `:custom' from `use-package', broken out." 85 "Basically, `:custom' from `use-package', but without `use-package'."
86 (declare (doc-string 3)
87 (indent 2))
100 `(funcall (or (get ',var 'custom-set) #'set-default) 88 `(funcall (or (get ',var 'custom-set) #'set-default)
101 ',var ,val)) 89 ',var ,val))
102 90
103 91
104## Keep a tidy `~/.emacs` 92## Clean `.emacs.d`
105 93
106 (straight-use-package 'no-littering) 94 (straight-use-package 'no-littering)
107 95 (require 'no-littering)
108 (cuss backup-directory-alist `((".*" . ,(no-littering-expand-var-file-name "backup/")))
109 "Where to store backup files.")
110
111 (cuss auto-save-file-name-transforms
112 `((".*" ,(no-littering-expand-var-file-name "autosaves/") t))
113 "Where to store auto-save files.")
114
115 (cuss save-place-file (no-littering-expand-var-file-name "places")
116 "Where to store place files.")
117
118 (cuss undo-fu-session-directory (no-littering-expand-var-file-name "undos/")
119 "Where to store undo information.")
120
121 (cuss elpher-certificate-directory
122 (no-littering-expand-var-file-name "elpher-certificates/")
123 "Where to store elpher client certificates.")
124
125 ;; Make all directories defined above
126 (dolist (dir '("backup"
127 "autosaves"
128 "undos"
129 "elpher-certificates"))
130 (make-directory (no-littering-expand-var-file-name dir) 'parents))
131
132 96
133## About me
134 97
135 (setq user-full-name "Case Duckworth" 98## Look and feel
136 user-mail-address "acdw@acdw.net")
137 99
138 100
139# Look and Feel 101### Fonts
140
141
142## Simplify the UI
143
144
145### Tool bars and menu bars
146
147 (cuss default-frame-alist
148 '((tool-bar-lines . 0)
149 (menu-bar-lines . 0)))
150
151 (menu-bar-mode -1)
152 (tool-bar-mode -1)
153
154
155### Scroll bars
156
157 (add-to-list 'default-frame-alist '(vertical-scroll-bars . nil))
158 (scroll-bar-mode -1)
159
160 (add-to-list 'default-frame-alist '(horizontal-scroll-bars . nil))
161 (horizontal-scroll-bar-mode -1)
162 102
1031. Define fonts
163 104
164### Dialog boxen 105 (defun set-face-from-alternatives (face fonts)
106 (catch :return
107 (dolist (font fonts)
108 (when (find-font (font-spec :family (car font)))
109 (apply #'set-face-attribute `(,face nil
110 :family ,(car font)
111 ,@(cdr font)))
112 (throw :return font)))))
113
114 (defun acdw/setup-fonts ()
115 "Setup fonts. This has to happen after the frame is setup for
116 the first time, so it should be added to `window-setup-hook'. It
117 removes itself from that hook."
118 (interactive)
119 (when (display-graphic-p)
120 (set-face-from-alternatives 'default
121 '(("Libertinus Mono"
122 :height 110)
123 ("Linux Libertine Mono O"
124 :height 110)
125 ("Go Mono"
126 :height 100)
127 ("Consolas"
128 :height 100)))
129
130 (set-face-from-alternatives 'fixed-pitch
131 '(("Libertinus Mono"
132 :height 110)
133 ("Linux Libertine Mono O"
134 :height 110)
135 ("Go Mono"
136 :height 100)
137 ("Consolas"
138 :height 100)))
139
140 (set-face-from-alternatives 'variable-pitch
141 '(("Libertinus Serif"
142 :height 120)
143 ("Linux Libertine O"
144 :height 120)
145 ("Georgia"
146 :height 110)))
147
148 (remove-function after-focus-change-function #'acdw/setup-fonts)))
149
150 (add-function :before after-focus-change-function #'acdw/setup-fonts)
165 151
166 (cuss use-dialog-box nil) 1522. Line spacing
167 153
154 (cuss line-spacing 0.1
155 "Add 10% extra space below each line.")
168 156
169### Shorten confirmations 1573. Unicode Fonts
170 158
171 (fset 'yes-or-no-p #'y-or-n-p) 159 (straight-use-package 'unicode-fonts)
160 (require 'unicode-fonts)
161 (unicode-fonts-setup)
172 162
173 163
174### Remove the bell 164### Cursor
175 165
176 (cuss visible-bell (not (string= (system-name) "larry"))) 166 (cuss cursor-type 'bar
167 "Show a vertical bar for the cursor.")
177 168
178 (defun acdw/ring-bell-function () 169 (cuss cursor-in-non-selected-windows 'hollow
179 "Custom bell-ringing function." 170 "Show an empty box in inactive windows.")
180 (let ((orig-face (face-foreground 'mode-line)))
181 (set-face-foreground 'modeline "#F2804F")
182 (run-with-idle-timer
183 0.1 nil
184 (lambda (fg)
185 (set-face-foreground 'mode-line fg))
186 orig-face)))
187 171
188 (cuss ring-bell-function #'acdw/ring-bell-function) 172 ;; Don't blink the cursor
189 173 (blink-cursor-mode -1)
190
191### Tell Ediff to setup windows better
192
193 (declare-function ediff-setup-windows-plain "ediff-wind.el")
194 (cuss ediff-window-setup-function #'ediff-setup-windows-plain)
195
196
197## Tweak the remaining UI
198
199
200### Fringes
201 174
202 (add-to-list 'default-frame-alist '(left-fringe-width . 2))
203 (add-to-list 'default-frame-alist '(right-fringe-width . 2))
204 175
176### Tool Bars
205 177
206### Minibuffer 1781. Tool bars and menu bars
207 179
2081. Setup the minibuffer frame 180 (cuss default-frame-alist
209 181 '((tool-bar-lines . 0)
210 (cuss minibuffer-frame-alist 182 (menu-bar-lines .0))
211 '((width . 80) 183 "Setup the default frame alist.")
212 (height . 2)
213 (vertical-scrollbars . nil)))
214 184
215 (set-window-scroll-bars (minibuffer-window) nil nil) 185 (menu-bar-mode -1)
216 186 (tool-bar-mode -1)
2172. Keep the cursor from going into the prompt
218
219 (cuss minibuffer-prompt-properties
220 '(read-only t cursor-intangible t face minibuffer-prompt))
221
222 187
223### Tabs 1882. Scroll bars
224 189
2251. Show the tabs as current buffer, plus window count 190 (add-to-list 'default-frame-alist
226 191 '(vertical-scroll-bars . nil))
227 (cuss tab-bar-tab-name-function #'tab-bar-tab-name-current-with-count) 192
228 193 (scroll-bar-mode -1)
2292. Only show the tab bar when there's more than one tab 194
195 (add-to-list 'default-frame-alist
196 '(horizontal-scroll-bars . nil))
197
198 (horizontal-scroll-bar-mode -1)
230 199
231 (cuss tab-bar-show 1
232 "Show the tab bar only when there's more than 1 tab.")
233 200
201### Dialogs
234 202
235### Cursor 203 (cuss use-dialog-box nil
204 "Don't use dialog boxes to ask questions.")
236 205
237 (cuss cursor-type 'bar 2061. Yes or no questions
238 "Show a vertical bar for the cursor.")
239 (cuss cursor-in-non-selected-windows 'hollow
240 "In inactive windows, make the cursor an empty box.")
241 (blink-cursor-mode 0)
242 207
208 (fset 'yes-or-no-p #'y-or-n-p)
243 209
244### Buffer names 2102. The Bell
245 211
246 (require 'uniquify) 212 (defun acdw/ring-bell-function ()
247 (cuss uniquify-buffer-name-style 'forward) 213 "Ring the bell."
214 (let ((orig-face (face-foreground 'mode-line)))
215 (set-face-foreground 'mode-line "#F2804F")
216 (run-with-idle-timer
217 0.1 nil
218 (lambda (fg)
219 (set-face-foreground 'mode-line fg))
220 orig-face)))
221
222 (cuss ring-bell-function #'acdw/ring-bell-function)
248 223
249 224
250### Buffer boundaries 225### Frames
251 226
252 (cuss indicate-buffer-boundaries 2271. Fringes
253 '((up . right)
254 (down . right)
255 (t . nil)))
256
257 (cuss indicate-empty-lines t)
258 228
229 (cuss indicate-empty-lines t
230 "Show an indicator on the left fringe of empty lines past the
231 end of the buffer.")
232 (cuss indicate-buffer-boundaries 'right
233 "Indicate the beginning and end of the buffer and whether it
234 scrolls off-window in the right fringe.")
259 235
260## Windows 2362. Minibuffer
261 237
238 (cuss minibuffer-prompt-properties
239 '(read-only t cursor-intangible t face minibuffer-prompt)
240 "Keep the cursor away from the minibuffer prompt.")
262 241
263### Winner mode 2423. Tabs
264 243
265 (when (fboundp 'winner-mode) 244 (cuss tab-bar-tab-name-function
266 (winner-mode +1)) 245 #'tab-bar-tab-name-current-with-count
246 "Show the tab name as the name of the current buffer, plus a
247 count of the windows in the tab.")
248
249 (cuss tab-bar-show 1
250 "Show the tab bar, when there's more than one tab.")
267 251
268 252
269### Windmove 253### Windows
270 254
271 (cuss windmove-create-window t 2551. Winner mode
272 "Create windows in a direction if they don't exist.")
273 (cuss windomove-wrap-around t
274 "Wrap window movements around frame edges.")
275
276 (windmove-default-keybindings)
277
278
279### Pop some buffers up in the same window
280
281from [link0ff](https://github.com/link0ff/emacs-init).
282
283 (push `(,(rx bos
284 "*"
285 (or "Help" "Apropos" "Colors" "Buffer List" "Command History"
286 "Dictionary" "Locate" "Messages" "Proced" "eww" "snd"
287 (and "gud-" (+ (any "a-z0-9")))
288 "compilation" "grep" "erlang" "haskell"
289 ;; Handle both "*shell*" and e.g. "*emacs-shell*"
290 ;; generated by `project-shell':
291 (and (? (* nonl) "-") "shell")
292 "Shell Command Output"
293 (and "SQL: " (+ (any "A-za-z")))
294 "Diff" "vc-dir" "vc-log" "vc-search-log")
295 "*"
296 ;; Uniquifed buffer name with optional suffix in angle brackets
297 (? (and "<" (+ (not (any ">"))) ">"))
298 eos)
299 display-buffer-same-window
300 (inhibit-same-window . nil))
301 display-buffer-alist)
302
303 (defun display-buffer-from-help-p (_buffer-name _action)
304 (unless current-prefix-arg
305 (with-current-buffer (window-buffer)
306 (eq major-mode 'help-mode))))
307
308 (push '(display-buffer-from-help-p display-buffer-same-window)
309 display-buffer-alist)
310 256
257 (when (fboundp 'winner-mode)
258 (winner-mode +1))
311 259
312## Startup 2602. Switch windows
313 261
314 (cuss inhibit-startup-screen t "Don't show Emacs' startup buffer.") 262 (global-set-key (kbd "M-o") #'other-window)
315 (cuss initial-buffer-choice t "Start at *scratch*.")
316 (cuss initial-scratch-message "" "Empty *scratch*.")
317 263
318 264
319## Theme 265### Buffers
320 266
321 (straight-use-package '(modus-themes 2671. Uniquify buffers
322 :host gitlab
323 :repo "protesilaos/modus-themes"
324 :branch "main"))
325
326 (cuss modus-themes-slanted-constructs t)
327 (cuss modus-themes-bold-constructs t)
328 (cuss modus-themes-fringes nil)
329 (cuss modus-themes-mode-line '3d)
330 (cuss modus-themes-syntax 'yellow-comments)
331 (cuss modus-themes-intense-hl-line nil)
332 (cuss modus-themes-paren-match 'intense-bold)
333 (cuss modus-themes-links nil)
334 (cuss modus-themes-no-mixed-fonts nil)
335 (cuss modus-themes-prompts nil)
336 (cuss modus-themes-completions nil)
337 (cuss modus-themes-diffs nil)
338 (cuss modus-themes-org-blocks 'grayscale)
339 (cuss modus-themes-headings
340 '((1 . line)
341 (t . t)))
342 (cuss modus-themes-variable-pitch-headings t)
343 (cuss modus-themes-scale-headings t)
344 (cuss modus-themes-scale-1 1.1)
345 (cuss modus-themes-scale-2 1.15)
346 (cuss modus-themes-scale-3 1.21)
347 (cuss modus-themes-scale-4 1.27)
348 (cuss modus-themes-scale-5 1.33)
349
350 ;; :custom-face
351 (custom-set-faces `(font-lock-comment-face
352 ((t (:inherit (custom-comment italic variable-pitch))))))
353
354 (load-theme 'modus-operandi t)
355 268
269 (require 'uniquify)
270 (cuss uniquify-buffer-name-style 'forward
271 "Uniquify buffers' names by going up the path trees until they
272 become unique.")
356 273
357### Change theme based on time of day 2742. Startup buffers
358 275
359 (cuss calendar-latitude 30.4515) 276 (cuss inhibit-startup-screen t
360 (cuss calendar-longitude -91.1871) 277 "Don't show Emacs' startup buffer.")
361 278
362 (straight-use-package 'circadian) 279 (cuss initial-buffer-choice t
363 280 "Start with *scratch*.")
364 (cuss circadian-themes '((:sunrise . modus-operandi) 281
365 (:sunset . modus-vivendi))) 282 (cuss initial-scratch-message ""
366 283 "Empty *scratch* buffer.")
367 (circadian-setup)
368 284
369 285
370### Modeline 286### Modeline
371 287
372 (straight-use-package 'smart-mode-line) 2881. Smart mode line
373 (cuss sml/no-confirm-load-theme t)
374 (sml/setup)
375 289
3761. Rich minority 290 (straight-use-package 'smart-mode-line)
291
292 (cuss sml/no-confirm-load-theme t
293 "Pass the NO-CONFIRM flag to `load-theme'.")
294
295 (sml/setup)
377 296
378 Since this *comes* with smart mode line, I’m just going to use it, instead of `diminish` or another package. I do have to write this helper function, though, to add things to the whitelist. 2972. Rich minority
298
299 Since this *comes* with smart mode line, I’m just going to use it,
300 instead of `diminish` or another package. I do have to write this
301 helper function, though, to add things to the whitelist.
379 302
380 (defun rm/whitelist-add (regexp) 303 (defun rm/whitelist-add (regexp)
381 "Add a REGEXP to the whitelist for `rich-minority'." 304 "Add a REGEXP to the whitelist for `rich-minority'."
@@ -390,212 +313,138 @@ from [link0ff](https://github.com/link0ff/emacs-init).
390 (rm/whitelist-add "^$") 313 (rm/whitelist-add "^$")
391 314
392 315
393### Fonts 316### Theme
394 317
3951. Define fonts 3181. Modus Themes
396 319
397 (defun set-face-from-alternatives (face fonts) 320 (straight-use-package 'modus-themes)
398 (catch :return
399 (dolist (font fonts)
400 (when (find-font (font-spec :family (car font)))
401 (apply #'set-face-attribute `(,face nil
402 :family ,(car font)
403 ,@(cdr font)))
404 (throw :return font)))))
405 321
406 (defun acdw/setup-fonts () 322 (cuss modus-themes-slanted-constructs t
407 "Setup fonts. This has to happen after the frame is setup for 323 "Use more slanted constructs.")
408 the first time, so it should be added to `window-setup-hook'. It 324 (cuss modus-themes-bold-constructs t
409 removes itself from that hook." 325 "Use more bold constructs.")
410 (interactive)
411 (when (display-graphic-p)
412 (set-face-from-alternatives 'default
413 '(("Libertinus Mono"
414 :height 110)
415 ("Linux Libertine Mono O"
416 :height 110)
417 ("Go Mono"
418 :height 100)
419 ("Consolas"
420 :height 100)))
421 326
422 (set-face-from-alternatives 'fixed-pitch 327 (cuss modus-themes-region 'bg-only
423 '(("Libertinus Mono" 328 "Only highlight the background of the selected region.")
424 :height 110)
425 ("Linux Libertine Mono O"
426 :height 110)
427 ("Go Mono"
428 :height 100)
429 ("Consolas"
430 :height 100)))
431 329
432 (set-face-from-alternatives 'variable-pitch 330 (cuss modus-themes-org-blocks 'grayscale
433 '(("Libertinus Serif" 331 "Show org-blocks with a grayscale background.")
434 :height 120) 332 (cuss modus-themes-headings
435 ("Linux Libertine O" 333 '((1 . line)
436 :height 120) 334 (t . t))
437 ("Georgia" 335 "Highlight top headings with `line' style, and others by default.")
438 :height 110)))
439 336
440 (remove-function after-focus-change-function #'acdw/setup-fonts))) 337 (cuss modus-themes-scale-headings t
338 "Scale headings by the ratios below.")
339 (cuss modus-themes-scale-1 1.1)
340 (cuss modus-themes-scale-2 1.15)
341 (cuss modus-themes-scale-3 1.21)
342 (cuss modus-themes-scale-4 1.27)
343 (cuss modus-themes-scale-5 1.33)
441 344
442 (add-function :before after-focus-change-function #'acdw/setup-fonts) 345 (load-theme 'modus-operandi t)
443
4442. Variable-pitch in text modes
445
446 (add-hook 'text-mode-hook #'variable-pitch-mode)
447
4483. Line spacing
449 346
450 (cuss line-spacing 0.1) 3472. Change themes based on time of day
451 348
4524. Unicode fonts 349 (cuss calendar-latitude 30.4515)
453 350 (cuss calendar-longitude -91.1871)
454 (straight-use-package 'unicode-fonts) 351
455 (with-eval-after-load 'unicode-fonts 352 (straight-use-package 'circadian)
456 (unicode-fonts-setup)) 353
457 354 (cuss circadian-themes '((:sunrise . modus-operandi)
458 355 (:sunset . modus-vivendi)))
459# Interactivity 356
460 357 (circadian-setup)
461
462## Async
463
464 (straight-use-package 'async)
465 (autoload 'dired-async-mode "dired-async.el" nil t)
466 (dired-async-mode +1)
467
468 (async-bytecomp-package-mode +1)
469
470
471## Completing-read
472
473
474### Shadow file names
475
476 (cuss file-name-shadow-properties '(invisible t))
477
478 (file-name-shadow-mode +1)
479 358
480 359
481### Selectrum 360## Interactivity
482 361
483 (straight-use-package 'selectrum)
484 (require 'selectrum)
485 (selectrum-mode +1)
486 362
363### Completing read
487 364
488### Prescient 3651. Shadow file names in `completing-read`.
489 366
490 (straight-use-package 'prescient) 367 (cuss file-name-shadow-properties '(invisible t))
491 (require 'prescient) 368
492 369 (file-name-shadow-mode +1)
493 (prescient-persist-mode +1)
494
495 (straight-use-package 'selectrum-prescient)
496
497 (with-eval-after-load 'prescient
498 (with-eval-after-load 'selectrum
499 (selectrum-prescient-mode +1)))
500
501 (straight-use-package 'company-prescient)
502
503 (with-eval-after-load 'prescient
504 (with-eval-after-load 'company
505 (company-prescient-mode +1)))
506
507
508### Consult
509
510 (use-package consult
511 :after (selectrum)
512 :straight (consult
513 :host github
514 :repo "minad/consult")
515 :bind
516 (("C-x b" . consult-buffer)
517 ("C-x 4 b" . consult-buffer-other-window)
518 ("C-x 5 b" . consult-buffer-other-frame)
519 ("M-g o" . consult-outline)
520 ("M-g l" . consult-line)
521 ("M-y" . consult-yank-pop)
522 ("<help> a" . consult-apropos))
523 :init
524 (fset 'multi-occur #'consult-multi-occur))
525
526 (use-package consult-selectrum
527 :straight (consult-selectrum
528 :host github
529 :repo "minad/consult"))
530
531
532### Marginalia
533
534 (straight-use-package '(marginalia
535 :host github
536 :repo "minad/marginalia"
537 :branch "main"))
538
539 (cuss marginalia-annotators
540 (if (eq system-type 'windows-nt)
541 '(marginalia-annotators-light
542 marginalia-annotators-heavy)
543 '(marginalia-annotators-heavy
544 marginalia-annotators-light)))
545
546 (marginalia-mode +1)
547
548
549## Ignore case
550 370
551 (cuss completion-ignore-case t) 3712. Ignore case in `completing-read`
552 (cuss read-buffer-completion-ignore-case t)
553 (cuss read-file-name-completion-ignore-case t)
554 372
373 (cuss completion-ignore-case t)
374 (cuss read-buffer-completion-ignore-case t)
375 (cuss read-file-name-completion-ignore-case t)
555 376
556## Search 3773. Selectrum
557 378
558 (use-package ctrlf 379 (straight-use-package 'selectrum)
559 :custom 380 (require 'selectrum)
560 (ctrlf-show-match-count-at-eol nil) 381 (selectrum-mode +1)
561 :bind
562 ("C-s" . ctrlf-forward-regexp)
563 ("C-r" . ctrlf-backward-regexp)
564 ("C-M-s" . ctrlf-forward-literal)
565 ("C-M-r" . ctrlf-backward-literal)
566 :config
567 (ctrlf-mode +1))
568 382
3834. Prescient
569 384
570## Mouse 385 (straight-use-package 'prescient)
386 (require 'prescient)
387 (prescient-persist-mode +1)
388
389 (straight-use-package 'selectrum-prescient)
390 (require 'selectrum-prescient)
391 (selectrum-prescient-mode +1)
571 392
3935. Consult
572 394
573### Fix scrolling in margins 395 (straight-use-package '(consult
396 :host github
397 :repo "minad/consult"))
398 (require 'consult)
399
400 (straight-use-package '(consult-selectrum
401 :host github
402 :repo "minad/consult"))
403 (require 'consult-selectrum)
404
405 (define-key ctl-x-map "b" #'consult-buffer)
406 (define-key ctl-x-map (kbd "C-r") #'consult-buffer)
407 (define-key ctl-x-map "4b" #'consult-buffer-other-window)
408 (define-key ctl-x-map "5b" #'consult-buffer-other-frame)
409
410 (define-key goto-map "o" #'consult-outline)
411 (define-key goto-map "g" #'consult-line)
412 (define-key goto-map (kbd "M-g") #'consult-line)
413 (define-key goto-map "l" #'consult-line)
414 (define-key goto-map "m" #'consult-mark)
415 (define-key goto-map "k" #'consult-global-mark)
416 (define-key goto-map "i" #'consult-imenu)
417 (define-key goto-map "e" #'consult-error)
418
419 (global-set-key (kbd "M-y") #'consult-yank-pop)
420
421 (define-key help-map "a" #'consult-apropos)
422
423 (fset 'multi-occur #'consult-multi-occur)
574 424
575This is not *quite* correct yet. For example, scrolling in the margins with a trackpad isn’t picked up (a trackpad sends different mouse events). 4256. Marginalia
576 426
577 (dolist (vec '([left-margin wheel-down] 427 (straight-use-package '(marginalia
578 [right-margin wheel-down] 428 :host github
579 [left-margin wheel-up] 429 :repo "minad/marginalia"
580 [right-margin wheel-up])) 430 :branch "main"))
581 (bind-key vec #'mwheel-scroll)) 431
432 (cuss marginalia-annotators
433 '(marginalia-annotators-heavy
434 marginalia-annotators-light))
435
436 (marginalia-mode +1)
582 437
583 438
584## Keyboard 439## Keyboard
585 440
586 441
587### Use `ESC` as a cancel key 442### `ESC` cancels all
588
589From [link0ff](https://github.com/link0ff/emacs-init). I thought they made a great point that `ESC` isn’t necessary to copy the `META` key on window-systems, which is where I use Emacs, anyway.
590
591 (when window-system
592 (define-key global-map [escape] 'keyboard-escape-quit)
593 (define-key isearch-mode-map [escape] 'isearch-cancel))
594 443
444 (global-set-key (kbd "<escape>") #'keyboard-escape-quit)
595 445
596### Make `C-z` more useful as a prefix key
597 446
598Also from link0ff. See the above for a link. 447### Personal prefix key: `C-z`
599 448
600 (defvar acdw/map 449 (defvar acdw/map
601 (let ((map (make-sparse-keymap)) 450 (let ((map (make-sparse-keymap))
@@ -604,370 +453,330 @@ Also from link0ff. See the above for a link.
604 (define-key global-map "\C-z" map) 453 (define-key global-map "\C-z" map)
605 (define-key map "\C-z" c-z) 454 (define-key map "\C-z" c-z)
606 map)) 455 map))
607 (run-hooks 'acdw/map-defined-hook)
608
609
610### Which-key
611
612 (straight-use-package 'which-key)
613 456
614 (which-key-mode +1) 457 (run-hooks 'acdw/map-defined-hook)
615
616
617### Bindings
618
6191. Switch to another window
620
621 (bind-key "M-o" #'other-window)
622 458
623 459
624# Persistence 460## Persistence
625 461
626 462
627## Save history 463### Minibuffer history
628 464
629 (require 'savehist) 465 (require 'savehist)
630 466
631 (cuss savehist-additional-variables 467 (cuss savehist-additional-variables
632 '(kill-ring 468 '(kill-ring
633 search-ring 469 search-ring
634 regexp-search-ring)) 470 regexp-search-ring)
471 "Other variables to save alongside the minibuffer history.")
635 472
636 (cuss savehist-save-minibuffer-history t) 473 (cuss history-length t
474 "Don't truncate history.")
637 475
638 (cuss history-length t) 476 (cuss history-delete-duplicates t
639 477 "Delete history duplicates.")
640 (cuss history-delete-duplicates t)
641 478
642 (savehist-mode +1) 479 (savehist-mode +1)
643 480
644 481
645## Save places in files 482### File places
646 483
647 (require 'saveplace) 484 (require 'saveplace) ; this isn't required, but ... I like having it here
648 485
649 (cuss save-place-forget-unreadable-files 486 (cuss save-place-forget-unreadable-files t
650 (not (eq system-type 'windows-nt))) 487 "Don't check if files are readable or not.")
651 488
652 (save-place-mode 1) 489 (save-place-mode +1)
653 490
654 491
655## Recent files 492### Recent files
656 493
657 (require 'recentf) 494 (require 'recentf)
658 495
659 (cuss recentf-max-menu-items 100) 496 (cuss recentf-max-menu-items 100
660 (cuss recentf-max-saved-items 100) 497 "The maximum number of items in the recentf menu.")
498 (cuss recentf-max-saved-items nil
499 "Don't limit the number of recent files.")
661 500
662 (with-eval-after-load 'no-littering 501 (with-eval-after-load 'no-littering
663 (add-to-list 'recentf-exclude no-littering-var-directory) 502 (add-to-list 'recentf-exclude no-littering-var-directory)
664 (add-to-list 'recentf-exclude no-littering-etc-directory)) 503 (add-to-list 'recentf-exclude no-littering-etc-directory))
665 504
666 (recentf-mode 1) 505 (recentf-mode +1)
667
668
669### Easily navigate recent files
670
671 (defun recentf-find-file ()
672 "Find a recent file using `completing-read'."
673 (interactive)
674 (let ((file (completing-read "Recent file: " recentf-list nil t)))
675 (when file
676 (find-file file))))
677 506
678 (global-set-key (kbd "C-x C-r") #'recentf-find-file) 507 ;; save the recentf-list every 5 minutes
508 (run-at-time nil (* 5 60) 'recentf-save-list)
679 509
680 510
681## Undo 511## Undo
682 512
683 (use-package undo-fu 513 (straight-use-package 'undo-fu)
684 :bind 514 (require 'undo-fu)
685 ("C-/" . undo-fu-only-undo) 515
686 ("C-?" . undo-fu-only-redo)) 516 (global-set-key (kbd "C-/") #'undo-fu-only-undo)
517 (global-set-key (kbd "C-?") #'undo-fu-only-redo)
687 518
688 (straight-use-package 'undo-fu-session) 519 (straight-use-package 'undo-fu-session)
520 (require 'undo-fu-session)
689 521
690 (cuss undo-fu-session-incompatible-files 522 (cuss undo-fu-session-incompatible-files
691 '("/COMMIT_EDITMSG\\'" 523 '("/COMMIT_EDITMSG\\'"
692 "/git-rebase-todo\\'")) 524 "/git-rebase-todo\\'")
525 "A list of files that are incompatible with the concept of undo sessions.")
526
527 (with-eval-after-load 'no-littering
528 (let ((dir (no-littering-expand-var-file-name "undos")))
529 (make-directory dir 'parents)
530 (cuss undo-fu-session-directory dir)))
693 531
694 (global-undo-fu-session-mode +1) 532 (global-undo-fu-session-mode +1)
695 533
696 534
697# Editing 535## Files
698
699 536
700## Operate visually on lines
701 537
702 (global-visual-line-mode +1) 538### Encoding
703
704
705## Require a final newline
706
707 (cuss require-final-newline t)
708 539
5401. UTF-8
709 541
710## Killing & Yanking 542 (set-language-environment "UTF-8")
543 (set-terminal-coding-system 'utf-8)
544 (cuss locale-coding-system 'utf-8)
545 (set-default-coding-systems 'utf-8)
546 (set-selection-coding-system 'utf-8)
547 (prefer-coding-system 'utf-8)
711 548
5492. Convert all files to UNIX-style line endings
712 550
713### Replace selection when typing 551 from [Emacs Wiki](https://www.emacswiki.org/emacs/EndOfLineTips).
714 552
715 (delete-selection-mode +1) 553 (defun ewiki/no-junk-please-were-unixish ()
716 554 "Convert line endings to UNIX, dammit."
717 555 (let ((coding-str (symbol-name buffer-file-coding-system)))
718### Save existing clipboard text into kill ring before replacing it 556 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
719 557 (set-buffer-file-coding-system 'unix))))
720 (cuss save-interprogram-paste-before-kill t) 558
721 559 I add it to the `find-file-hook` *and* `before-save-hook` because I
722 560 don't want to ever work with anything other than UNIX line endings
723### Sync the system clipboard and the kill ring 561 ever again. I just don't care. Even Microsoft Notepad can handle
724 562 UNIX line endings, so I don't want to hear it.
725 (cuss yank-pop-change-selection t) 563
726 564 (add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish)
727 565 (add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish)
728## So long mode
729
730 (when (fboundp 'global-so-long-mode)
731 (global-so-long-mode))
732
733
734## Multiple cursors
735
736 (use-package multiple-cursors
737 :bind
738 ("C->" . mc/mark-next-like-this)
739 ("C-<" . mc/mark-previous-like-this)
740 ("C-c C-<" . mc/mark-all-like-this))
741 566
742 567
743## Expand region 568### Backups
744 569
745 (use-package expand-region 570 (cuss backup-by-copying 1)
746 :bind 571 (cuss delete-old-versions -1)
747 (("C-=" . er/expand-region) 572 (cuss version-control t)
748 ("C-+" . er/contract-region))) 573 (cuss vc-make-backup-files t)
574
575 (with-eval-after-load 'no-littering
576 (let ((dir (no-littering-expand-var-file-name "backup")))
577 (make-directory dir 'parents)
578 (cuss backup-directory-alist
579 `((".*" . ,dir)))))
749 580
750 581
751## Highlight modified regions 582### Auto-saves
752 583
753 (straight-use-package 'goggles) 584 (with-eval-after-load 'no-littering
754 585 (let ((dir (no-littering-expand-var-file-name "autosaves")))
755 (cuss goggles-pulse nil) 586 (make-directory dir 'parents)
587 (cuss auto-save-file-name-transforms
588 `((".*" ,dir t))))
756 589
757 (goggles-mode +1) 590 (auto-save-visited-mode +1))
758
759
760# Files
761 591
762 592
763## Encoding 593### Auto-revert buffers to files on disk
764 594
595 (global-auto-revert-mode +1)
765 596
766### UTF-8
767 597
768 (set-language-environment "UTF-8") 598### Add a timestamp to files
769 (set-terminal-coding-system 'utf-8)
770 (cuss locale-coding-system 'utf-8)
771 (set-default-coding-systems 'utf-8)
772 (set-selection-coding-system 'utf-8)
773 (prefer-coding-system 'utf-8)
774 599
600 (add-hook 'before-save-hook #'time-stamp)
775 601
776### Convert all files to UNIX-style line endings
777 602
778from [Emacs Wiki](https://www.emacswiki.org/emacs/EndOfLineTips). 603### Require a final new line
779 604
780 (defun ewiki/no-junk-please-were-unixish () 605 (cuss require-final-newline t)
781 "Convert line endings to UNIX, dammit."
782 (let ((coding-str (symbol-name buffer-file-coding-system)))
783 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
784 (set-buffer-file-coding-system 'unix))))
785 606
786I add it to the `find-file-hook` *and* `before-save-hook` because I don't want to ever work with anything other than UNIX line endings ever again. I just don't care. Even Microsoft Notepad can handle UNIX line endings, so I don't want to hear it.
787 607
788 (add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish) 608## Text editing
789 (add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish)
790 609
791 610
792## Backups 611### Operate visually on lines
793 612
794 (cuss backup-by-copying 1) 613 (global-visual-line-mode +1)
795 (cuss delete-old-versions -1)
796 (cuss version-control t)
797 (cuss vc-make-backup-files t)
798 614
799 615
800## Auto-saves 616### Stay snappy with long-lined files
801 617
802 (auto-save-visited-mode 1) 618 (when (fboundp 'global-so-long-mode)
619 (global-so-long-mode +1))
803 620
804 621
805## Revert files 622### Killing & Yanking
806 623
807 (cuss auto-revert-verbose nil) 6241. Replace selection when typing
808 (global-auto-revert-mode +1)
809 625
626 (delete-selection-mode +1)
810 627
811## Add a timestamp to files 6282. Work better with the system clipboard
812 629
813 (add-hook 'before-save-hook #'time-stamp) 630 (cuss save-interprogram-paste-before-kill t
631 "Save existing clipboard text into the kill ring before
632 replacing it.")
633
634 (cuss yank-pop-change-selection t
635 "Update the X selection when rotating the kill ring.")
814 636
815 637
816# Programming 638### Searching & Replacing
817 639
640 (straight-use-package 'visual-regexp)
641 (require 'visual-regexp)
642
643 (with-eval-after-load 'visual-regexp
644 (global-set-key (kbd "M-C-%") #'vr/query-replace))
818 645
819## Which function are we in?
820 646
821 (which-function-mode +1) 647# Programming
822 648
823 649
824## Parentheses 650## Parentheses
825 651
826 652
827### Show parentheses
828
829 (cuss show-paren-delay 0 "Show matching parens immediately.")
830 (cuss show-paren-style 'mixed
831 "Show parenthesis, or whole expression, depending on visibility.")
832 (cuss show-paren-when-point-in-periphery t
833 "Show paren when point is near-to paren.")
834 (cuss show-paren-when-point-inside-paren t
835 "Show surrounding parens.")
836
837 (add-hook 'prog-mode-hook #'show-paren-mode)
838
839
840### Smart parentheses 653### Smart parentheses
841 654
842 (straight-use-package 'smartparens) 655 (straight-use-package 'smartparens)
843 (require 'smartparens-config) 656 (require 'smartparens-config)
844 657
845 (show-smartparens-global-mode +1) 658 ;; replace show-paren
846 (add-to-list 'sp-ignore-modes-list 'org-mode)
847 659
660 (cuss sp-show-pair-delay 0
661 "Don't delay before showing the pairs.")
662 (cuss sp-show-pair-from-inside t
663 "Highlight the enclosing pair when immediately inside.")
664
665 (add-hook 'prog-mode-hook #'show-smartparens-mode +1)
666
667 ;; enable strict smartparens in prog mode
848 (add-hook 'prog-mode-hook #'smartparens-strict-mode) 668 (add-hook 'prog-mode-hook #'smartparens-strict-mode)
849 669
850 670
851## Indenting 671## Indent aggressively
852 672
853 (straight-use-package 'aggressive-indent) 673 (straight-use-package 'aggressive-indent)
854 674
855 (global-aggressive-indent-mode +1) 675 (global-aggressive-indent-mode +1)
856 676
857 677
858## Completion 678## Language-specific packages
859
860 (use-package company
861 :custom
862 (company-idle-delay 0.1)
863 (company-minimum-prefix-length 3)
864
865 :init
866 (defun acdw/company-complete-common-or-cycle+1 ()
867 (interactive)
868 (company-complete-common-or-cycle +1))
869
870 (defun acdw/company-complete-common-or-cycle-1 ()
871 (interactive)
872 (company-complete-common-or-cycle -1))
873
874 :bind
875 (:map company-active-map
876 ("C-n" . acdw/company-complete-common-or-cycle+1)
877 ("C-p" . acdw/company-complete-common-or-cycle-1))
878
879 :hook
880 (prog-mode-hook . company-mode))
881
882 (use-package company-prescient
883 :hook
884 (company-mode-hook . company-prescient-mode))
885
886 ;; this comes with company-quickhelp, so....
887
888 (use-package company-posframe
889 :after (company)
890 :config
891 (company-posframe-mode +1))
892
893
894## Languages
895
896
897### Lua
898
899 (use-package lua-mode
900 :mode "\\.lua\\'"
901 :interpreter "lua")
902
903
904### Fennel
905
906 (use-package fennel-mode
907 :mode "\\.fnl\\'")
908 679
909 680
910### Emacs lisp 681### Emacs lisp
911 682
912 (cuss eval-expression-print-length nil 683 (cuss eval-expression-print-length nil
913 "Don't truncate printed expressions by length.") 684 "Don't truncate printed expressions by length.")
914 (cuss eval-expression-print-level nil 685 (cuss eval-expression-print-level nil
915 "Don't truncate printed expressions by level.") 686 "Don't truncate printed expressions by level.")
916 687
917 688
918# Writing 689# Writing
919 690
920 691
921## Visual Fill Column 692## Visual fill column
693
694
695### Fix scrolling in margins
696
697This has to be done *before* loading the package. It's included in `visual-fill-column`, too, but for some reason isn't loaded there.
698
699 (global-set-key [right-margin mouse-1] (global-key-binding [mouse-1])) ; #'mouse-set-point
700 (global-set-key [right-margin mouse-2] (global-key-binding [mouse-2])) ; #'mouse-yank-primary
701 (global-set-key [right-margin mouse-3] (global-key-binding [mouse-3])) ; #'mouse-save-then-kill
702 (global-set-key [right-margin drag-mouse-1] #'ignore)
703 (global-set-key [right-margin drag-mouse-2] #'ignore)
704 (global-set-key [right-margin drag-mouse-3] #'ignore)
705 (global-set-key [right-margin double-mouse-1] #'ignore)
706 (global-set-key [right-margin double-mouse-2] #'ignore)
707 (global-set-key [right-margin double-mouse-3] #'ignore)
708 (global-set-key [right-margin triple-mouse-1] #'ignore)
709 (global-set-key [right-margin triple-mouse-2] #'ignore)
710 (global-set-key [right-margin triple-mouse-3] #'ignore)
711 (global-set-key [left-margin mouse-1] (global-key-binding [mouse-1])) ; #'mouse-set-point
712 (global-set-key [left-margin mouse-2] (global-key-binding [mouse-2])) ; #'mouse-yank-primary
713 (global-set-key [left-margin mouse-3] (global-key-binding [mouse-3])) ; #'mouse-save-then-kill
714 (global-set-key [left-margin drag-mouse-1] #'ignore)
715 (global-set-key [left-margin drag-mouse-2] #'ignore)
716 (global-set-key [left-margin drag-mouse-3] #'ignore)
717 (global-set-key [left-margin double-mouse-1] #'ignore)
718 (global-set-key [left-margin double-mouse-2] #'ignore)
719 (global-set-key [left-margin double-mouse-3] #'ignore)
720 (global-set-key [left-margin triple-mouse-1] #'ignore)
721 (global-set-key [left-margin triple-mouse-2] #'ignore)
722 (global-set-key [left-margin triple-mouse-3] #'ignore)
723
724 (mouse-wheel-mode +1)
725
726 (when (bound-and-true-p mouse-wheel-mode)
727 (global-set-key [right-margin mouse-wheel-down-event] #'mwheel-scroll)
728 (global-set-key [right-margin mouse-wheel-up-event] #'mwheel-scroll)
729 (global-set-key [right-margin wheel-down] #'mwheel-scroll)
730 (global-set-key [right-margin wheel-up] #'mwheel-scroll)
731 (global-set-key [left-margin mouse-wheel-down-event] #'mwheel-scroll)
732 (global-set-key [left-margin mouse-wheel-up-event] #'mwheel-scroll)
733 (global-set-key [left-margin wheel-down] #'mwheel-scroll)
734 (global-set-key [left-margin wheel-up] #'mwheel-scroll))
735
736
737### Load the package
922 738
923 (straight-use-package 'visual-fill-column) 739 (straight-use-package 'visual-fill-column)
924 740
925 (cuss split-window-preferred-function 741 (cuss visual-fill-column-center-text nil
926 'visual-fill-column-split-window-sensibly) 742 "Whether to center the text in the frame.")
927 (cuss visual-fill-column-center-text t) 743
928 (cuss fill-column 80) 744 (cuss fill-column 84
745 "Width of fill-column, and thus, visual-fill-column.")
929 746
930 (advice-add 'text-scale-adjust 747 (advice-add 'text-scale-adjust
931 :after #'visual-fill-column-adjust) 748 :after #'visual-fill-column-adjust)
932 749
933 (add-hook 'text-mode-hook #'visual-fill-column-mode) 750 (global-visual-fill-column-mode +1)
751
934 752
753## Typographical niceties
935 754
936## Type nice-looking quote-type marks 755
756### Typo mode
937 757
938 (straight-use-package 'typo) 758 (straight-use-package 'typo)
939 759
940 (add-hook 'text-mode-hook #'typo-mode) 760 (add-hook 'text-mode-hook #'typo-mode)
941 761
942 762
943## Insert *kaomoji*
944
945 (use-package insert-kaomoji
946 :bind
947 ("C-x 8 k" . insert-kaomoji))
948
949
950# Applications 763# Applications
951 764
952 765
953## Magit
954
955 (use-package magit
956 :bind
957 ("C-z g" . magit-status))
958
959
960## Org mode 766## Org mode
961 767
962I’ve put org mode under Applications, as opposed to Writing, because it’s more generally-applicable than that. 768I’ve put org mode under Applications, as opposed to Writing, because it’s more generally-applicable than that.
963 769
770
771### Basics
772
964 (straight-use-package 'org) 773 (straight-use-package 'org)
965 774
966 (with-eval-after-load 'org 775 (with-eval-after-load 'org
967 (require 'org-tempo) 776 (require 'org-tempo)
968 (require 'ox-md) 777 (require 'ox-md)
969 (bind-key "M-n" #'outline-next-visible-heading 'org-mode-map) 778 (define-key org-mode-map (kbd "M-n") #'outline-next-visible-heading)
970 (bind-key "M-p" #'outline-previous-visible-heading 'org-mode-map)) 779 (define-key org-mode-map (kbd "M-p") #'outline-previous-visible-heading))
971 780
972 (cuss org-hide-emphasis-markers t) 781 (cuss org-hide-emphasis-markers t)
973 (cuss org-fontify-done-headline t) 782 (cuss org-fontify-done-headline t)
@@ -989,17 +798,8 @@ I’ve put org mode under Applications, as opposed to Writing, because it’s m
989 (if (and (stringp org-agenda-files) 798 (if (and (stringp org-agenda-files)
990 (not (file-exists-p org-agenda-files))) 799 (not (file-exists-p org-agenda-files)))
991 (with-temp-buffer (write-file org-agenda-files))) 800 (with-temp-buffer (write-file org-agenda-files)))
992 801
993 802 (define-key acdw/map (kbd "C-a") #'org-agenda)
994### Make bullets look like bullets
995
996 (font-lock-add-keywords
997 'org-mode
998 '(("^ *\\([-+]\\) "
999 (0 (prog1 ()
1000 (compose-region (match-beginning 1)
1001 (match-end 1)
1002 "•"))))))
1003 803
1004 804
1005### [A better return in Org mode](http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/) 805### [A better return in Org mode](http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/)
@@ -1076,7 +876,7 @@ I’ve put org mode under Applications, as opposed to Writing, because it’s m
1076 'scimax/org-return) 876 'scimax/org-return)
1077 877
1078 878
1079### Insert blank lines 879### Insert blank lines around headers
1080 880
1081from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#ensure-blank-lines-between-headings-and-before-contents). 881from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#ensure-blank-lines-between-headings-and-before-contents).
1082 882
@@ -1126,172 +926,6 @@ from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#ensure-blank-lin
1126 (add-hook 'before-save-hook #'cribbed/org-mode-fix-blank-lines) 926 (add-hook 'before-save-hook #'cribbed/org-mode-fix-blank-lines)
1127 927
1128 928
1129## Elpher
1130
1131 (use-package elpher
1132 :straight (elpher
1133 :repo "git://thelambdalab.xyz/elpher.git"
1134 :branch "patch_multiple_buffers")
1135
1136 :custom
1137 (elpher-ipv4-always t)
1138
1139 :custom-face
1140 (elpher-gemini-heading1
1141 ((t (:inherit (modus-theme-heading-1)))))
1142 (elpher-gemini-heading2
1143 ((t (:inherit (modus-theme-heading-2)))))
1144 (elpher-gemini-heading3
1145 ((t (:inherit (modus-theme-heading-3)))))
1146
1147 :config
1148 (defun elpher:eww-browse-url (original url &optional new-window)
1149 "Handle gemini/gopher links with eww."
1150 (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
1151 (require 'elpher)
1152 (elpher-go url))
1153 (t (funcall original url new-window))))
1154 (advice-add 'eww-browse-url :around 'elpher:eww-browse-url)
1155
1156 :bind (:map elpher-mode-map
1157 ("n" . elpher-next-link)
1158 ("p" . elpher-prev-link)
1159 ("o" . elpher-follow-current-link)
1160 ("G" . elpher-go-current))
1161
1162 :hook
1163 (elpher-mode-hook . visual-fill-column-mode))
1164
1165
1166### Gemini mode
1167
1168 (use-package gemini-mode
1169 :straight (gemini-mode
1170 :repo "https://git.carcosa.net/jmcbray/gemini.el.git")
1171
1172 :mode "\\.\\(gemini|gmi\\)\\'"
1173
1174 :custom-face
1175 (gemini-heading-face-1
1176 ((t (:inherit (elpher-gemini-heading1)))))
1177 (gemini-heading-face2
1178 ((t (:inherit (elpher-gemini-heading2)))))
1179 (gemini-heading-face3
1180 ((t (:inherit (elpher-gemini-heading3)))))
1181
1182 :init
1183 (defun acdw/setup-gemini-mode ()
1184 (visual-fill-column-mode 1)
1185 (variable-pitch-mode -1))
1186
1187 :hook
1188 (gemini-mode-hook . acdw/setup-gemini-mode))
1189
1190
1191### Gemini write
1192
1193 (use-package gemini-write
1194 :straight (gemini-write
1195 :repo "https://alexschroeder.ch/cgit/gemini-write"))
1196
1197
1198### Ox-gemini
1199
1200 (use-package ox-gemini
1201 :straight (ox-gemini
1202 :repo "https://git.sr.ht/~abrahms/ox-gemini"
1203 :branch "main"))
1204
1205
1206## Pastebin
1207
1208 (straight-use-package '0x0)
1209
1210 (cuss 0x0-default-service 'ttm)
1211
1212
1213## RSS
1214
1215 (use-package newsticker
1216 :custom
1217 (newsticker-url-list
1218 ;; LABEL URL [START-TIME] [INERVAL] [WGET-ARGUMENTS]
1219 '(("wsinatra" "http://lambdacreate.com/static/feed.rss")
1220 ("elioat" "https://eli.li/feed.rss")
1221 ("ACDW" "https://www.acdw.net/atom.xml")
1222 ("june" "https://text.causal.agency/feed.atom")
1223 ("kylie - notes" "https://www.somas.is/notes.atom")
1224 ("kylie - rhizome" "https://www.somas.is/rhizome.atom")
1225 ("brennan" "https://p1k3.com/all.xml")
1226 ("Planet Emacs" "https://planet.emacslife.com/atom.xml")
1227 ("nullprogram, Chris Wellons" "https://nullprogram.com/feed/")
1228 ("Malleable Systems" "https://malleable.systems/blog/index.xml"))
1229 )
1230 :hook
1231 (newsticker-treeview-item-mode-hook . visual-fill-column-mode))
1232
1233
1234## Web browsing
1235
1236
1237### Open youtube links in mpv
1238
1239from [karthinks](https://karthinks.com/software/more-batteries-included-with-emacs/#regexp-builder--m-x-re-builder).
1240
1241 (require 'browse-url)
1242
1243 (when (executable-find "mpv")
1244 (defun browse-url-mpv (url &optional single)
1245 (start-process "mpv" nil (if single "mpv" "umpv")
1246 (shell-quote-wildcard-pattern url)))
1247
1248 (defun browse-url-at-point-mpv (&optional single)
1249 "Open a link in mpv."
1250 (interactive "P")
1251 (let ((browse-url-browser-function
1252 (if single
1253 (lambda
1254 (url &optional _new-window)
1255 (browse-url-mpv url t))
1256 #'browse-url-mpv)))
1257 (browse-url-at-point)))
1258
1259 (cuss browse-url-browser-function
1260 '(("https?:\\/\\/www\\.youtu\\.*be." . browse-url-mpv)
1261 ("." . browse-url-generic))))
1262
1263
1264## Reading e-books
1265
1266 (use-package nov
1267 :mode ("\\.epub\\'" . nov-mode)
1268 :init
1269 (defun acdw/setup-nov-mode ()
1270 (visual-line-mode +1)
1271 (visual-fill-column-mode +1)
1272 (variable-pitch-mode +1)
1273 (setq cursor-type nil))
1274 :config
1275 (cuss nov-text-width t)
1276 :hook
1277 (nov-mode-hook . acdw/setup-nov-mode))
1278
1279
1280## Eshell
1281
1282 (when (executable-find "bash")
1283 (straight-use-package 'bash-completion))
1284
1285 (when (executable-find "fish")
1286 (straight-use-package 'fish-completion)
1287 (require 'fish-completion)
1288 (cuss fish-completion-fallback-on-bash-p (executable-find "bash"))
1289 (global-fish-completion-mode +1)
1290
1291 (straight-use-package 'fish-mode)
1292 (add-to-list 'auto-mode-alist '("\\.fish\\'" . fish-mode)))
1293
1294
1295# Appendices 929# Appendices
1296 930
1297 931
@@ -1300,40 +934,24 @@ from [karthinks](https://karthinks.com/software/more-batteries-included-with-ema
1300 934
1301### init.el 935### init.el
1302 936
1303 ;; init.el -*- lexical-binding: t -*- 937I realized I didn’t need `early-init.el`, since it really only set `load-prefer-newer`. So I’ve set that here, and wrapped the actual loading of config in a `let*` form that speeds up init, and loads the newer of either `config.org` or `config.el`.
1304
13051. Speed up init
1306
1307 (setq gc-cons-threshold most-positive-fixnum)
1308 (defvar old-file-name-handler file-name-handler-alist)
1309 (setq file-name-handler-alist nil)
1310
13112. Load config
1312
1313 inspired by [Protesilaos Stavrou](https://protesilaos.com/dotemacs/#h:584c3604-55a1-49d0-9c31-abe46cb1f028).
1314
1315 (let* ((conf (expand-file-name "config"
1316 user-emacs-directory))
1317 (conf-el (concat conf ".el"))
1318 (conf-org (concat conf ".org")))
1319 (unless (and (file-newer-than-file-p conf-el conf-org)
1320 (load conf 'no-error))
1321 (require 'org)
1322 (org-babel-load-file conf-org)))
1323 938
13243. Reset for normal operation 939 ;; init.el -*- lexical-binding: t -*-
1325
1326 (setq gc-cons-threshold 16777216 ; 16mb
1327 gc-cons-percentage 0.1
1328 file-name-handler-alist old-file-name-handler)
1329
1330
1331### early-init.el
1332
1333 ;; early-init.el -*- lexical-binding: t; no-byte-compile: t; -*-
1334 940
1335 (setq load-prefer-newer t) 941 (setq load-prefer-newer t)
1336 (setq frame-inhibit-implied-resize t) 942
943 (let* (;; Speed up init
944 (gc-cons-threshold most-positive-fixnum)
945 (file-name-handler-alist nil)
946 ;; Config file names
947 (conf (expand-file-name "config"
948 user-emacs-directory))
949 (conf-el (concat conf ".el"))
950 (conf-org (concat conf ".org")))
951 (unless (and (file-newer-than-file-p conf-el conf-org)
952 (load conf 'no-error))
953 (require 'org)
954 (org-babel-load-file conf-org)))
1337 955
1338 956
1339## Ease tangling and loading of Emacs' init 957## Ease tangling and loading of Emacs' init
@@ -1350,34 +968,33 @@ from [karthinks](https://karthinks.com/software/more-batteries-included-with-ema
1350 (when (file-newer-than-file-p config (expand-file-name 968 (when (file-newer-than-file-p config (expand-file-name
1351 "README.md" 969 "README.md"
1352 user-emacs-directory)) 970 user-emacs-directory))
971 (message "Exporting README.md...")
1353 (require 'ox-md) 972 (require 'ox-md)
1354 (org-md-export-to-markdown)) 973 (with-demoted-errors "Problem exporting README.md: %S"
974 (org-md-export-to-markdown)))
1355 ;; tangle config.org 975 ;; tangle config.org
1356 (when (file-newer-than-file-p config (expand-file-name 976 (when (file-newer-than-file-p config (expand-file-name
1357 "config.el" 977 "config.el"
1358 user-emacs-directory)) 978 user-emacs-directory))
979 (message "Tangling config.org...")
1359 (require 'org) 980 (require 'org)
1360 (let ((inits (org-babel-tangle))) 981 (let ((inits (org-babel-tangle)))
1361 ;; byte-compile resulting files 982 ;; byte-compile resulting files
983 (message "Byte-compiling...")
1362 (dolist (f inits) 984 (dolist (f inits)
1363 (when (string-match "\\.el\\'" f) 985 (when (string-match "\\.el\\'" f)
1364 (byte-compile-file f (not disable-load))))))))))) 986 (byte-compile-file f (not disable-load)))))))))))
1365 987
1366 988
1367### Add a hook to tangle when quitting
1368
1369 (defun acdw/refresh-emacs-no-load ()
1370 (refresh-emacs 'disable-load))
1371
1372 (add-hook 'kill-emacs-hook #'acdw/refresh-emacs-no-load)
1373
1374
1375## Ancillary scripts 989## Ancillary scripts
1376 990
1377 991
1378### emacsdc 992### emacsdc
1379 993
1380Here’s a wrapper script that’ll start `emacs –daemon` if there isn’t one, and then launch `emacsclient` with the arguments. I’d recommend installing with either `ln -s bin/emacsdc $HOME/.local/bin/`, or adding `$HOME/.local/bin` to your `$PATH`. 994Here's a wrapper script that'll start `emacs –daemon` if there isn't
995one, and then launch `emacsclient` with the arguments. I'd recommend
996installing with either `ln -s bin/emacsdc $HOME/.local/bin/`, or
997adding `$HOME/.local/bin` to your `$PATH`.
1381 998
1382 if ! emacsclient -nc "$@" 2>/dev/null; then 999 if ! emacsclient -nc "$@" 2>/dev/null; then
1383 emacs --daemon 1000 emacs --daemon
@@ -1385,6 +1002,14 @@ Here’s a wrapper script that’ll start `emacs –daemon` if there isn’t one
1385 fi 1002 fi
1386 1003
1387 1004
1005### Emacs.cmd
1006
1007Here’s a wrapper script that’ll run Emacs on Windows, with a custom `$HOME`. I have mine setup like this: Emacs is downloaded from [the GNU mirror](https://mirrors.tripadvisor.com/gnu/emacs/windows/emacs-27/emacs-27.1-x86_64.zip) and unzipped to `~/Downloads/emacs/`. `Emacs.cmd` sets `$HOME` to `~/Downloads/emacshome/`, which is where `.emacs.d` is, and whatever else I might want to throw in there.
1008
1009 set HOME=%~dp0..\..\emacshome
1010 "%~dp0runemacs.exe" %*
1011
1012
1388## License 1013## License
1389 1014
1390Copyright © 2020 Case Duckworth <acdw@acdw.net> 1015Copyright © 2020 Case Duckworth <acdw@acdw.net>
diff --git a/config.org b/config.org index 8446fe9..2b9671d 100644 --- a/config.org +++ b/config.org
@@ -1,435 +1,350 @@
1#+TITLE: Emacs, emacs, emacs 1#+TITLE: Emacs, emacs, emacs
2#+AUTHOR: Case Duckworth 2#+AUTHOR: Case Duckworth
3#+PROPERTY: header-args :tangle config.el :comments both :mkdirp yes 3#+PROPERTY: header-args :tangle config.el :comments both :mkdirp yes
4#+STARTUP:
4#+EXPORT_FILE_NAME: README.md 5#+EXPORT_FILE_NAME: README.md
5#+OPTIONS: toc:nil 6#+OPTIONS: toc:nil
6#+BANKRUPTCY_COUNT: 3 7#+BANKRUPTCY_COUNT: 3.2
7#+Time-stamp: <2020-12-23 20:27:53 acdw> 8#+Time-stamp: <2020-12-30 23:33:02 acdw>
8 9
9Let’s configure Emacs using Org mode, they said. It’ll be fun, they said. 10Why the hell not, let’s do this again.
10 11
11* Pave the way 12* Basics
13
14** About me
15
16#+BEGIN_SRC emacs-lisp
17(setq user-full-name "Case Duckworth"
18 user-mail-address "acdw@acdw.net")
19#+END_SRC
12 20
13** Correct =exec-path= 21** Correct =exec-path=
14 22
15 #+begin_src emacs-lisp 23Straight depends on Git, so I need to tell Emacs where different paths are.
16 (let ((win-downloads "c:/Users/aduckworth/Downloads")) 24
17 (dolist (path (list 25#+BEGIN_SRC emacs-lisp
18 ;; Linux 26(let ((win-downloads "c:/Users/aduckworth/Downloads"))
19 (expand-file-name "bin" 27 (dolist (path (list
20 user-emacs-directory) 28 ;; Linux
21 (expand-file-name "~/bin") 29 (expand-file-name "bin"
22 (expand-file-name "~/.local/bin") 30 user-emacs-directory)
23 (expand-file-name "~/Scripts") 31 (expand-file-name "~/bin")
24 ;; Windows 32 (expand-file-name "~/.local/bin")
25 (expand-file-name "emacs/bin" 33 (expand-file-name "~/Scripts")
26 win-downloads) 34 ;; Windows
27 (expand-file-name "m/usr/bin" 35 (expand-file-name "emacs/bin"
28 win-downloads) 36 win-downloads)
29 (expand-file-name "m/mingw64/bin" 37 (expand-file-name "m/usr/bin"
30 win-downloads) 38 win-downloads)
31 (expand-file-name "PortableGit/bin" 39 (expand-file-name "m/mingw64/bin"
32 win-downloads) 40 win-downloads)
33 (expand-file-name "PortableGit/usr/bin" 41 (expand-file-name "PortableGit/bin"
34 win-downloads))) 42 win-downloads)
35 (when (file-exists-p path) 43 (expand-file-name "PortableGit/usr/bin"
36 (add-to-list 'exec-path path)))) 44 win-downloads)))
37 #+end_src 45 (when (file-exists-p path)
46 (add-to-list 'exec-path path))))
47#+END_SRC
38 48
39** Package management 49** Package management
40 50
41*** Straight.el 51*** Straight.el
42 52
43Since for whatever reason, Straight can't bootstrap itself on Windows 53Straight can't bootstrap itself on Windows, so I've wrapped the
44-- I've wrapped it in a function here and added the direct git command 54bootstrap code from straight's repo in a function.
45when it errors.
46
47 #+begin_src emacs-lisp
48 (defun acdw/bootstrap-straight ()
49 (defvar bootstrap-version)
50 (let ((bootstrap-file
51 (expand-file-name
52 "straight/repos/straight.el/bootstrap.el"
53 user-emacs-directory))
54 (bootstrap-version 5))
55 (unless (file-exists-p bootstrap-file)
56 (with-current-buffer
57 (url-retrieve-synchronously
58 (concat "https://raw.githubusercontent.com/"
59 "raxod502/straight.el/develop/install.el")
60 'silent 'inhibit-cookies)
61 (goto-char (point-max))
62 (eval-print-last-sexp)))
63 (load bootstrap-file nil 'nomessage)))
64
65 (unless (ignore-errors (acdw/bootstrap-straight))
66 (message "Straight.el didn't bootstrap correctly. Cloning directly...")
67 (call-process "git" nil (get-buffer-create "*bootstrap-straight-messages*") nil
68 "clone"
69 "https://github.com/raxod502/straight.el"
70 (expand-file-name "straight/repos/straight.el"
71 user-emacs-directory))
72 (acdw/bootstrap-straight))
73 #+end_src
74
75** Customize variables
76
77*** Put customizations in a separate file
78
79 #+begin_src emacs-lisp
80 (setq custom-file
81 (expand-file-name "custom.el" user-emacs-directory))
82 #+end_src
83
84*** A macro for ease of customization
85
86 #+begin_src emacs-lisp
87 (defmacro cuss (var val &optional docstring)
88 "Basically `:custom' from `use-package', broken out."
89 (declare (indent 2)
90 (doc-string 3))
91 `(funcall (or (get ',var 'custom-set) #'set-default)
92 ',var ,val))
93 #+end_src
94
95** Keep a tidy =~/.emacs=
96 55
97#+begin_src emacs-lisp 56#+BEGIN_SRC emacs-lisp
98 (straight-use-package 'no-littering) 57(defun acdw/bootstrap-straight ()
99 58 "Bootstrap straight.el."
100 (cuss backup-directory-alist 59 (defvar bootstrap-version)
101 `((".*" . ,(no-littering-expand-var-file-name "backup/"))) 60 (let ((bootstrap-file
102 "Where to store backup files.") 61 (expand-file-name
103 62 "straight/repos/straight.el/bootstrap.el"
104 (cuss auto-save-file-name-transforms 63 user-emacs-directory))
105 `((".*" ,(no-littering-expand-var-file-name "autosaves/") t)) 64 (bootstrap-version 5))
106 "Where to store auto-save files.") 65 (unless (file-exists-p bootstrap-file)
107 66 (with-current-buffer
108 (cuss save-place-file 67 (url-retrieve-synchronously
109 (no-littering-expand-var-file-name "places") 68 (concat
110 "Where to store place files.") 69 "https://raw.githubusercontent.com/"
111 70 "raxod502/straight.el/"
112 (cuss undo-fu-session-directory 71 "develop/install.el")
113 (no-littering-expand-var-file-name "undos/") 72 'silent 'inhibit-cookies)
114 "Where to store undo information.") 73 (goto-char (point-max))
115 74 (eval-print-last-sexp)))
116 (cuss elpher-certificate-directory 75 (load bootstrap-file nil 'nomessage)))
117 (no-littering-expand-var-file-name "elpher-certificates/") 76#+END_SRC
118 "Where to store elpher client certificates.")
119
120 ;; Make all directories defined above
121 (dolist (dir '("backup"
122 "autosaves"
123 "undos"
124 "elpher-certificates"))
125 (make-directory (no-littering-expand-var-file-name dir) 'parents))
126#+end_src
127 77
128** About me 78Now, I'll /try/ running it regular-style, ignoring the errors. If it
79doesn't work, I'll call git directly and clone the repo myself.
129 80
130#+begin_src emacs-lisp 81#+BEGIN_SRC emacs-lisp
131 (setq user-full-name "Case Duckworth" 82(unless (ignore-errors (acdw/bootstrap-straight))
132 user-mail-address "acdw@acdw.net") 83 (message "Straight.el didn't bootstrap correctly. Cloning directly...")
133#+end_src 84 (call-process "git" nil
85 (get-buffer-create "*bootstrap-straight-messages*") nil
86 "clone"
87 "https://github.com/raxod502/straight.el"
88 (expand-file-name "straight/repos/straight.el"
89 user-emacs-directory))
90 (acdw/bootstrap-straight))
91#+END_SRC
134 92
135* Look and Feel 93** Customize macro
136 94
137** Simplify the UI 95#+BEGIN_SRC emacs-lisp
96(defmacro cuss (var val &optional docstring)
97 "Basically, `:custom' from `use-package', but without `use-package'."
98 (declare (doc-string 3)
99 (indent 2))
100 `(funcall (or (get ',var 'custom-set) #'set-default)
101 ',var ,val))
102#+END_SRC
138 103
139*** Tool bars and menu bars 104** Clean =.emacs.d=
140 105
141#+begin_src emacs-lisp 106#+BEGIN_SRC emacs-lisp
142 (cuss default-frame-alist 107(straight-use-package 'no-littering)
143 '((tool-bar-lines . 0) 108(require 'no-littering)
144 (menu-bar-lines . 0)) 109#+END_SRC
145 "On a default frame, show no tool bars or menu bars.")
146 110
147 (menu-bar-mode -1) 111** Look and feel
148 (tool-bar-mode -1)
149#+end_src
150 112
151*** Scroll bars 113*** Cursor
152 114
153#+begin_src emacs-lisp 115#+BEGIN_SRC emacs-lisp
154 (add-to-list 'default-frame-alist '(vertical-scroll-bars . nil)) 116(cuss cursor-type 'bar
155 (scroll-bar-mode -1) 117 "Show a vertical bar for the cursor.")
156 118
157 (add-to-list 'default-frame-alist '(horizontal-scroll-bars . nil)) 119(cuss cursor-in-non-selected-windows 'hollow
158 (horizontal-scroll-bar-mode -1) 120 "Show an empty box in inactive windows.")
159#+end_src
160 121
161*** Dialog boxen 122;; Don't blink the cursor
123(blink-cursor-mode -1)
124#+END_SRC
162 125
163#+begin_src emacs-lisp 126*** Tool Bars
164 (cuss use-dialog-box nil
165 "Don't show dialog boxes.")
166#+end_src
167 127
168*** Shorten confirmations 128**** Tool bars and menu bars
169 129
170#+begin_src emacs-lisp 130#+BEGIN_SRC emacs-lisp
171 (fset 'yes-or-no-p #'y-or-n-p) 131(cuss default-frame-alist
172#+end_src 132 '((tool-bar-lines . 0)
133 (menu-bar-lines .0))
134 "Setup the default frame alist.")
173 135
174*** Remove the bell 136(menu-bar-mode -1)
137(tool-bar-mode -1)
138#+END_SRC
175 139
176#+begin_src emacs-lisp 140**** Scroll bars
177 ;(cuss visible-bell
178 ; (not (string= (system-name) "larry"))
179 ; "Only show a visible bell when on 'larry'.")
180
181 (defun acdw/ring-bell-function ()
182 "Custom bell-ringing function."
183 (let ((orig-face (face-foreground 'mode-line)))
184 (set-face-foreground 'modeline "#F2804F")
185 (run-with-idle-timer
186 0.1 nil
187 (lambda (fg)
188 (set-face-foreground 'mode-line fg))
189 orig-face)))
190
191 (cuss ring-bell-function #'acdw/ring-bell-function)
192#+end_src
193 141
194*** Tell Ediff to setup windows better 142#+BEGIN_SRC emacs-lisp
143(add-to-list 'default-frame-alist
144 '(vertical-scroll-bars . nil))
195 145
196#+begin_src emacs-lisp 146(scroll-bar-mode -1)
197 (declare-function ediff-setup-windows-plain "ediff-wind.el")
198 (cuss ediff-window-setup-function #'ediff-setup-windows-plain)
199#+end_src
200 147
201** Tweak the remaining UI 148(add-to-list 'default-frame-alist
149 '(horizontal-scroll-bars . nil))
202 150
203*** Fringes 151(horizontal-scroll-bar-mode -1)
152#+END_SRC
204 153
205#+begin_src emacs-lisp 154*** Dialogs
206 (add-to-list 'default-frame-alist '(left-fringe-width . 2))
207 (add-to-list 'default-frame-alist '(right-fringe-width . 2))
208#+end_src
209 155
210*** Minibuffer 156#+BEGIN_SRC emacs-lisp
157(cuss use-dialog-box nil
158 "Don't use dialog boxes to ask questions.")
159#+END_SRC
211 160
212**** Setup the minibuffer frame 161**** Yes or no questions
213 162
214#+begin_src emacs-lisp 163#+BEGIN_SRC emacs-lisp
215 (cuss minibuffer-frame-alist 164(fset 'yes-or-no-p #'y-or-n-p)
216 '((width . 80) 165#+END_SRC
217 (height . 2)
218 (vertical-scrollbars . nil))
219 "Set up the minibuffer frame.")
220 166
221 (set-window-scroll-bars (minibuffer-window) nil nil) 167**** The Bell
222#+end_src
223 168
224**** Keep the cursor from going into the prompt 169#+BEGIN_SRC emacs-lisp
170(defun acdw/ring-bell-function ()
171 "Ring the bell."
172 (let ((orig-face (face-foreground 'mode-line)))
173 (set-face-foreground 'mode-line "#F2804F")
174 (run-with-idle-timer
175 0.1 nil
176 (lambda (fg)
177 (set-face-foreground 'mode-line fg))
178 orig-face)))
179
180(cuss ring-bell-function #'acdw/ring-bell-function)
181#+END_SRC
225 182
226#+begin_src emacs-lisp 183*** Frames
227 (cuss minibuffer-prompt-properties
228 '(read-only t cursor-intangible t face minibuffer-prompt)
229 "Disable moving the cursor into the minibuffer prompt.")
230#+end_src
231 184
232*** Tabs 185**** Fringes
233 186
234**** Show the tabs as current buffer, plus window count 187#+BEGIN_SRC emacs-lisp
188(cuss indicate-empty-lines t
189 "Show an indicator on the left fringe of empty lines past the
190end of the buffer.")
191(cuss indicate-buffer-boundaries 'right
192 "Indicate the beginning and end of the buffer and whether it
193 scrolls off-window in the right fringe.")
194#+END_SRC
235 195
236#+begin_src emacs-lisp 196**** Minibuffer
237 (cuss tab-bar-tab-name-function
238 #'tab-bar-tab-name-current-with-count)
239#+end_src
240 197
241**** Only show the tab bar when there's more than one tab 198#+BEGIN_SRC emacs-lisp
199(cuss minibuffer-prompt-properties
200 '(read-only t cursor-intangible t face minibuffer-prompt)
201 "Keep the cursor away from the minibuffer prompt.")
202#+END_SRC
242 203
243#+begin_src emacs-lisp 204**** Tabs
244 (cuss tab-bar-show 1
245 "Show the tab bar only when there's more than 1 tab.")
246#+end_src
247 205
248*** Cursor 206#+BEGIN_SRC emacs-lisp
207(cuss tab-bar-tab-name-function
208 #'tab-bar-tab-name-current-with-count
209 "Show the tab name as the name of the current buffer, plus a
210 count of the windows in the tab.")
249 211
250#+begin_src emacs-lisp 212(cuss tab-bar-show 1
251 (cuss cursor-type 'bar 213 "Show the tab bar, when there's more than one tab.")
252 "Show a vertical bar for the cursor.") 214#+END_SRC
253 (cuss cursor-in-non-selected-windows 'hollow
254 "In inactive windows, make the cursor an empty box.")
255 215
256 (blink-cursor-mode 0) 216*** Windows
257#+end_src
258 217
259*** Buffer names 218**** Winner mode
260 219
261#+begin_src emacs-lisp 220#+BEGIN_SRC emacs-lisp
262 (require 'uniquify) 221(when (fboundp 'winner-mode)
263 (cuss uniquify-buffer-name-style 'forward) 222 (winner-mode +1))
264#+end_src 223#+END_SRC
265 224
266*** Buffer boundaries 225**** Switch windows
267 226
268#+begin_src emacs-lisp 227#+BEGIN_SRC emacs-lisp
269 (cuss indicate-buffer-boundaries 228(global-set-key (kbd "M-o") #'other-window)
270 '((up . right) 229#+END_SRC
271 (down . right)
272 (t . nil))
273 "Show arrows on the right when there's more to the buffer up or down.")
274
275 (cuss indicate-empty-lines t
276 "Show a bitmap on the left for empty lines after the end of a buffer.")
277#+end_src
278 230
279** Windows 231*** Buffers
280 232
281*** Winner mode 233**** Uniquify buffers
282 234
283#+begin_src emacs-lisp 235#+BEGIN_SRC emacs-lisp
284 (when (fboundp 'winner-mode) 236(require 'uniquify)
285 (winner-mode +1)) 237(cuss uniquify-buffer-name-style 'forward
286#+end_src 238 "Uniquify buffers' names by going up the path trees until they
239become unique.")
240#+END_SRC
287 241
288*** Windmove 242**** Startup buffers
289 243
290 #+begin_src emacs-lisp 244#+BEGIN_SRC emacs-lisp
291 (cuss windmove-create-window t 245(cuss inhibit-startup-screen t
292 "Create windows in a direction if they don't exist.") 246 "Don't show Emacs' startup buffer.")
293 (cuss windomove-wrap-around t
294 "Wrap window movements around frame edges.")
295 247
296 (windmove-default-keybindings) 248(cuss initial-buffer-choice t
297 #+end_src 249 "Start with *scratch*.")
298 250
299*** Pop some buffers up in the same window 251(cuss initial-scratch-message ""
252 "Empty *scratch* buffer.")
253#+END_SRC
300 254
301from [[https://github.com/link0ff/emacs-init][link0ff]]. 255*** Modeline
302 256
303#+begin_src emacs-lisp 257**** Smart mode line
304 (push `(,(rx bos
305 "*"
306 (or "Help" "Apropos" "Colors" "Buffer List" "Command History"
307 "Dictionary" "Locate" "Messages" "Proced" "eww" "snd"
308 (and "gud-" (+ (any "a-z0-9")))
309 "compilation" "grep" "erlang" "haskell"
310 ;; Handle both "*shell*" and e.g. "*emacs-shell*"
311 ;; generated by `project-shell':
312 (and (? (* nonl) "-") "shell")
313 "Shell Command Output"
314 (and "SQL: " (+ (any "A-za-z")))
315 "Diff" "vc-dir" "vc-log" "vc-search-log")
316 "*"
317 ;; Uniquifed buffer name with optional suffix in angle brackets
318 (? (and "<" (+ (not (any ">"))) ">"))
319 eos)
320 display-buffer-same-window
321 (inhibit-same-window . nil))
322 display-buffer-alist)
323
324 (defun display-buffer-from-help-p (_buffer-name _action)
325 (unless current-prefix-arg
326 (with-current-buffer (window-buffer)
327 (eq major-mode 'help-mode))))
328
329 (push '(display-buffer-from-help-p display-buffer-same-window)
330 display-buffer-alist)
331#+end_src
332 258
333** Startup 259 #+BEGIN_SRC emacs-lisp
260 (straight-use-package 'smart-mode-line)
334 261
335#+begin_src emacs-lisp 262 (cuss sml/no-confirm-load-theme t
336 (cuss inhibit-startup-screen t "Don't show Emacs' startup buffer.") 263 "Pass the NO-CONFIRM flag to `load-theme'.")
337 (cuss initial-buffer-choice t "Start at *scratch*.")
338 (cuss initial-scratch-message "" "Empty *scratch*.")
339#+end_src
340 264
341** Theme 265 (sml/setup)
266 #+END_SRC
342 267
343#+begin_src emacs-lisp 268**** Rich minority
344 (straight-use-package '(modus-themes
345 :host gitlab
346 :repo "protesilaos/modus-themes"
347 :branch "main"))
348
349 (cuss modus-themes-slanted-constructs t)
350 (cuss modus-themes-bold-constructs t)
351 (cuss modus-themes-fringes nil)
352 (cuss modus-themes-mode-line '3d)
353 (cuss modus-themes-syntax 'yellow-comments)
354 (cuss modus-themes-intense-hl-line nil)
355 (cuss modus-themes-paren-match 'intense-bold)
356 (cuss modus-themes-links nil)
357 (cuss modus-themes-no-mixed-fonts nil)
358 (cuss modus-themes-prompts nil)
359 (cuss modus-themes-completions nil)
360 (cuss modus-themes-diffs nil)
361 (cuss modus-themes-org-blocks 'grayscale)
362 (cuss modus-themes-headings
363 '((1 . line)
364 (t . t)))
365 (cuss modus-themes-variable-pitch-headings t)
366 (cuss modus-themes-scale-headings t)
367 (cuss modus-themes-scale-1 1.1)
368 (cuss modus-themes-scale-2 1.15)
369 (cuss modus-themes-scale-3 1.21)
370 (cuss modus-themes-scale-4 1.27)
371 (cuss modus-themes-scale-5 1.33)
372
373 ;; :custom-face
374 (custom-set-faces `(font-lock-comment-face
375 ((t (:inherit (custom-comment italic variable-pitch))))))
376
377 (load-theme 'modus-operandi t)
378#+end_src
379 269
380*** Change theme based on time of day 270 Since this /comes/ with smart mode line, I’m just going to use it,
271 instead of =diminish= or another package. I do have to write this
272 helper function, though, to add things to the whitelist.
381 273
382#+begin_src emacs-lisp 274 #+BEGIN_SRC emacs-lisp
383 (cuss calendar-latitude 30.4515) 275 (defun rm/whitelist-add (regexp)
384 (cuss calendar-longitude -91.1871) 276 "Add a REGEXP to the whitelist for `rich-minority'."
277 (if (listp 'rm--whitelist-regexps)
278 (add-to-list 'rm--whitelist-regexps regexp)
279 (setq rm--whitelist-regexps `(,regexp)))
280 (setq rm-whitelist
281 (mapconcat 'identity rm--whitelist-regexps "\\|")))
385 282
386 (straight-use-package 'circadian) 283 (straight-use-package 'rich-minority)
387 284
388 (cuss circadian-themes '((:sunrise . modus-operandi) 285 (rm/whitelist-add "^$")
389 (:sunset . modus-vivendi))) 286 #+END_SRC
390 287
391 (circadian-setup) 288*** Theme
392#+end_src
393 289
394*** Modeline 290**** Modus Themes
395 291
396#+begin_src emacs-lisp 292#+BEGIN_SRC emacs-lisp
397 (straight-use-package 'smart-mode-line) 293(straight-use-package 'modus-themes)
398 (cuss sml/no-confirm-load-theme t) 294
399 (sml/setup) 295(cuss modus-themes-slanted-constructs t
400#+end_src 296 "Use more slanted constructs.")
297(cuss modus-themes-bold-constructs t
298 "Use more bold constructs.")
299
300(cuss modus-themes-region 'bg-only
301 "Only highlight the background of the selected region.")
302
303(cuss modus-themes-org-blocks 'grayscale
304 "Show org-blocks with a grayscale background.")
305(cuss modus-themes-headings
306 '((1 . line)
307 (t . t))
308 "Highlight top headings with `line' style, and others by default.")
309
310(cuss modus-themes-scale-headings t
311 "Scale headings by the ratios below.")
312(cuss modus-themes-scale-1 1.1)
313(cuss modus-themes-scale-2 1.15)
314(cuss modus-themes-scale-3 1.21)
315(cuss modus-themes-scale-4 1.27)
316(cuss modus-themes-scale-5 1.33)
317
318(load-theme 'modus-operandi t)
319#+END_SRC
401 320
402**** Rich minority 321**** Change themes based on time of day
403 322
404Since this /comes/ with smart mode line, I’m just going to use it, instead of =diminish= or another package. I do have to write this helper function, though, to add things to the whitelist. 323#+BEGIN_SRC emacs-lisp
324(cuss calendar-latitude 30.4515)
325(cuss calendar-longitude -91.1871)
405 326
406#+begin_src emacs-lisp 327(straight-use-package 'circadian)
407 (defun rm/whitelist-add (regexp)
408 "Add a REGEXP to the whitelist for `rich-minority'."
409 (if (listp 'rm--whitelist-regexps)
410 (add-to-list 'rm--whitelist-regexps regexp)
411 (setq rm--whitelist-regexps `(,regexp)))
412 (setq rm-whitelist
413 (mapconcat 'identity rm--whitelist-regexps "\\|")))
414 328
415 (straight-use-package 'rich-minority) 329(cuss circadian-themes '((:sunrise . modus-operandi)
330 (:sunset . modus-vivendi)))
416 331
417 (rm/whitelist-add "^$") 332(circadian-setup)
418#+end_src 333#+END_SRC
419 334
420*** Fonts 335*** Fonts
421 336
422**** Define fonts 337**** Define fonts
423 338
424#+begin_src emacs-lisp 339#+BEGIN_SRC emacs-lisp
425 (defun set-face-from-alternatives (face fonts) 340 (defun set-face-from-alternatives (face fonts)
426 (catch :return 341 (catch :return
427 (dolist (font fonts) 342 (dolist (font fonts)
428 (when (find-font (font-spec :family (car font))) 343 (when (find-font (font-spec :family (car font)))
429 (apply #'set-face-attribute `(,face nil 344 (apply #'set-face-attribute `(,face nil
430 :family ,(car font) 345 :family ,(car font)
431 ,@(cdr font))) 346 ,@(cdr font)))
432 (throw :return font))))) 347 (throw :return font)))))
433 348
434 (defun acdw/setup-fonts () 349 (defun acdw/setup-fonts ()
435 "Setup fonts. This has to happen after the frame is setup for 350 "Setup fonts. This has to happen after the frame is setup for