summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--config.org913
1 files changed, 540 insertions, 373 deletions
diff --git a/config.org b/config.org index ac18133..b27fb35 100644 --- a/config.org +++ b/config.org
@@ -1,143 +1,27 @@
1#+TITLE: Emacs configuration, literate-style 1#+TITLE: Emacs configuration, literate-style
2#+AUTHOR: Case Duckworth 2#+AUTHOR: Case Duckworth
3#+PROPERTY: header-args :tangle yes :tangle-mode (identity #o444) :comments both
4 3
5* Settings 4* About me
6 5
7Basic settings necessary for a decent editing experience in Emacs. 6#+begin_src emacs-lisp :noweb-ref settings
8These should not require non-built-in packages.
9
10** Prelude
11
12*** Enable lexical binding
13
14#+begin_src emacs-lisp :comments no
15 ;; config.el -*- lexical-binding: t -*-
16#+end_src
17
18*** Disclaimer
19
20#+NAME: disclaimer
21#+begin_src emacs-lisp :comments no
22 ;; This file is automatically tangled from config.org.
23 ;; Hand edits will be overwritten!
24#+end_src
25
26** Customization
27
28*** Emulate use-package's =:custom=
29
30#+begin_src emacs-lisp
31 (defmacro cuss (var val &optional _docstring)
32 "`use-package''s `:custom', without `use-package'."
33 (declare (doc-string 3)
34 (indent 2))
35 `(funcall (or (get ',var 'custom-set) #'set-default)
36 ',var ,val))
37#+end_src
38
39*** Emulate use-package's =:custom-face=
40
41#+begin_src emacs-lisp
42 (defvar acdw--custom-faces ()
43 "List of custom faces to run through `acdw/set-custom-faces'.")
44
45 (defun acdw/set-custom-faces ()
46 "Customize faces using `customize-set-faces'.
47
48 I only want to run this once, per the documentation of `customize-set-faces'."
49 (when acdw--custom-faces
50 (let ((msg "Customizing faces"))
51 (message "%s..." msg)
52 (apply #'custom-set-faces acdw--custom-faces)
53 (message "%s...Done." msg)
54 (remove-function after-focuse-change-function #'acdw/set-custom-faces))))
55
56 (add-function :before after-focus-change-function #'acdw/set-custom-faces)
57
58 (defmacro cussface (face spec &optional _docstring)
59 "Add the form (FACE SPEC) to `acdw--custom-faces'."
60 (declare (doc-string 3)
61 (indent defun))
62 `(add-to-list 'acdw--custom-faces '(,face ,spec)))
63#+end_src
64
65*** Only do something when Emacs is unfocused
66
67Since Emacs is single-threaded, I only want to run really expensive
68operations when I won't notice, say .. when I'm focused on another
69window.
70
71#+begin_src emacs-lisp
72 (defun when-unfocused (func &rest args)
73 "Run FUNC with ARGS iff all frames are out of focus."
74 (when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list)))
75 (apply func args)))
76#+end_src
77
78*** Throw customizations away
79
80I use Emacs's Customize interface, but really only to learn about what
81options a package presents to /be/ customized. I don't want to use
82the custom file for anything at all.
83
84#+begin_src emacs-lisp
85 (cuss custom-file null-device)
86#+end_src
87
88** About me
89
90My name and email address.
91
92#+begin_src emacs-lisp
93 (setq user-full-name "Case Duckworth" 7 (setq user-full-name "Case Duckworth"
94 user-mail-address "acdw@acdw.net") 8 user-mail-address "acdw@acdw.net")
95#+end_src 9#+end_src
96 10
97** Look and feel 11* Look and feel
98
99*** Cursor
100
101#+begin_src emacs-lisp
102 ;; Show a vertical bar cursor
103 (cuss cursor-type 'bar)
104
105 ;; Hide the cursor in other windows
106 (cuss cursor-in-non-selected-windows nil)
107
108 ;; Don't blink the cursor
109 (blink-cursor-mode -1)
110#+end_src
111
112*** Tabs
113
114**** Tab names should be current buffer + a count of windows
115
116#+begin_src emacs-lisp
117 (cuss tab-bar-tab-name-function
118 #'tab-bar-tab-name-current-with-count)
119#+end_src
120
121**** Only show the tab bar when there's more than one tab
122
123For some reason, this doesn't work with multiple frames.
124
125#+begin_src emacs-lisp
126 (cuss tab-bar-show 1)
127#+end_src
128
129*** Frames
130 12
131/Frames/ are Emacs's concepts that generally correspond to other 13** Frames
132programs' /windows/ -- that is, they're the boxen on the screen that
133contain the Emacs programmen.
134 14
135**** Initial frame setup 15*** Initial frame setup
136:PROPERTIES: 16:PROPERTIES:
137:header-args: :noweb-ref initial-frame-setup 17:header-args: :noweb-ref initial-frame-setup
138:END: 18:END:
139 19
140***** Tool bar 20I tangle this section to =early-init.el=, since that's evaluated
21before GUI set-up. Which, in turn, means Emacs will skip the "flash
22of unstyled content" thing.
23
24**** Tool bar
141 25
142#+begin_src emacs-lisp 26#+begin_src emacs-lisp
143 (add-to-list 'default-frame-alist 27 (add-to-list 'default-frame-alist
@@ -146,7 +30,7 @@ contain the Emacs programmen.
146 (tool-bar-mode -1) 30 (tool-bar-mode -1)
147#+end_src 31#+end_src
148 32
149***** Menu bar 33**** Menu bar
150 34
151#+begin_src emacs-lisp 35#+begin_src emacs-lisp
152 (add-to-list 'default-frame-alist 36 (add-to-list 'default-frame-alist
@@ -155,7 +39,7 @@ contain the Emacs programmen.
155 (menu-bar-mode -1) 39 (menu-bar-mode -1)
156#+end_src 40#+end_src
157 41
158***** Scroll bars 42**** Scroll bars
159 43
160#+begin_src emacs-lisp 44#+begin_src emacs-lisp
161 (add-to-list 'default-frame-alist 45 (add-to-list 'default-frame-alist
@@ -166,44 +50,44 @@ contain the Emacs programmen.
166 (horizontal-scroll-bar-mode -1) 50 (horizontal-scroll-bar-mode -1)
167#+end_src 51#+end_src
168 52
169**** Frame titles 53*** Frame titles
170
171Set the frame title to something more useful than the default: include
172the current buffer and the current filename.
173 54
174#+begin_src emacs-lisp 55#+begin_src emacs-lisp :noweb-ref settings
175 (cuss frame-title-format 56 (setq-default frame-title-format
176 (concat invocation-name "@" (system-name) 57 (concat invocation-name "@" (system-name)
177 ": %b %+%+ %f")) 58 ": %b %+%+ %f"))
178#+end_src 59#+end_src
179 60
180**** Fringes 61*** Fringes
62:PROPERTIES:
63:header-args: :noweb-ref settings
64:END:
181 65
182I have grown to love Emacs's little fringes on the side of the 66I have grown to love Emacs's little fringes on the side of the
183windows. In fact, I love them so much that I really went overboard 67windows. In fact, I love them so much that I really went overboard
184and have made a custom fringe bitmap. 68and have made a custom fringe bitmap.
185 69
186***** Indicate empty lines after the end of the buffer 70**** Indicate empty lines after the end of the buffer
187 71
188#+begin_src emacs-lisp 72#+begin_src emacs-lisp
189 (cuss indicate-empty-lines t) 73 (setq-default indicate-empty-lines t)
190#+end_src 74#+end_src
191 75
192***** Indicate the boundaries of the buffer 76**** Indicate the boundaries of the buffer
193 77
194#+begin_src emacs-lisp 78#+begin_src emacs-lisp
195 (cuss indicate-buffer-boundaries 'right) 79 (setq-default indicate-buffer-boundaries 'right)
196#+end_src 80#+end_src
197 81
198***** Indicate continuation lines, but only on the left fringe 82**** Indicate continuation lines, but only on the left fringe
199 83
200#+begin_src emacs-lisp 84#+begin_src emacs-lisp
201 (cuss visual-line-fringe-indicators '(left-curly-arrow nil)) 85 (setq-default visual-line-fringe-indicators '(left-curly-arrow nil))
202#+end_src 86#+end_src
203 87
204***** Customize fringe bitmaps 88**** Customize fringe bitmaps
205 89
206****** Curly arrows (continuation lines) 90***** Curly arrows (continuation lines)
207 91
208#+begin_src emacs-lisp 92#+begin_src emacs-lisp
209 (define-fringe-bitmap 'left-curly-arrow 93 (define-fringe-bitmap 'left-curly-arrow
@@ -219,7 +103,7 @@ and have made a custom fringe bitmap.
219 #b11000000]) 103 #b11000000])
220#+end_src 104#+end_src
221 105
222****** Arrows (truncation lines) 106***** Arrows (truncation lines)
223 107
224#+begin_src emacs-lisp 108#+begin_src emacs-lisp
225 (define-fringe-bitmap 'left-arrow 109 (define-fringe-bitmap 'left-arrow
@@ -235,139 +119,162 @@ and have made a custom fringe bitmap.
235 #b00000000]) 119 #b00000000])
236#+end_src 120#+end_src
237 121
238*** Windows 122** Windows
239
240**** Winner mode
241
242I don't really /use/ winner-mode as of yet, but it seems like a really
243good thing to have. It lets you move between window configurations
244with =C-c <-/->=.
245
246#+begin_src emacs-lisp
247 (when (fboundp 'winner-mode)
248 (winner-mode +1))
249#+end_src
250 123
251**** Switch windows, or buffers if there's only one 124*** Switch to other window or buffer
252 125
253from [[https://www.reddit.com/r/emacs/comments/kz347f/what_parts_of_your_config_do_you_like_best/gjlnp2c/][u/astoff1]]. 126I grabbed this from [[https://www.reddit.com/r/emacs/comments/kz347f/what_parts_of_your_config_do_you_like_best/gjlnp2c/][u/astoff1]]: it extends the =other-window= command
127to switch to the other buffer if there's only one window in the frame.
254 128
255#+begin_src emacs-lisp 129#+begin_src emacs-lisp :noweb-ref functions
256 (defun other-window-or-buffer () 130 (defun other-window-or-buffer ()
257 "Switch to the other window, or previous buffer." 131 "Switch to other window, or the previous buffer."
258 (interactive) 132 (interactive)
259 (if (eq (count-windows) 1) 133 (if (eq (count-windows) 1)
260 (switch-to-buffer nil) 134 (switch-to-buffer nil)
261 (other-window 1))) 135 (other-window 1)))
262#+end_src 136#+end_src
263 137
264*** Buffers 138And I'll bind it to =M-o=, since that's easier to reach than =C-x o=.
265 139
266**** Startup buffers 140#+begin_src emacs-lisp :noweb-ref bindings
141 (define-key global-map (kbd "M-o") #'other-window-or-buffer)
142#+end_src
267 143
268I don't want to see Emacs's splash screen, and I want the =*scratch*= 144** Buffers
269buffer to have a little message.
270 145
271#+begin_src emacs-lisp 146*** Uniquify buffers
272 (cuss inhibit-startup-screen t
273 "Don't show the startup buffer.")
274 147
275 (cuss initial-buffer-choice t 148The default way Emacs makes buffer names unique is really ugly and,
276 "Start with *scratch*.") 149dare I say it, stupid. Instead, I want them to be uniquified by their
150filesystem paths.
277 151
278 (cuss initial-scratch-message 152#+begin_src emacs-lisp :noweb-ref requires
279 (concat ";; Hello, " (nth 0 (split-string user-full-name)) "!\n" 153 (require 'uniquify)
280 ";; Happy hacking ..."))
281#+end_src 154#+end_src
282 155
283**** Immortal =*scratch*= buffer 156#+begin_src emacs-lisp :noweb-ref settings
157 (setq-default uniquify-buffer-name-style 'forward)
158#+end_src
284 159
285I don't want to accidentally kill the =*scratch*= buffer. 160*** Startup buffers
286 161
287#+begin_src emacs-lisp 162When Emacs starts up, I want a blank slate: the *scratch* buffer. I
288 (defun immortal-scratch () 163also want it to show a cute little message to myself.
289 (if (eq (current-buffer) (get-buffer "*scratch*"))
290 (progn (bury-buffer)
291 nil)
292 t))
293 164
294 (add-hook 'kill-buffer-query-functions #'immortal-scratch) 165#+begin_src emacs-lisp :noweb-ref settings
166 (setq-default inhibit-startup-screen t ; Don't show that splash screen thing.
167 initial-buffer-choice t ; Start on *scratch*
168 initial-scratch-message
169 (concat ";; Howdy, "
170 (nth 0 (split-string user-full-name)) "!\n"
171 ";; Welcome to Emacs."
172 "\n\n"))
295#+end_src 173#+end_src
296 174
297**** Uniquify buffers 175*** Immortal =*scratch*= buffer
298 176
299I like the =forward= style, which uniquifies buffers by including path 177I don't want to accidentally kill the *scratch* buffer. So, I add a
300elements up the tree until the names are unique. 178function to the =kill-buffer-query-functions= hook that will return
179=nil= if the buffer is *scratch*.
301 180
302#+begin_src emacs-lisp 181#+begin_src emacs-lisp :noweb-ref functions
303 (require 'uniquify) 182 (defun immortal-scratch ()
304 (cuss uniquify-buffer-name-style 'forward) 183 (if (not (eq (current-buffer) (get-buffer "*scratch*")))
184 t
185 (bury-buffer)
186 nil))
305#+end_src 187#+end_src
306 188
307**** Kill buffers more smarter-ly 189#+begin_src emacs-lisp :noweb-ref hooks
308 190 (add-hook 'kill-buffer-query-functions #'immortal-scratch)
309#+begin_src emacs-lisp 191#+end_src
310 (defun kill-a-buffer (&optional prefix)
311 "Kill buffers and windows sanely.
312 192
313 `kill-a-buffer' works based on the prefix argument as follows: 193*** Kill buffers better
314 194
315 - 0 => kill the CURRENT buffer and window 195#+begin_src emacs-lisp :noweb-ref functions
316 - 4 (C-u) => kill the OTHER window and its buffer 196 (defun kill-a-buffer (&optional prefix)
317 - 16 (C-u C-u) => kill ALL OTHER buffers and windows 197 "Kill a buffer and its window, prompting only on unsaved changes.
318 198
319 Prompt iff there are unsaved changes." 199 `kill-a-buffer' uses the PREFIX argument to determine which buffer(s) to kill:
200 0 => Kill current buffer & window
201 4 (C-u) => Kill OTHER buffer & window
202 16 (C-u C-u) => Kill ALL OTHER buffers & windows"
320 (interactive "P") 203 (interactive "P")
321 (pcase (or (car prefix) 0) 204 (pcase (or (car prefix) 0)
322 (0 (kill-current-buffer) 205 (0 (kill-current-buffer)
323 (unless (one-window-p) (delete-window))) 206 (unless (one-window-p) (delete-window)))
324 (4 (other-window 1) 207 (4 (other-window 1)
325 (kill-current-buffer) 208 (kill-current-buffer)
326 (unless (one-window-p) (delete-window))) 209 (unless (one-window-p) (delete-window)))
327 (16 (mapc #'kill-buffer (delq (current-buffer) (buffer-list))) 210 (16 (mapc #'kill-buffer (delq (current-buffer) (buffer-list)))
328 (delete-other-windows)))) 211 (delete-other-windows))))
329#+end_src 212#+end_src
330 213
331*** Fonts 214#+begin_src emacs-lisp :noweb-ref bindings
215 (define-key ctl-x-map "k" #'kill-a-buffer)
216#+end_src
332 217
333**** Function: =set-face-from-alternatives= 218** Cursor
334 219
335To be honest, this might be better off using =cussface=, but that's 220*** Cursor shape
336another story for another day.
337 221
338#+begin_src emacs-lisp 222I like a vertical bar, but only in the selected window.
339 (defun set-face-from-alternatives (face frame &rest fontspecs) 223
340 "Set FACE on FRAME from first available font from FONTSPECS. 224#+begin_src emacs-lisp :noweb-ref settings
341 FACE and FRAME work the same as with `set-face-attribute'." 225 (setq-default cursor-type 'bar
342 (catch :return 226 cursor-in-non-selected-windows nil)
343 (dolist (spec fontspecs)
344 (when-let ((found (find-font (apply #'font-spec spec))))
345 (set-face-attribute face frame :font found)
346 (throw :return found)))))
347#+end_src 227#+end_src
348 228
349**** Add a hook to setup fonts after the first window focus change 229*** Don't blink the cursor
350 230
351Of course, I only need to setup the fonts on a graphical session. 231#+begin_src emacs-lisp :noweb-ref modes
232 (blink-cursor-mode -1)
233#+end_src
352 234
353#+begin_src emacs-lisp 235** Tabs
354 (when (display-graphic-p) 236
355 (add-function :before after-focus-change-function #'acdw/setup-fonts)) 237*** Tab names
238
239#+begin_src emacs-lisp :noweb-ref settings
240 (setq-default tab-bar-tab-name-function
241 #'tab-bar-tab-name-current-with-count)
356#+end_src 242#+end_src
357 243
358**** Setup my fonts 244*** When to show the tab bar
359 245
360Notice that this function removes itself from 246Only when there's more than one tab.
361=after-focus-change-function=, since ideally you'll only need to set
362the fonts once.
363 247
364#+begin_src emacs-lisp 248#+begin_src emacs-lisp :noweb-ref settings
365 (defun acdw/setup-fonts () 249 (setq-default tab-bar-show 1)
366 "Setup fonts. 250#+end_src
251
252** Fonts
367 253
368 This has to happen after the frame is setup for the first time, 254*** Find an installed font from a list of alternatives
369 so it should be added to `after-focus-change-function'. It 255
370 removes itself." 256#+begin_src emacs-lisp :noweb-ref functions
257 (defun set-face-from-alternatives (face frame &rest fontspecs)
258 "Set FACE on FRAME from first available spec from FONTSPECS.
259 FACE and FRAME work the same as with `set-face-attribute.'"
260 (catch :return
261 (dolist (spec fontspecs)
262 (when-let ((found (find-font (apply #'font-spec spec))))
263 (set-face-attribute face frame :font found)
264 (throw :return found)))))
265#+end_src
266
267*** Setup fonts on first window focus
268
269At the end of this function, it removes itself from
270=after-focus-change-function=, so it only runs once.
271
272#+begin_src emacs-lisp :noweb-ref functions
273 (defun acdw/setup-fonts ()
274 "Setup fonts. This has to happen after the frame is setup for
275 the first time, so it should be added to `after-focus-change-function'. It
276 removes itself from that hook."
277 (interactive)
371 (set-face-from-alternatives 'default nil 278 (set-face-from-alternatives 'default nil
372 '(:family "Input Mono" 279 '(:family "Input Mono"
373 :slant normal 280 :slant normal
@@ -377,9 +284,9 @@ the fonts once.
377 :slant normal 284 :slant normal
378 :weight normal 285 :weight normal
379 :height 100)) 286 :height 100))
380 ;; `fixed-pitch' should just inherit from `default' 287 ;; `fixed-pitch' inherits from `default'
381 (set-face-attribute 'fixed-pitch nil :inherit 'default) 288 (set-face-attribute 'fixed-pitch nil :inherit 'default)
382 289 ;; variable-pitch is different
383 (set-face-from-alternatives 'variable-pitch nil 290 (set-face-from-alternatives 'variable-pitch nil
384 '(:family "Input Sans" 291 '(:family "Input Sans"
385 :slant normal 292 :slant normal
@@ -387,163 +294,318 @@ the fonts once.
387 '(:family "Georgia" 294 '(:family "Georgia"
388 :slant normal 295 :slant normal
389 :weight normal)) 296 :weight normal))
390 297 ;; remove self from hook
391 (remove-function after-focus-change-function #'acdw/setup-fonts)) 298 (remove-function after-focus-change-function #'acdw/setup-fonts))
392#+end_src 299#+end_src
393 300
394**** Underlines 301Of course, it only makes sense to run the font setup at all if I'm
302using the graphical Emacs.
395 303
396#+begin_src emacs-lisp 304#+begin_src emacs-lisp :noweb-ref hooks
397 (cuss x-underline-at-descent-line t) 305 (when (display-graphic-p)
306 (add-function :before after-focus-change-function
307 #'acdw/setup-fonts))
398#+end_src 308#+end_src
399 309
400** Interactivity 310*** Underlines
401*** Dialogs and alerts
402 311
403**** Don't use a dialog box 312I like the /fancy/ underlines in newer browsers that skip all the
313descenders. Emacs doesn't /quite/ have that, but it can put the
314underline below all the text.
404 315
405#+begin_src emacs-lisp 316#+begin_src emacs-lisp :noweb-ref settings
406 (cuss use-dialog-box nil) 317 (setq-default x-underline-at-descent-line t)
407#+end_src 318#+end_src
408 319
409**** Yes or no questions 320* Interactivity
410 321
411#+begin_src emacs-lisp 322** Dialogs and alerts
323
324*** Don't use a dialog box
325
326Ask in the modeline instead.
327
328#+begin_src emacs-lisp :noweb-ref settings
329 (setq-default use-dialog-box nil)
330#+end_src
331
332*** Yes or no questions
333
334I just want to type =y= or =n=, okay?
335
336#+begin_src emacs-lisp :noweb-ref functions
412 (fset 'yes-or-no-p #'y-or-n-p) 337 (fset 'yes-or-no-p #'y-or-n-p)
413#+end_src 338#+end_src
414 339
415**** The Bell 340*** The Bell
416 341
417#+begin_src emacs-lisp 342The only system I /sort of/ like the bell on is my Thinkpad, which
418 ;; Don't flash the whole screen on bell 343does a little on-board speaker beep. Until I can figure out how to
419 (cuss visible-bell nil) 344let it do its thing, though, I'll just change the bell on all my
345systems.
420 346
421 ;; Instead, flash the mode line 347#+begin_src emacs-lisp :noweb-ref settings
422 (cuss ring-bell-function #'flash-mode-line) 348 (setq-default visible-bell nil
349 ring-bell-function #'flash-mode-line)
350#+end_src
351
352**** Flash the mode-line
423 353
354#+begin_src emacs-lisp :noweb-ref functions
424 (defun flash-mode-line () 355 (defun flash-mode-line ()
425 (invert-face 'mode-line) 356 (invert-face 'mode-line)
426 (run-with-timer 0.2 nil #'invert-face 'mode-line)) 357 (run-with-timer 0.2 nil #'invert-face 'mode-line))
427#+end_src 358#+end_src
428 359
429t*** Minibuffer 360** Minibuffer
430 361
431*** Minibuffer 362*** Keep the cursor away from the minibuffer prompt
432 363
433**** Keep the cursor away from the minibuffer prompt 364#+begin_src emacs-lisp :noweb-ref settings
434 365 (setq-default minibuffer-prompt-properties
435#+begin_src emacs-lisp 366 '(read-only t
436 (cuss minibuffer-prompt-properties 367 cursor-intangible t
437 '(read-only t cursor-intangible t face minibuffer-prompt)) 368 face minibuffer-prompt))
438#+end_src 369#+end_src
439 370
440**** Enable recursive minibuffer 371*** Enable a recursive minibuffer
441 372
442#+begin_src emacs-lisp 373#+begin_src emacs-lisp :noweb-ref
443 (cuss enable-recursive-minibuffers t) 374 (setq-default enable-recursive-minibuffers t)
444#+end_src 375#+end_src
445 376
446**** Show how deep the minibuffer goes in the modeline 377*** Show the recursivity of the minibuffer in the mode-line
447 378
448#+begin_src emacs-lisp 379#+begin_src emacs-lisp :noweb-ref modes
449 (minibuffer-depth-indicate-mode +1) 380 (minibuffer-depth-indicate-mode +1)
450#+end_src 381#+end_src
451 382
452*** Completing-read 383** Completing-read
453 384
454**** Shadow file names 385*** Shadow file names
455 386
456When typing =~= or =/= in the file-selection dialog, Emacs "pretends" 387When typing =~= or =/= in the file-selection dialog, Emacs "pretends"
457that you've typed them at the beginning of the line. By default, 388that you've typed them at the beginning of the line. By default,
458however, it only /fades out/ the previous contents of the line. I 389however, it only /fades out/ the previous contents of the line. I want
459want to /hide/ those contents. 390to /hide/ those contents.
460 391
461#+begin_src emacs-lisp 392#+begin_src emacs-lisp :noweb-ref settings
462 (cuss file-name-shadow-properties '(invisible t)) 393 (setq-default file-name-shadow-properties '(invisible t))
394#+end_src
463 395
396#+begin_src emacs-lisp :noweb-ref modes
464 (file-name-shadow-mode +1) 397 (file-name-shadow-mode +1)
465#+end_src 398#+end_src
466 399
467**** Ignore case 400*** Ignore case
468 401
469#+begin_src emacs-lisp 402#+begin_src emacs-lisp :noweb-ref
470 (cuss completion-ignore-case t) 403 (setq-default completion-ignore-case t
471 (cuss read-buffer-completion-ignore-case t) 404 read-buffer-completion-ignore-case t
472 (cuss read-file-name-completion-ignore-case t) 405 read-file-name-completion-ignore-case t)
473#+end_src 406#+end_src
474 407
475** Persistence 408* Persistence
476 409
477*** Minibuffer history 410** Minibuffer history
478 411
479The =savehist= package saves the minibuffer history between sessions. 412The =savehist= package saves minibuffer history between sessions, as
480It can also save some other variables alongside the minibuffer 413well as the option for some other variables. Since storage is cheap,
481history. Since storage is cheap, I'm also going to keep all my 414I keep all of it.
482history.
483 415
484#+begin_src emacs-lisp 416#+begin_src emacs-lisp :noweb-ref requires
485 (require 'savehist) 417 (require 'savehist)
418#+end_src
486 419
487 (cuss savehist-additional-variables 420#+begin_src emacs-lisp :noweb-ref modes
488 '(kill-ring 421 (setq-default savehist-additional-variables
489 search-ring 422 '(kill-ring
490 regexp-search-ring)) 423 search-ring
491 424 regexp-search-ring)
492 ;; Don't truncate history 425 history-length t ; Don't truncate
493 (cuss history-length t) 426 history-delete-duplicates t)
494 427#+end_src
495 ;; Delete history duplicates
496 (cuss history-delete-duplicates t)
497 428
429#+begin_src emacs-lisp :noweb-ref modes
498 (savehist-mode +1) 430 (savehist-mode +1)
499#+end_src 431#+end_src
500 432
501*** File places 433** File places
502 434
503The =saveplace= package saves where I've been in the files I've 435The =saveplace= package saves where I've been in my visited files.
504visited, so I can return back to them.
505 436
506#+begin_src emacs-lisp 437#+begin_src emacs-lisp :noweb-ref requires
507 (require 'saveplace) 438 (require 'saveplace)
439#+end_src
508 440
509 ;; Forget the place in unreadable files 441Since storage is cheap, but I'm impatient -- especially on Windows --
510 (cuss save-place-forget-unreadable-files t) 442I'm not going to check whether the files =save-place= saves the places
443of are readable or not.
444
445#+begin_src emacs-lisp :noweb-ref settings
446 (setq-default save-place-forget-unreadable-files (when-at :home))
447#+end_src
511 448
449#+begin_src emacs-lisp :noweb-ref modes
512 (save-place-mode +1) 450 (save-place-mode +1)
513#+end_src 451#+end_src
514 452
515*** Recent files 453** Recent files
516 454
517#+begin_src emacs-lisp 455I also like to keep track of recently-opened files. =recentf= helps
456with that.
457
458#+begin_src emacs-lisp :noweb-ref requires
518 (require 'recentf) 459 (require 'recentf)
460#+end_src
519 461
520 ;; Limit the number of items in the recentf menu 462#+begin_src emacs-lisp :noweb-ref settings
521 (cuss recentf-max-menu-items 100) 463 (setq-default recentf-max-menu-items 100
522 ;; But not the number of items in the actual list 464 recentf-max-saved-items nil)
523 (cuss recentf-max-saved-items nil) 465#+end_src
524 466
467#+begin_src emacs-lisp :noweb-ref modes
525 (recentf-mode +1) 468 (recentf-mode +1)
526#+end_src 469#+end_src
527 470
528**** Save the recentf list periodically 471*** Save the recentf list periodically
529 472
530#+begin_src emacs-lisp 473#+begin_src emacs-lisp :noweb-ref functions
531 (defun acdw/maybe-save-recentf () 474 (defun maybe-save-recentf ()
532 "Save `recentf-file every five minutes, but only when out of focus." 475 "Save `recentf-file' every five minutes, but only when out of focus."
533 (defvar recentf--last-save (time-convert nil 'integer) 476 (defvar recentf--last-save (time-convert nil 'integer)
534 "When we last ran `recentf-save-list'.") 477 "When we last saved the `recentf-save-list'.")
535 478
536 (when (> (time-convert (time-since recentf--last-save) 'integer) 479 (when (> (time-convert (time-since recentf--last-save) 'integer)
537 (* 60 5)) 480 (* 60 5))
538 (setq recentf--last-save (time-convert nil 'integer)) 481 (setq-default recentf--last-save (time-convert nil 'integer))
539 (acdw/when-unfocused #'recentf-save-list))) 482 (when-unfocused #'recentf-save-list)))
483#+end_src
484
485#+begin_src emacs-lisp :noweb-ref hooks
486 (add-function :after after-focus-change-function
487 #'maybe-save-recentf)
488#+end_src
489
490* Responsiveness
491
492Emacs has a slew of well-documented problems with snappiness.
493Luckily, there are a number of solutions.
494
495** Only do things when unfocused
496
497Sometimes, we can fake responsiveness by only performing commands when
498the user is looking at something else.
499
500#+begin_src emacs-lisp :noweb-ref functions
501 (defun when-unfocused (func &rest args)
502 "Run FUNC, with ARGS, iff all frames are out of focus."
503 (when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list)))
504 (apply func args)))
505#+end_src
506
507* Files
508
509** Encoding
510
511*** UTF-8
512
513It's 2020. Let's encode files like it is.
514
515#+begin_src emacs-lisp :noweb-ref settings
516 (prefer-coding-system 'utf-8)
517 (set-default-coding-systems 'utf-8)
518 (set-terminal-coding-system 'utf-8)
519 (set-keyboard-coding-system 'utf-8)
520
521 (setq-default buffer-file-coding-system 'utf-8
522 x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
523#+end_src
524
525*** UNIX-style line endings
526
527This function is from the [[https://www.emacswiki.org/emacs/EndOfLineTips][Emacs Wiki]].
528
529#+begin_src emacs-lisp :noweb-ref functions
530 (defun ewiki/no-junk-please-were-unixish ()
531 "Convert line endings to UNIX, dammit."
532 (let ((coding-str (symbol-name buffer-file-coding-system)))
533 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
534 (set-buffer-file-coding-system 'unix))))
535#+end_src
536
537I add it to both =file-find-hook= /and/ =before-save-hook= because I'm
538/that/ over it. I don't want to ever work with anything other than
539UNIX line endings ever again. I just don't care. Even Microsoft
540Notepad can handle UNIX line endings, so I don't want to hear it.
541
542#+begin_src emacs-lisp :noweb-ref hooks
543 (add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish)
544 (add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish)
545#+end_src
546
547** Keep =~/.emacs.d= clean :package:
540 548
541 (add-function :after after-focus-change-function #'acdw/maybe-save-recentf) 549* Package management :package:
550:PROPERTIES:
551:header-args: :noweb-ref package-bootstrap
552:END:
553
554Emacs is the /extensible/ editor, and that means I want to use
555third-party packages. Of course, first I have to /manage/ those
556packages. I use the excellent =straight.el=.
557
558** TODO Update the PATH
559
560** Disable =package.el=
561
562#+begin_src emacs-lisp
563 (setq package-enable-at-startup nil)
542#+end_src 564#+end_src
543 565
544** Files 566** Bootstrap
545 567
546*** Encoding 568The following is straight (heh) from the straight repo, wrapped in a
569function so I can call it in another wrapper.
570
571#+begin_src emacs-lisp
572 (defun acdw/bootstrap-straight ()
573 "Bootstrap straight.el."
574 (defvar bootstrap-version)
575 (let ((bootstrap-file
576 (expand-file-name
577 "straight/repos/straight.el/bootstrap.el"
578 user-emacs-directory))
579 (bootstrap-version 5))
580 (unless (file-exists-p bootstrap-file)
581 (with-current-buffer
582 (url-retrieve-synchronously
583 (concat
584 "https://raw.githubusercontent.com/"
585 "raxod502/straight.el/develop/install.el")
586 'silent 'inhibit-cookies)
587 (goto-char (point-max))
588 (eval-print-last-sexp)))
589 (load bootstrap-file nil 'nomessage)))
590#+end_src
591
592To actually bootstrap straight, I'll first try running the above
593directly. If it errors (it tends to on Windows), I'll directly clone
594the repo using git, /then/ run the bootstrap code.
595
596#+begin_src emacs-lisp
597 (unless (ignore-errors (acdw/bootstrap-straight))
598 (let ((msg "Straight.el didn't bootstrap correctly. Cloning directly"))
599 (message "%s..." msg)
600 (call-process "git" nil
601 (get-buffer-create "*bootstrap-straight-messages*") nil
602 "clone"
603 "https://github.com/raxod502/straight.el"
604 (expand-file-name "straight/repos/straight.el"
605 user-emacs-directory))
606 (message "%s...Done." msg)
607 (acdw/bootstrap-straight)))
608#+end_src
547 609
548* System-specific 610* System-specific
549 611
@@ -552,27 +614,41 @@ easier to use in both systems, I've included various system-specific
552settings and written some ancillary scripts. 614settings and written some ancillary scripts.
553 615
554** Determine where I am 616** Determine where I am
617:PROPERTIES:
618:header-args: :noweb-ref functions
619:END:
555 620
556#+begin_src emacs-lisp 621#+begin_src emacs-lisp
557 (defmacro when-at (conditions &rest commands) 622 (defmacro when-at (conditions &rest commands)
558 "Run COMMANDS when at a specific place. 623 "Run COMMANDS, or let the user know, when at a specific place.
559 624
560 CONDITIONS are one of `:work', `:home', or a list beginning with 625 CONDITIONS are one of `:work', `:home', or a list beginning with
561 those and other conditions to check. COMMANDS are only run if 626 those and other conditions to check. COMMANDS are only run if
562 all CONDITIONS are met." 627 all CONDITIONS are met.
628
629 If COMMANDS is empty or nil, simply return the result of CONDITIONS."
563 (declare (indent 1)) 630 (declare (indent 1))
564 (let ((at-work (memq system-type '(ms-dos windows-nt))) 631 (let ((at-work '(memq system-type '(ms-dos windows-nt)))
565 (at-home (memq system-type '(gnu gnu/linux gnu/kfreebsd)))) 632 (at-home '(memq system-type '(gnu gnu/linux gnu/kfreebsd))))
566 (pcase conditions 633 (pcase conditions
567 (:work `(when ',at-work ,@commands)) 634 (:work (if commands `(when ,at-work ,@commands) at-work))
568 (:home `(when ',at-home ,@commands)) 635 (:home (if commands `(when ,at-home ,@commands) at-home))
569 (`(:work ,others) `(when (and ',at-work ,others) 636 ((guard (eq (car conditions) :work))
570 ,@commands)) 637 (if commands
571 (`(:home ,others) `(when (and ',at-home ,others) 638 `(when (and ,at-work ,@(cdr conditions))
572 ,@commands))))) 639 ,@commands)
573#+end_src 640 `(and ,at-work ,@(cdr conditions))))
574 641 ((guard (eq (car conditions) :home))
575** Linux 642 (if commands
643 `(when (and ,at-home ,@(cdr conditions))
644 ,@commands)
645 `(and ,at-work ,@(cdr conditions)))))))
646#+end_src
647
648** Linux (home)
649:PROPERTIES:
650:header-args: :noweb-ref linux-specific
651:END:
576 652
577*** Settings 653*** Settings
578 654
@@ -580,14 +656,14 @@ settings and written some ancillary scripts.
580 656
581**** em 657**** em
582:PROPERTIES: 658:PROPERTIES:
583:header-args: :tangle-mode (identity #o755) :tangle bin/em :mkdirp yes 659:header-args: :tangle-mode (identity #o755) :mkdirp yes
584:END: 660:END:
585 661
586Here's a wrapper script that'll start =emacs --daemon= if there isn't 662Here's a wrapper script that'll start =emacs --daemon= if there isn't
587one, and then launch =emacsclient= with the arguments. Install it to 663one, and then launch =emacsclient= with the arguments. Install it to
588your =$PATH= somewhere. 664your =$PATH= somewhere.
589 665
590#+begin_src sh :shebang "#!/bin/sh" 666#+begin_src sh :shebang "#!/bin/sh" :tangle (when-at :home "~/bin/em")
591 if ! emacsclient -nc "$@"; then 667 if ! emacsclient -nc "$@"; then
592 emacs --daemon 668 emacs --daemon
593 emacsclient -nc "$@" 669 emacsclient -nc "$@"
@@ -596,13 +672,13 @@ your =$PATH= somewhere.
596 672
597**** emacsclient.desktop 673**** emacsclient.desktop
598:PROPERTIES: 674:PROPERTIES:
599:header-args: :tangle bin/emacsclient.desktop :mkdirp yes 675:header-args: :mkdirp yes
600:END: 676:END:
601 677
602I haven't really tested this yet, but it should allow me to open other 678I haven't really tested this yet, but it should allow me to open other
603files and things in Emacs. From [[https://www.taingram.org/blog/emacs-client.html][taingram]]. 679files and things in Emacs. From [[https://www.taingram.org/blog/emacs-client.html][taingram]].
604 680
605#+begin_src conf-desktop 681#+begin_src conf-desktop :tangle (when-at :home "~/.local/share/applications/emacsclient.desktop")
606 [Desktop Entry] 682 [Desktop Entry]
607 Name=Emacs Client 683 Name=Emacs Client
608 GenericName=Text Editor 684 GenericName=Text Editor
@@ -615,7 +691,10 @@ files and things in Emacs. From [[https://www.taingram.org/blog/emacs-client.ht
615 Categories=Utility;TextEditor; 691 Categories=Utility;TextEditor;
616#+end_src 692#+end_src
617 693
618** Windows 694** Windows (work)
695:PROPERTIES:
696:header-args: :noweb-ref windows-specific
697:END:
619 698
620I use Windows at work, where I /also/ don't have Admin rights. So I 699I use Windows at work, where I /also/ don't have Admin rights. So I
621kind of fly-by-night there. Much of the ideas and scripts in this 700kind of fly-by-night there. Much of the ideas and scripts in this
@@ -623,24 +702,21 @@ section come from [[https://github.com/termitereform/JunkPile/blob/master/emacs-
623 702
624*** Settings 703*** Settings
625 704
626#+NAME: w32-settings
627#+begin_src emacs-lisp 705#+begin_src emacs-lisp
628 (when (memq system-type '(windows-nt ms-dos cygwin)) 706 (setq-default w32-allow-system-shell t) ; enable cmd.exe as shell
629 (setq w32-allow-system-shell t ; enable cmd.exe as shell
630 ))
631#+end_src 707#+end_src
632 708
633*** Scripts 709*** Scripts
634:PROPERTIES: 710:PROPERTIES:
635:header-args: :noweb tangle :mkdirp yes 711:header-args: :noweb yes :mkdirp yes
636:END: 712:END:
637 713
638**** Common variables 714**** Common variables
639 715
640#+NAME: w32-bat-common 716#+NAME: w32-bat-common
641#+begin_src bat 717#+begin_src bat
642set HOME=%~dp0..\..\ 718set HOME=%~dp0..\..
643set EMACS=%~dp0..\..\..\bin\runemacs.exe 719set EMACS=%HOME%\Applications\Emacs\bin\runemacs.exe
644#+end_src 720#+end_src
645 721
646**** Emacs Daemon 722**** Emacs Daemon
@@ -649,9 +725,9 @@ Either run this once at startup, or put a shortcut of it in the
649Startup folder: 725Startup folder:
650=%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup=. 726=%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup=.
651 727
652#+begin_src bat :tangle "bin/Emacs Daemon.cmd" 728#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Daemon.cmd")
653<<w32-bat-common>> 729<<w32-bat-common>>
654"%EMACS%" --daemon 730%EMACS% --daemon
655#+end_src 731#+end_src
656 732
657**** Emacs Client 733**** Emacs Client
@@ -661,9 +737,9 @@ run =runemacs.exe=.
661 737
662*This is the main shortcut for running Emacs.* 738*This is the main shortcut for running Emacs.*
663 739
664#+begin_src bat :tangle bin/Emacs.cmd 740#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs.cmd")
665<<w32-bat-common>> 741<<w32-bat-common>>
666set EMACSC=%~dp0..\..\..\bin\emacsclientw.exe 742set EMACSC=%HOME%\Applications\Emacs\bin\emacsclientw.exe
667"%EMACSC%" -n -c -a "%EMACS%" %* 743"%EMACSC%" -n -c -a "%EMACS%" %*
668#+end_src 744#+end_src
669 745
@@ -671,7 +747,7 @@ set EMACSC=%~dp0..\..\..\bin\emacsclientw.exe
671 747
672This runs Emacs with the factory settings. 748This runs Emacs with the factory settings.
673 749
674#+begin_src bat :tangle "bin/Emacs Safe Start.cmd" 750#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Safe Start.cmd")
675<<w32-bat-common>> 751<<w32-bat-common>>
676"%EMACS%" -Q %* 752"%EMACS%" -Q %*
677#+end_src 753#+end_src
@@ -680,23 +756,76 @@ This runs Emacs with the factory settings.
680 756
681This runs Emacs with the =--debug-init= option enabled. 757This runs Emacs with the =--debug-init= option enabled.
682 758
683#+begin_src bat :tangle "bin/Emacs Debug.cmd" 759#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Debug.cmd")
684<<w32-bat-common>> 760<<w32-bat-common>>
685"%EMACS%" --debug-init %* 761"%EMACS%" --debug-init %*
686#+end_src 762#+end_src
687* Appendices 763* Appendices
764
765** =config.el=
766:PROPERTIES:
767:header-args: :tangle config.el :noweb yes
768:END:
769
770While =config.el= is written above, I use Noweb references to tangle
771them all together in the following block, which enables me to organize
772my config here /logically/, while keeping the generated file organized
773/programmatically/.
774
775*** Enable lexical binding
776
777#+begin_src emacs-lisp
778 ;; config.el -*- lexical-binding: t -*-
779#+end_src
780
781*** Disclaimer
782:PROPERTIES:
783:header-args: :noweb-ref disclaimer
784:END:
785
786#+begin_src emacs-lisp
787 ;; This file is automatically tangled from config.org.
788 ;; Hand edits will be overwritten!
789#+end_src
790
791*** The rest
792
793#+begin_src emacs-lisp
794 ;;; REQUIRES
795 <<requires>>
796 ;;; PACKAGES
797 <<packages>>
798 ;;; FUNCTIONS
799 <<functions>>
800 ;;; SETTINGS
801 <<settings>>
802 ;;; MODES
803 <<modes>>
804 ;;; SYSTEM-DEPENDENT SETTINGS
805 (when-at :home
806 <<linux-specific>>
807 )
808 (when-at :work
809 <<windows-specific>>
810 )
811 ;;; HOOKS
812 <<hooks>>
813 ;;; BINDINGS
814 <<bindings>>
815#+end_src
816
688** Emacs's files 817** Emacs's files
689 818
690*** init.el 819*** init.el
691:PROPERTIES: 820:PROPERTIES:
692:header-args: :tangle init.el :comments both 821:header-args: :tangle init.el :noweb yes
693:END: 822:END:
694 823
695The classic Emacs initiation file. 824The classic Emacs initiation file.
696 825
697**** Use lexical binding when evaluating =init.el= 826**** Use lexical binding when evaluating =init.el=
698 827
699#+begin_src emacs-lisp :comments no :noweb tangle 828#+begin_src emacs-lisp
700 ;; init.el -*- lexical-binding: t -*- 829 ;; init.el -*- lexical-binding: t -*-
701 <<disclaimer>> 830 <<disclaimer>>
702#+end_src 831#+end_src
@@ -704,7 +833,7 @@ The classic Emacs initiation file.
704**** Prefer newer files to older files 833**** Prefer newer files to older files
705 834
706#+begin_src emacs-lisp 835#+begin_src emacs-lisp
707 (setq load-prefer-newer t) 836 (setq-default load-prefer-newer t)
708#+end_src 837#+end_src
709 838
710**** Load the config 839**** Load the config
@@ -715,27 +844,33 @@ directly from Org if it's newer.
715 844
716#+begin_src emacs-lisp 845#+begin_src emacs-lisp
717 (let* (;; Speed up init 846 (let* (;; Speed up init
718 (gc-cons-threshold most-positive-fixnum) 847 (gc-cons-threshold most-positive-fixnum)
719 (file-name-handler-alist nil) 848 (file-name-handler-alist nil)
720 ;; Config file names 849 ;; Config file names
721 (conf (expand-file-name "config" 850 (config (expand-file-name "config"
722 user-emacs-directory)) 851 user-emacs-directory))
723 (conf-el (concat conf ".el")) 852 (config.el (concat config ".el"))
724 (conf-org (concat conf ".org"))) 853 (config.org (concat config ".org"))
725 (unless (and (file-newer-than-file-p conf-el conf-org) 854 (straight-org-dir (expand-file-name "straight/build/org"
726 (load conf 'no-error)) 855 user-emacs-directory)))
727 ;; A plain require here just loads the older `org' 856 ;; Unless config.org is /newer/ than config.el, *or* the config
728 ;; in Emacs' install dir. We need to add the newer 857 ;; is able to be loaded without errors, load the config from
729 ;; one to the `load-path', hopefully that's all. 858 ;; config.org.
730 (add-to-list 'load-path (expand-file-name "straight/build/org" 859 (unless (or (file-newer-than-file-p config.org config.el)
731 user-emacs-directory)) 860 (load config 'no-error))
732 (require 'org) 861 ;; A plain require here just loads the older `org'
733 (org-babel-load-file conf-org))) 862 ;; in Emacs' install dir. We need to add the newer
863 ;; one to the `load-path', hopefully that's all.
864 (when (file-exists-p straight-org-dir)
865 (add-to-list 'load-path straight-org-dir))
866 ;; Load config.org
867 (require 'org)
868 (org-babel-load-file config.org)))
734#+end_src 869#+end_src
735 870
736*** early-init.el 871*** early-init.el
737:PROPERTIES: 872:PROPERTIES:
738:header-args: :tangle early-init.el :comments both 873:header-args: :tangle early-init.el :noweb yes
739:END: 874:END:
740 875
741Beginning with 27.1, Emacs also loads an =early-init.el= file, before 876Beginning with 27.1, Emacs also loads an =early-init.el= file, before
@@ -744,29 +879,31 @@ little as possible in this file, so I only have what I need.
744 879
745**** Don't byte-compile this file 880**** Don't byte-compile this file
746 881
747#+begin_src emacs-lisp :comments no :noweb tangle 882#+begin_src emacs-lisp
748 ;; early-init.el -*- no-byte-compile: t; -*- 883 ;; early-init.el -*- no-byte-compile: t; -*-
749 <<disclaimer>> 884 <<disclaimer>>
750#+end_src 885#+end_src
751 886
752**** Disable loading of =package.el= 887**** Package management
753 888
754I use =straight.el= instead. 889Since =early-init.el= loads before the built-in package manager
890initializes, I disable it and bootstrap my package manager of choice,
891=straight.el=.
755 892
756#+begin_src emacs-lisp 893#+begin_src emacs-lisp
757 (setq package-enable-at-startup nil) 894 <<package-bootstrap>>
758#+end_src 895#+end_src
759 896
760**** Don't resize the frame when loading fonts 897**** Don't resize the frame when loading fonts
761 898
762#+begin_src emacs-lisp 899#+begin_src emacs-lisp
763 (setq frame-inhibit-implied-resize t) 900 (setq-default frame-inhibit-implied-resize t)
764#+end_src 901#+end_src
765 902
766**** Resize frame by pixels 903**** Resize frame by pixels
767 904
768#+begin_src emacs-lisp 905#+begin_src emacs-lisp
769 (setq frame-resize-pixelwise t) 906 (setq-default frame-resize-pixelwise t)
770#+end_src 907#+end_src
771 908
772**** Shoe-horned from elsewhere in =config.org= 909**** Shoe-horned from elsewhere in =config.org=
@@ -778,13 +915,13 @@ weird shoe-horning of other bits of my config here, in a backwater
778heading in an appendix, isn't quite the future I wanted. But it's 915heading in an appendix, isn't quite the future I wanted. But it's
779what I have for now. 916what I have for now.
780 917
781#+begin_src emacs-lisp :noweb tangle 918#+begin_src emacs-lisp
782 <<initial-frame-setup>> 919 <<initial-frame-setup>>
783#+end_src 920#+end_src
784 921
785** License 922** License
786:PROPERTIES: 923:PROPERTIES:
787:header-args: :tangle LICENSE :comments no 924:header-args: :tangle LICENSE
788:END: 925:END:
789 926
790Copyright © 2020 Case Duckworth <acdw@acdw.net> 927Copyright © 2020 Case Duckworth <acdw@acdw.net>
@@ -817,3 +954,33 @@ It's highly likely that the WTFPL is completely incompatible with the
817GPL, for what should be fairly obvious reasons. To that, I say: 954GPL, for what should be fairly obvious reasons. To that, I say:
818 955
819*SUE ME, RMS!* 956*SUE ME, RMS!*
957
958** Make it easier to edit =config.org= :noexport:
959
960Because I use a lot of =:noweb-ref= directives in this file, editing
961it can be annoying -- I need some nice templates. Run this code block
962with =C-c C-c=.
963
964#+begin_src emacs-lisp :results output silent
965 (require 'org-tempo)
966
967 (dolist (cell '(("el" . "src emacs-lisp")
968 ("cr" . "src emacs-lisp :noweb-ref requires")
969 ("cf" . "src emacs-lisp :noweb-ref functions")
970 ("cs" . "src emacs-lisp :noweb-ref settings")
971 ("cm" . "src emacs-lisp :noweb-ref modes")
972 ("cl" . "src emacs-lisp :noweb-ref linux-specific")
973 ("cw" . "src emacs-lisp :noweb-ref windows-specific")
974 ("cp" . "src emacs-lisp :noweb-ref packages")
975 ("ch" . "src emacs-lisp :noweb-ref hooks")
976 ("cb" . "src emacs-lisp :noweb-ref bindings")))
977 (add-to-list 'org-structure-template-alist cell))
978#+end_src
979
980** Local variables :noexport:
981
982# Local variables:
983# org-adapt-indentation: nil
984# lisp-indent-function: 'common-lisp-indent-function
985# eval: (auto-fill-mode +1)
986# End: