summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--README.md2030
-rw-r--r--config.org1998
2 files changed, 1032 insertions, 2996 deletions
diff --git a/README.md b/README.md index 3f1adfa..fd7ed85 100644 --- a/README.md +++ b/README.md
@@ -1,1656 +1,896 @@
1This is my Emacs configuration. It's also a literate `org-mode` file. Yeah, I'm a cool guy.
2 1
3 2# Table of Contents
4# About me 3
5 41. [Pave the way](#org24d31f9)
6 ;; init.el -*- lexical-binding: t -*- 5 1. [Correct `exec-path`](#org82dd805)
7 (setq user-full-name "Case Duckworth" 6 2. [Package management](#org947e1de)
8 user-mail-address "acdw@acdw.net") 7 1. [Straight.el](#orgd711f6b)
9 8 2. [Use-package](#org9392b5d)
10 9 3. [Extra use-package keywords](#orgc93ae09)
11# License 10 3. [Customize variables](#org7cae7fe)
12 11 1. [Put customizations in a separate file](#org126d855)
13Copyright © 2020 Case Duckworth <acdw@acdw.net> 12 2. [A macro for ease of customization](#org2cf1d1a)
14 13 4. [Keep a tidy `~/.emacs`](#orga6c0096)
15This work is free. You can redistribute it and/or modify it under the terms of the Do What the Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See the `LICENSE` file, tangled from the following source block, for details. 142. [Look and Feel](#org1ecbcc5)
16 15 1. [Simplify the UI](#org23fb19e)
17 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 16 1. [Tool bars and menu bars](#orgad64258)
18 17 2. [Scroll bars](#org9b2f49e)
19 Version 2, December 2004 18 3. [Dialog boxen](#orgf1c5f65)
20 19 4. [Shorten confirmations](#orgedf9e78)
21 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 20 5. [Remove the bell](#org1643ce2)
22 21 6. [Tell Ediff to setup windows better](#org3996a6f)
23 Everyone is permitted to copy and distribute verbatim or modified copies of 22 2. [Tweak the remaining UI](#orgcdf874b)
24 this license document, and changing it is allowed as long as the name is changed. 23 1. [Window dividers](#org187505c)
25 24 2. [Fringes](#org3fd2bc6)
26 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 25 3. [Minibuffer](#org8ff32ea)
27 26 4. [Tabs](#orgef2a000)
28 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 27 5. [Cursor](#orge57d1b2)
29 28 6. [Buffer names](#orgb3f29a9)
30 0. You just DO WHAT THE FUCK YOU WANT TO. 29 7. [Buffer boundaries](#org2627b1e)
31 30 3. [Startup](#org1fc3c6d)
32 31 4. [Theme](#org207a1bd)
33## Note on the license 32 1. [Fonts](#org52f6c8c)
34 333. [Interactivity](#org6cbcfe5)
35It's highly likely that the WTFPL is completely incompatible with the GPL, for what should be fairly obvious reasons. To that, I say: 34 1. [Selectrum](#org7f26398)
36 35 2. [Prescient](#orgea8df9e)
37**SUE ME, RMS!** 36 3. [Consult](#org8818eb9)
38 37 4. [Marginalia](#orgd31a964)
39 38 5. [Ignore case](#org6e4913f)
40# Bootstrap 39 6. [Search](#org416dd18)
41 404. [Persistence](#orgb20768d)
42 41 1. [Save history](#org7dfee32)
43## Original init.el 42 2. [Save places in files](#org0f20005)
44 43 3. [Recent files](#org6d1a477)
45This file replaces itself with the actual configuration when it's first run. For easy installation, *this* is the `init.el` file in git &#x2013; and you probably want to keep it that way. To keep git from trying to update `init.el` when it's re-tangled, type this in the repo: 44 1. [Easily navigate recent files](#org9368a6b)
46 45 4. [Undo](#orgbb4f91a)
47 git update-index --assume-unchanged init.el 465. [Editing](#org52b008a)
48 47 1. [Operate visually on lines](#orgce838ba)
49If, for some reason, you want to change this original file to be re-tracked, run this command: 48 2. [Require a final newline](#org6f67996)
50 49 3. [Killing & Yanking](#orga2bdb3e)
51 git update-index --no-assume-unchanged init.el 50 1. [Replace selection when typing](#org16c1a6b)
52 51 2. [Save existing clipboard text into kill ring before replacing it](#orgea7fd73)
53Otherwise, here's the actual, original `init.el` that tangles this Org file and gets us going. 52 4. [So long mode](#org27f430f)
54 536. [Files](#org8cc8ee8)
55 (require 'org) 54 1. [Encoding](#org8ca2e9b)
56 (find-file (concat user-emacs-directory "config.org")) 55 1. [UTF-8](#org54363a7)
57 (org-babel-tangle) 56 2. [Convert all files to UNIX-style line endings](#orgeaed3bd)
58 (load-file (concat user-emacs-directory "early-init.el")) 57 2. [Backups](#org7239c47)
59 (load-file (concat user-emacs-directory "init.el")) 58 3. [Auto-saves](#org32fc658)
60 (byte-compile-file (concat user-emacs-directory "init.el")) 59 4. [Revert files](#org94456e2)
61 60 5. [Add a timestamp to files](#orgb586b3b)
62 617. [Programming](#org738fbd9)
63### TODO What I should do instead 62 1. [Which function are we in?](#org080eb2f)
64 638. [Writing](#org6bf5097)
65Honestly, I should just change this "Original init.el" thing to a Makefile I can tangle in `config.org`, and track &#x2013; since it won't be overwritten or need any special `git` invocations to stop tracking it, I can edit it as I think about what would work best. I could also maybe give it more of a "cross-platform" vibe by installing, say, `straight.el` in the Makefile on Windows. One day &#x2026; 64 1. [Visual Fill Column](#org6f01971)
66 65 2. [Type nice-looking quote-type marks](#org03e747d)
67 669. [Applications](#org9528516)
68## Tangling 67 1. [Magit](#orgd2a60aa)
69 6810. [Appendices](#org7339cf2)
70After our first tangle, each time we edit `config.org` we want to go ahead and re-tangle our config. To that end, I've written `acdw/tangle-init`, which automatically tangles `config.org`. 69 1. [Emacs' files](#org6070b2c)
71 70 1. [init.el](#org0d720f6)
72 (defun acdw/tangle-init () 71 2. [early-init.el](#orgd6bffd2)
73 "If the current buffer is `config.org', tangle it, then compile 72 2. [Ease tangling and loading of Emacs' init](#org9c5b437)
74 and load the resulting files." 73 3. [License](#org1a4bb4d)
75 (when (equal (buffer-file-name) 74 1. [Note on the license](#orga6047ee)
76 (expand-file-name 75
77 (concat user-emacs-directory "config.org"))) 76
78 ;; Tangle and load init.el and early-init.el 77
79 (require 'async) 78<a id="org24d31f9"></a>
80 (async-start 79
81 (lambda () 80# Pave the way
82 (let ((prog-mode-hook nil)) 81
83 (require 'org) 82
84 (org-babel-tangle-file 83<a id="org82dd805"></a>
85 (expand-file-name 84
86 (concat user-emacs-directory "config.org"))))) 85## Correct `exec-path`
87 (lambda (response) 86
88 (acdw/load-init) 87 (let ((win-downloads "c:/Users/aduckworth/Downloads"))
89 (message "Tangled and loaded: %s" response))))) 88 (dolist (path `(;; Linux
90 89 ,(expand-file-name "bin"
91Since I want to tangle every time I save `config.org`, I've added `acdw/tangle-init` to a hook. 90 user-emacs-directory)
92 91 ,(expand-file-name "~/bin")
93 (add-hook 'after-save-hook #'acdw/tangle-init) 92 ,(expand-file-name "~/.local/bin")
94 93 ,(expand-file-name "~/Scripts")
95Finally, I want an easier way to load the generated init files than the old `M-x load-file RET ~/.config/emacs/init.el RET`. So I've written `acdw/load-init` &#x2013; which also gets called at the end of the async part of `acdw/tangle-init`. 94 ;; Windows
96 95 ,(expand-file-name "emacs/bin"
97 (defun acdw/load-init () 96 win-downloads)
98 (interactive) 97 ,(expand-file-name "PortableGit/bin"
99 (load-file (expand-file-name 98 win-downloads)
100 (concat user-emacs-directory "early-init.el"))) 99 ,(expand-file-name "PortableGit/usr/bin"
101 (load-file (expand-file-name 100 win-downloads)))
102 (concat user-emacs-directory "init.el")))) 101 (when (file-exists-p path)
103 102 (add-to-list 'exec-path path))))
104 103
105## Miscellaneous bootstrappy stuff 104
106 105<a id="org947e1de"></a>
107 106
108### Add directories to `load-path` 107## Package management
109 108
110I also put lispy stuff in the `lisp/` subdirectory of my Emacs config, and under my SyncThing directory (for easy syncing ;P). 109
111 110<a id="orgd711f6b"></a>
112 (dolist (dir `(,(concat user-emacs-directory 111
113 (convert-standard-filename "lisp/")) 112### Straight.el
114 ,(expand-file-name "~/Sync/elisp/"))) 113
115 (add-to-list 'load-path dir)) 114 (defvar bootstrap-version)
116 115 (let ((bootstrap-file
117 116 (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
118### TODO Require my secrets 117 (bootstrap-version 5))
119 118 (unless (file-exists-p bootstrap-file)
120While this is like, the *dumbest* way to do this, it's what I'm doing right now. I'm going to slap a TODO on here because I really should make it better &#x2013; like, `auth-sources` hooked into KeePassXC somehow&#x2026; ? Maybe follow [Bill Dietrich's setup](https://www.billdietrich.me/Authentication.html?expandall=1#KeePassXCandSecretService). 119 (with-current-buffer
121
122 (require 'acdw-secrets)
123
124
125# Early initiation
126
127Starting with version 27.1, Emacs loads `early-init.el` *before* `init.el`, setting up early stuff like package management, etc. Since I use an alternative package manager, I have to bootstrap it here.
128
129Of course, I also want to set some really early-on settings here too, like `load-prefer-newer` &#x2013; why not?
130
131 ;; early-init.el -*- lexical-binding: t; no-byte-compile: t -*-
132 (setq load-prefer-newer t)
133
134
135## Increase the garbage collector
136
137Let's try to speed startup times by increasing the garbage collector's threshold while running init. Note the hook afterwards that restores it to a reasonable default.
138
139 (setq gc-cons-threshold (* 100 100 1000))
140
141 (add-hook 'after-init-hook
142 (lambda ()
143 (setq gc-cons-threshold (* 100 100 100))
144 (message "gc-cons-threshold restored to %S"
145 gc-cons-threshold)))
146
147
148## Add more paths to the `exec-path`
149
150When using Windows (at work), I need to use the PortableGit installation I've downloaded, since I don't have Admin privileges.
151
152 (when (eq system-type 'windows-nt)
153 (dolist (path '("c:/Users/aduckworth/Downloads/emacs/bin"
154 "C:/Users/aduckworth/Downloads/PortableGit/bin"
155 "C:/Users/aduckworth/Downloads/PortableGit/usr/bin"))
156 (add-to-list 'exec-path path)))
157
158Elsewhere, I want to add a few more paths to the `exec-path` as well, since I store scripts in a couple of places at ~.
159
160 (dolist (path `(,(expand-file-name "bin"
161 user-emacs-directory)
162 ,(expand-file-name "~/bin")
163 ,(expand-file-name "~/.local/bin")
164 ,(expand-file-name "~/Scripts")))
165 (add-to-list 'exec-path path))
166
167
168## Bootstrap [straight.el](https://github.com/raxod502/straight.el)
169
170So far, this is the best package manager I've used. It allows for *truly* declarative package management (if I don't specify a package here, it doesn't get loaded), easy installation from pretty much any source (as long as it's got a git repo), *and* it hooks into `use-package`!
171
172The one annoying thing is that this bootstrap code doesn't work on Windows for some reason. I'm too lazy to really try and figure out why, so when I need to bootstrap on Windows (pretty rare, TBH), I just [download the master-branch zip file](https://github.com/raxod502/straight.el/archive/master.zip) and extract it to `~/.emacs.d/straight/repos/`.
173
174 (defvar bootstrap-version)
175 (let ((bootstrap-file
176 (expand-file-name "straight/repos/straight.el/bootstrap.el"
177 user-emacs-directory))
178 (bootstrap-version 5))
179 (unless (file-exists-p bootstrap-file)
180 (with-current-buffer
181 (url-retrieve-synchronously
182 "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
183 'silent 'inhibit-cookies)
184 (goto-char (point-max))
185 (eval-print-last-sexp)))
186 (load bootstrap-file nil 'nomessage))
187
188
189## &#x2026; but first: override the definition of straight.el to use the `develop` branch
190
191For the KeePassXC bits later, I need the `develop` branch of straight, so I can pass a `:build` keyword. I can do this, but I have to override the recipe for `straight.el` itself. I do that here. For more information, see [the README](https://github.com/raxod502/straight.el#overriding-recipes).
192
193 (setq straight-repository-branch "develop")
194
195 (defvar bootstrap-version)
196 (let ((bootstrap-file
197 (expand-file-name "straight/repos/straight.el/bootstrap.el"
198 user-emacs-directory))
199 (bootstrap-version 5))
200 (unless (file-exists-p bootstrap-file)
201 (with-current-buffer
202 (url-retrieve-synchronously 120 (url-retrieve-synchronously
203 "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 121 "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
204 'silent 'inhibit-cookies) 122 'silent 'inhibit-cookies)
205 (goto-char (point-max)) 123 (goto-char (point-max))
206 (eval-print-last-sexp))) 124 (eval-print-last-sexp)))
207 (load bootstrap-file nil 'nomessage)) 125 (load bootstrap-file nil 'nomessage))
208
209
210## Use [use-package](https://jwiegley.github.io/use-package/)
211
212Like I said, `straight.el` hooks into `use-package` easily. These two lines get the latter to use the former by default.
213
214 (setq straight-use-package-by-default t)
215 (straight-use-package 'use-package)
216
217
218## Keep `~/.emacs.d` tidy with [no-littering](https://github.com/emacscollective/no-littering)
219
220I'll be honest &#x2013; I don't really notice this package. But I think that's the point. It keeps Emacs (and packages) from throwing files all over the place, so I have a clean `ls -l`. Since I want to run this code as early as possible, I use the `straight-use-package` form instead of `use-package`.
221
222 (straight-use-package 'no-littering)
223 (require 'no-littering)
224 126
225 127
226## Additional `use-package` keywords 128<a id="org9392b5d"></a>
227 129
130### Use-package
228 131
229### [:custom-update](https://github.com/a13/use-package-custom-update) 132 (setq straight-use-package-by-default t)
133 (straight-use-package 'use-package)
230 134
231The `:custom-update` keyword lets me do this:
232 135
233 (use-package package 136<a id="orgc93ae09"></a>
234 :custom-update
235 (package-list '(1 2 3)))
236 137
237instead of this: 138### Extra use-package keywords
238 139
239 (use-package package 1401. :custom-update
240 :config
241 (add-to-list 'package-list '(1 2 3)))
242 141
243It's not &#x2026; perfect, but it's kind of nice. 142 (straight-use-package
143 '(use-package-custom-update
144 :host "github"
145 :repo "a13/use-package-custom-update"))
146
147 (require 'use-package-custom-update)
244 148
245 (use-package use-package-custom-update
246 :straight (use-package-custom-update
247 :host github
248 :repo "a13/use-package-custom-update"))
249
250
251## Setup [async](https://github.com/jwiegley/emacs-async)
252
253I thought this was included in Emacs at first, but it's not &#x2013; so we need to install and require it.
254
255 (straight-use-package 'async)
256 (require 'async)
257
258
259# Macros
260
261
262## Customizing variables
263 149
264I like `use-package` a lot, but I don't like using those shims you see in a lot of other Emacs configs where they use `(use-package emacs)` forms and stuff like that &#x2013; it just feels dirty. Plus, `straight` gets confused about those packages sometimes. So, since I'm actually *configuring* Emacs in this Org file, which is nicely organized anyway, I can just set settings the old-school way. 150<a id="org7cae7fe"></a>
265 151
266Except. Using `setq` is actually *not* recommended any more, because `customize-set-variable` is more expressive and can include side-effects. However, not all settings are customizable, *and* `customize-set-variable` is like, way longer to type. So I've decided to write a little macro (my first!) to copy `use-package`'s `:custom` keyword, except &#x2026; *outside* `use-package`. I've called it `cuss`, because I have a terrible sense of humor. 152## Customize variables
267 153
268 (defmacro cuss (var val)
269 "Basically `use-package''s `:custom', but without using either."
270 `(progn
271 (funcall (or (get ',var 'custom-set) #'set-default)
272 ',var ,val)))
273 154
155<a id="org126d855"></a>
274 156
275# Theme: [Modus](https://protesilaos.com/modus-themes/) 157### Put customizations in a separate file
276 158
277Protesilaos Stavrou's *excellent* theme pair. At some point I'll probably write my own that's really minimal and does some funky stuff with faces, but until then, these really are the best I've used. 159 (setq custom-file
160 (expand-file-name "custom.el" user-emacs-directory))
278 161
279The big `dolist` form is from [his documentation](https://protesilaos.com/modus-themes/#h:a897b302-8e10-4a26-beab-3caaee1e1193); it basically allows me to configure both themes before loading them. I've tweaked his code a little to use `use-package`.
280 162
281 (defmacro modus-themes-format-sexp (sexp &rest objects) 163<a id="org2cf1d1a"></a>
282 `(eval (read (format ,(format "%S" sexp) ,@objects))))
283 164
284 (dolist (theme '("operandi" "vivendi")) 165### A macro for ease of customization
285 (modus-themes-format-sexp
286 (use-package modus-%1$s-theme
287 :custom
288 (modus-%1$s-theme-slanted-constructs t)
289 (modus-%1$s-theme-bold-constructs t)
290 (modus-%1$s-theme-fringes nil)
291 (modus-%1$s-theme-mode-line '3d)
292 (modus-%1$s-theme-syntax 'yellow-comments)
293 (modus-%1$s-theme-intense-hl-line nil)
294 (modus-%1$s-theme-intense-paren-match t)
295 (modus-%1$s-theme-links nil)
296 (modus-%1$s-theme-no-mixed-fonts nil)
297 (modus-%1$s-theme-prompts nil)
298 (modus-%1$s-theme-completions nil)
299 (modus-%1$s-theme-diffs nil)
300 (modus-%1$s-theme-org-blocks 'grayscale)
301 (modus-%1$s-theme-headings
302 '((1 . section)
303 (2 . line)
304 (t . rainbow-line)))
305 (modus-%1$s-theme-variable-pitch-headings t)
306 (modus-%1$s-theme-scale-headings t)
307 (modus-%1$s-theme-scale-1 1.1)
308 (modus-%1$s-theme-scale-2 1.15)
309 (modus-%1$s-theme-scale-3 1.21)
310 (modus-%1$s-theme-scale-4 1.27)
311 (modus-%1$s-theme-scale-5 1.33)
312 :custom-face
313 (font-lock-comment-face
314 ((t (:inherit (custom-comment italic variable-pitch))))))
315 theme))
316 166
167 (defmacro cuss (var val &optional docstring)
168 "Basically `:custom' from `use-package', broken out."
169 `(funcall (or (get ',var 'custom-set) #'set-default)
170 ',var ,val))
317 171
318## Theme changer
319 172
320I also want to switch themes between night and day. 173<a id="orga6c0096"></a>
321 174
322 (use-package theme-changer 175## Keep a tidy `~/.emacs`
323 :custom
324 (calendar-latitude 30.39)
325 (calendar-longitude -91.83)
326 :config
327 (change-theme 'modus-operandi 'modus-vivendi))
328 176
177 (use-package no-littering
178 :custom
179 (backup-directory-alist
180 `((".*" . ,(no-littering-expand-var-file-name "backup/"))))
181 (auto-save-file-name-transforms
182 `((".*" ,(no-littering-expand-var-file-name "autosaves/") t)))
183 (save-place-file
184 (no-littering-expand-var-file-name "places"))
185 (undo-fu-session-directory
186 (no-littering-expand-var-file-name "undos/"))
187 (undohist-directory
188 (no-littering-expand-var-file-name "undos/"))
189 (elpher-certificate-directory
190 (no-littering-expand-var-file-name "elpher-certificates/")))
191
192 (dolist (dir '("backup"
193 "autosaves"
194 "undos"
195 "elpher-certificates"))
196 (make-directory (no-littering-expand-var-file-name dir) t))
329 197
330# Simplify GUI
331 198
199<a id="org1ecbcc5"></a>
332 200
333<a id="org1f12d35"></a> 201# Look and Feel
334 202
335## Frame defaults
336 203
337I want no toolbar, menubar, or scrollbars (ideally I'd have a vertical scrollbar if necessary, but apparently that's too much to ask the Emacs devs); and fringes and window dividers 2 pixels wide. 204<a id="org23fb19e"></a>
338 205
339 (cuss default-frame-alist 206## Simplify the UI
340 '((tool-bar-lines . 0)
341 (menu-bar-lines . 0)
342 (vertical-scroll-bars . nil)
343 (horizontal-scroll-bars . nil)
344 (right-divider-width . 2)
345 (bottom-divider-width . 2)
346 (left-fringe-width . 2)
347 (right-fringe-width . 2)))
348 207
349 208
350## Minibuffer window/frame defaults 209<a id="orgad64258"></a>
351 210
352Of course, on the minibuffer, I want to make sure there's no scrollbar &#x2013; even if I change my mind on `vertical-scroll-bars`, above. 211### Tool bars and menu bars
353 212
354 (cuss minibuffer-frame-alist 213 (cuss default-frame-alist
355 '((width . 80) 214 '((tool-bar-lines . 0)
356 (height . 2) 215 (menu-bar-lines . 0)))
357 (vertical-scrollbars . nil))) 216
217 (menu-bar-mode -1)
218 (tool-bar-mode -1)
358 219
359 (set-window-scroll-bars (minibuffer-window) nil nil)
360 220
221<a id="org9b2f49e"></a>
361 222
362## Remove unneeded GUI elements 223### Scroll bars
363 224
364The [Frame Defaults](#org1f12d35) section sets up the frame to be free of visual clutter, but *this* section allows us to toggle that clutter's visibility easily, with one call to each of these functions. 225 (add-to-list 'default-frame-alist '(vertical-scroll-bars . nil))
226 (scroll-bar-mode -1)
227
228 (add-to-list 'default-frame-alist '(horizontal-scroll-bars . nil))
229 (horizontal-scroll-bar-mode -1)
365 230
366 (menu-bar-mode -1)
367 (tool-bar-mode -1)
368 (scroll-bar-mode -1)
369 (horizontal-scroll-bar-mode -1)
370 231
232<a id="orgf1c5f65"></a>
371 233
372## Tabs 234### Dialog boxen
373 235
374I'm kind of getting into Emacs tabs &#x2013; but I like not showing the `tab-bar` when there's only one. 236 (cuss use-dialog-box nil)
375 237
376 (cuss tab-bar-show 1)
377 238
378 (cuss tab-bar-tab-name-function 'tab-bar-tab-name-current-with-count) 239<a id="orgedf9e78"></a>
379 240
241### Shorten confirmations
380 242
381## Word wrap and operate visually 243 (fset 'yes-or-no-p #'y-or-n-p)
382 244
383`global-visual-line-mode` is one of those which, in my opinion, should be a default. There's only one place I don't want to wrap words, and that's in `dired`, which I can set individually in its config.
384 245
385 (global-visual-line-mode 1) 246<a id="org1643ce2"></a>
386 247
248### Remove the bell
387 249
388## Modeline 250 (cuss visible-bell (not (string= (system-name) "larry")))
389 251
390 252
391### [smart-mode-line](https://github.com/Malabarba/smart-mode-line) 253<a id="org3996a6f"></a>
392 254
393 (use-package smart-mode-line 255### Tell Ediff to setup windows better
394 :custom
395 (sml/no-confirm-load-theme t)
396 :config
397 (sml/setup))
398 256
257 (declare-function ediff-setup-windows-plain "ediff-wind.el")
258 (cuss ediff-window-setup-function #'ediff-setup-windows-plain)
399 259
400### [rich-minority](https://github.com/Malabarba/rich-minority)
401 260
402`smart-mode-line` comes with `rich-minority` for taking care of minor modes in the modeline, so I'm not going to *also* use `diminish` or anything. However, `rich-minority` has kind of a hinky way of adding modes to the whitelist, so I had to write my own function to do so. 261<a id="orgcdf874b"></a>
403 262
404This confuration means that, by default, no minor modes are shown; if you want a minor mode to be shown (like `word-count-mode` for me), call `(rm/whitelist-add "REGEXP")`. 263## Tweak the remaining UI
405 264
406 (defun rm/whitelist-add (regexp)
407 "Add a REGEXP to the whitelist for `rich-minority'."
408 (if (listp 'rm--whitelist-regexps)
409 (add-to-list 'rm--whitelist-regexps regexp)
410 (setq rm--whitelist-regexps `(,regexp)))
411 (setq rm-whitelist
412 (mapconcat 'identity rm--whitelist-regexps "\\|")))
413 265
414 (use-package rich-minority 266<a id="org187505c"></a>
415 :config
416 (rm/whitelist-add "^$"))
417 267
268### Window dividers
418 269
419## Minibuffer 270 (add-to-list 'default-frame-alist '(right-divider-width . 2))
271 (add-to-list 'default-frame-alist '(bottom-divider-width . 2))
420 272
421 273
422### Keep cursor from going into the prompt 274<a id="org3fd2bc6"></a>
423 275
424from [Ergo Emacs](http://ergoemacs.org/emacs/emacs_stop_cursor_enter_prompt.html). 276### Fringes
425 277
426 (cuss minibuffer-prompt-properties 278 (add-to-list 'default-frame-alist '(left-fringe-width . 2))
427 '(read-only t cursor-intangible t face minibuffer-prompt)) 279 (add-to-list 'default-frame-alist '(right-fringe-width . 2))
428 280
429 281
430## Show `^L` as a line 282<a id="org8ff32ea"></a>
431 283
432I like using the form-feed character to separate pages, it turns out. 'Tis nice. This package turns that character into a nice long line. 284### Minibuffer
433 285
434 (use-package form-feed 2861. Setup the minibuffer frame
435 :hook
436 ((text-mode prog-mode) . form-feed-mode))
437 287
288 (cuss minibuffer-frame-alist
289 '((width . 80)
290 (height . 2)
291 (vertical-scrollbars . nil)))
292
293 (set-window-scroll-bars (minibuffer-window) nil nil)
438 294
439## Cursor 2952. Keep the cursor from going into the prompt
440 296
441I want my cursor to be a bar in focused windows, but a hollow box in non-focused windows. 297 (cuss minibuffer-prompt-properties
298 '(read-only t cursor-intangible t face minibuffer-prompt))
442 299
443 (cuss cursor-type 'bar)
444 (cuss cursor-in-non-selected-windows 'hollow)
445 300
301<a id="orgef2a000"></a>
446 302
447# Typesetting 303### Tabs
448 304
3051. Show the tabs as current buffer, plus window count
449 306
450## Fonts 307 (cuss tab-bar-tab-name-function #'tab-bar-tab-name-current-with-count)
451 308
452This is the best way I've come up with to specify a number of different fonts that apply depending on what's applied. To be honest, I didn't really come up with the `font-candidate` function, though &#x2013; I got it from the ["Testing if fonts are available?"](https://www.emacswiki.org/emacs/SetFonts#toc11) section of the SetFonts page on EmacsWiki. 3092. Only show the tab bar when there's more than one tab
453 310
454See [this StackExchange question and answer](https://emacs.stackexchange.com/questions/12351/when-to-call-find-font-if-launching-emacs-in-daemon-mode) for more information on why I have these font settings applied in a hook. 311 (cuss tab-bar-show 1)
455 312
456 (require 'cl)
457 (defun font-candidate (&rest fonts)
458 (loop for font in fonts
459 when (find-font (font-spec :name font))
460 return font))
461 313
462 (defun acdw/setup-fonts () 314<a id="orge57d1b2"></a>
463 "Setup fonts. This has to happen after the frame is set up for
464 the first time, so add it to `focus-in-hook'. It removes
465 itself."
466 (interactive)
467 (set-face-attribute 'default nil
468 :font
469 (font-candidate
470 "Libertinus Mono-11"
471 "Linux Libertine Mono O-11"
472 "Go Mono-11"
473 "Consolas-11"))
474 315
475 (set-face-attribute 'fixed-pitch nil 316### Cursor
476 :font
477 (font-candidate
478 "Libertinus Mono-11"
479 "Linux Libertine Mono O-11"
480 "Go Mono-11"
481 "Consolas-11"))
482 317
483 (set-face-attribute 'variable-pitch nil 318 (cuss cursor-type 'bar)
484 :font 319 (cuss cursor-in-non-selected-windows 'hollow)
485 (font-candidate
486 "Libertinus Serif-13"
487 "Linux Libertine O-12"
488 "Georgia-11"))
489 320
490 (remove-hook 'focus-in-hook #'acdw/setup-fonts))
491 321
492 (add-hook 'focus-in-hook #'acdw/setup-fonts) 322<a id="orgb3f29a9"></a>
493 323
324### Buffer names
494 325
495## [unicode-fonts](https://github.com/rolandwalker/unicode-fonts) 326 (require 'uniquify)
327 (cuss uniquify-buffer-name-style 'forward)
496 328
497This does something similar to the above code, but for the entirety of the Unicode field (I think).
498 329
499 (use-package unicode-fonts 330<a id="org2627b1e"></a>
500 :config
501 (unicode-fonts-setup))
502 331
332### Buffer boundaries
503 333
504## Variable pitch faces 334 (cuss indicate-buffer-boundaries
505 335 '((top . right)
506One reason I like the Modus themes so much is that they have *excellent* support for variable-pitch faces, and mixing them with fixed-pitch faces in, say, Org Mode. That means I can enable `variable-pitch-mode` in all my `text-mode`-derived buffers. 336 (bottom . right)
507 337 (t . nil)))
508 (add-hook 'text-mode-hook #'variable-pitch-mode) 338
509 339 (cuss indicate-empty-lines t)
510
511## Padding
512
513This has been taken from ["Ricing Org Mode"](https://lepisma.xyz/2017/10/28/ricing-org-mode/) &#x2013; of course, I want the typographic niceties everywhere.
514
515 (cuss line-spacing 0.1)
516
517 340
518# Ease of use
519 341
342<a id="org1fc3c6d"></a>
520 343
521## Startup 344## Startup
522 345
523I want a minimal screen when I start Emacs. Based on the beauty of configs like [Nicolas Rougier's](https://github.com/rougier/elegant-emacs) [splash screen](https://github.com/rougier/emacs-splash) [experiments](https://github.com/rougier/nano-emacs), I might try my hand at some kind of splash screen or dashboard &#x2013; but until then, a simple "Hi there!" will suffice 😎 346 (cuss inhibit-startup-buffer-menu t)
524 347 (cuss inhibit-start-screen t)
525 (cuss inhibit-startup-buffer-menu t) 348 (cuss initial-buffer-choice t)
526 (cuss inhibit-startup-screen t) 349 (cuss initial-scratch-message ";; Hi there!\n")
527 (cuss initial-buffer-choice t) 350
528 (cuss initial-scratch-message ";; Hi there!\n") 351
529 352<a id="org207a1bd"></a>
530 353
531## Completing-read niceties 354## Theme
532 355
533`completing-read` is Emacs's selection-narrowing-slash-completion framework thing. There's a bunch of packages for it, including `ido`, `icomplete`, `ivy`, and `helm`. I use raxod52's `selectrum` and others, which *extend* without *clobbering* existing Emacs functionality. Plus they seem to run faster, at least on Windows. 356 (use-package modus-themes
534 357 :straight (modus-themes
535 358 :host gitlab
536### [selectrum](https://github.com/raxod502/selectrum) 359 :repo "protesilaos/modus-themes"
537 360 :branch "main")
538`selectrum` is the basic *sorting and selecting items from a list* functionality. It's a drop-in replacement for `ido` or the really basic tab-completion Emacs has for, say, `find-file`. 361 :custom
539 362 (modus-themes-slanted-constructs t)
540 (use-package selectrum 363 (modus-themes-bold-constructs t)
541 :config 364 (modus-themes-fringes nil)
542 (selectrum-mode 1)) 365 (modus-themes-mode-line '3d)
543 366 (modus-themes-syntax 'yellow-comments)
544 367 (modus-themes-intense-hl-line nil)
545### [prescient](https://github.com/raxod502/prescient.el) 368 (modus-themes-paren-match 'intense-bold)
546 369 (modus-themes-links nil)
547`prescient` helps `selectrum` be more intelligent about sorting the candidates in a list &#x2013; it's in charge of the *filtering and sorting* bit of `completing-read` and friends. It has an algorithm that works well enough for me, though I keep hearing about [orderless](https://github.com/oantolin/orderless), enough to maybe try it as well sometime. 370 (modus-themes-no-mixed-fonts nil)
548 371 (modus-themes-prompts nil)
549 (use-package prescient 372 (modus-themes-completions nil)
550 :config 373 (modus-themes-diffs nil)
551 (prescient-persist-mode 1)) 374 (modus-themes-org-blocks 'grayscale)
552 375 (modus-themes-headings
553 (use-package selectrum-prescient 376 '())
554 :after (selectrum prescient) 377 (modus-themes-variable-pitch-headings t)
555 :config 378 (modus-themes-scale-headings t)
556 (selectrum-prescient-mode 1)) 379 (modus-themes-scale-1 1.1)
557 380 (modus-themes-scale-2 1.15)
558 381 (modus-themes-scale-3 1.21)
559### [consult](https://github.com/minad/cconsult) 382 (modus-themes-scale-4 1.27)
560 383 (modus-themes-scale-5 1.33)
561`consult` is the newest package I have with this setup, and it kind of brings the `selectrum` experience up to par with `ivy`'s &#x2013; it provides functions that list, say, recently used files *alongside* buffers, allow you to search lines and go to them, etc. It seems pretty nice so far. 384 :custom-face
385 (font-lock-comment-face
386 ((t (:inherit (custom-comment italic variable-pitch)))))
387 :init
388 (load-theme 'modus-operandi t))
389
390
391<a id="org52f6c8c"></a>
392
393### Fonts
394
3951. Define fonts
396
397 (defun font-candidate (&rest fonts)
398 (catch :font
399 (dolist (font fonts)
400 (if (find-font (font-spec :name font))
401 (throw :font font)))))
402
403 (defun acdw/setup-fonts ()
404 "Setup fonts. This has to happen after the frame is setup for
405 the first time, so it should be added to `window-setup-hook'. It
406 removes itself from that hook."
407 (interactive)
408 (set-face-attribute 'default nil
409 :font
410 (font-candidate
411 "Libertinus Mono-11"
412 "Linux Libertine Mono O-11"
413 "Go Mono-10"
414 "Consolas-10"))
415
416 (set-face-attribute 'fixed-pitch nil
417 :font
418 (font-candidate
419 "Libertinus Mono-11"
420 "Linux Libertine Mono O-11"
421 "Go Mono-10"
422 "Consolas-10"))
423
424 (set-face-attribute 'variable-pitch nil
425 :font
426 (font-candidate
427 "Libertinus Serif-13"
428 "Linux Libertine O-12"
429 "Georgia-11"))
430
431 (remove-hook 'window-setup-hook #'acdw/setup-fonts))
432
433 (add-hook 'window-setup-hook #'acdw/setup-fonts)
434
4352. Variable-pitch in text modes
436
437 (add-hook 'text-mode-hook #'variable-pitch-mode)
438
4393. Line spacing
440
441 (cuss line-spacing 0.1)
442
4434. Unicode fonts
444
445 (use-package unicode-fonts
446 :config
447 (unicode-fonts-setup))
448
449
450<a id="org6cbcfe5"></a>
451
452# Interactivity
453
454
455<a id="org7f26398"></a>
456
457## Selectrum
458
459 (use-package selectrum
460 :config
461 (selectrum-mode +1))
462
463
464<a id="orgea8df9e"></a>
465
466## Prescient
467
468 (use-package prescient
469 :config
470 (prescient-persist-mode +1))
471
472 (use-package selectrum-prescient
473 :after (selectrum prescient)
474 :config
475 (selectrum-prescient-mode +1))
476
477
478<a id="org8818eb9"></a>
562 479
563By the way, the [Reddit announcement thread for consult](https://www.reddit.com/r/emacs/comments/k3c0u7) has a great comment by the author detailing [the differences between different completing-read implementations](https://www.reddit.com/r/emacs/comments/k3c0u7/consult_counselswiper_alternative_for/ge460z3/) that actually is what convinced me to try `consult`. 480## Consult
564 481
565 (use-package consult 482 (use-package consult
566 :after (selectrum) 483 :after (selectrum)
567 :straight (consult 484 :straight (consult
568 :host github 485 :host github
569 :repo "minad/consult") 486 :repo "minad/consult")
570 :bind (("C-x b" . consult-buffer) 487 :bind
571 ("C-x 4 b" . consult-buffer-other-window) 488 (("C-x b" . consult-buffer)
572 ("C-x 5 b" . consult-buffer-other-frame) 489 ("C-x 4 b" . consult-buffer-other-window)
573 ("M-g o" . consult-outline) 490 ("C-x 5 b" . consult-buffer-other-frame)
574 ("M-g l" . consult-line) 491 ("M-g o" . consult-outline)
575 ("M-y" . consult-yank-pop) 492 ("M-g l" . consult-line)
576 ("<help> a" . consult-apropos)) 493 ("M-y" . consult-yank-pop)
577 :init 494 ("<help> a" . consult-apropos))
578 (fset 'multi-occur #'consult-multi-occur) 495 :init
579 (consult-annotate-mode) 496 (fset 'multi-occur #'consult-multi-occur))
580 :config
581 (setf (alist-get 'execute-extended-command consult-annotate-alist)
582 #'consult-annotate-command-full))
583
584
585### Ignore case
586
587I don't like holding the Shift key if I can help it.
588
589 (cuss completion-ignore-case t)
590 (cuss read-buffer-completion-ignore-case t)
591 (cuss read-file-name-completion-ignore-case t)
592
593
594## [ctrlf](https://github.com/raxod502/ctrlf)
595
596The biggest reason I use this over the default functionality of `C-s` is that `ctrlf-forward-*` wraps the search around by default.
597
598 (use-package ctrlf
599 :custom
600 (ctrlf-show-match-count-at-eol nil)
601 :bind
602 ("C-s" . ctrlf-forward-regexp)
603 ("C-r" . ctrlf-backward-regexp)
604 ("C-M-s" . ctrlf-forward-literal)
605 ("C-M-r" . ctrlf-backward-literal)
606 :config
607 (ctrlf-mode 1))
608
609
610## [which-key](https://github.com/justbur/emacs-which-key)
611
612This package is really helpful for discovering functionality. When I get more adept in my Emacs-fu, I might remove this.
613
614 (use-package which-key
615 :custom
616 (which-key-popup-type 'minibuffer)
617 :config
618 (which-key-mode))
619
620
621## Miscellaneous settings
622
623Maybe a better title for this section is **Other settings** &#x2013; or maybe I should put them somewhere else entirely.
624
625
626### Set `view-mode` when in a read-only file
627 497
628`view-mode` gives easy-to-use keybindings, like Space for page-down, etc., which are nice to have when you can't edit the file anyway.
629 498
630 (cuss view-read-only t) 499<a id="orgd31a964"></a>
631 500
501## Marginalia
632 502
633### Don't use dialog boxen 503 (use-package marginalia
634 504 :straight (marginalia
635 (cuss use-dialog-box nil) 505 :host github
636 506 :repo "minad/marginalia"
637 507 :branch "main")
638### Enable all functions 508 :custom
639 509 (marginalia-annotators
640By default, Emacs disables some commands, because NeWbIeS wOuLd GeT cOnFuSeD or some ish. I just want to use the dang editor! 510 '((command . marginalia-annotate-command-full)
641 511 (customize-group . marginalia-annotate-customize-group)
642 (cuss disabled-command-function nil) 512 (variable . marginalia-annotate-variable)
643 513 (face . marginalia-annotate-face)
644 514 (symbol . marginalia-annotate-symbol)
645### Shorter confirmations 515 (variable . marginalia-annotate-variable)
646 516 (package . marginalia-annotate-package)))
647Instead of making me type *yes* or *no*, just let me hit the *y* or *n* key. 517 :init
648 518 (marginalia-mode +1))
649 (fset 'yes-or-no-p #'y-or-n-p)
650
651
652### Uniquify buffer names
653
654This names buffers with the same basename (e.g., `~/.config/emacs/config.org` and `~/.emacs.d/config.org`) in a better way than the default (`config.org<1>`, etc).
655
656 (require 'uniquify)
657 (cuss uniquify-buffer-name-style 'forward)
658
659
660### Show buffer boundaries
661
662These little L-shaped graphics at the top and bottom of buffers don't do anything, but I like 'em.
663
664 (cuss indicate-buffer-boundaries
665 '((top . right)
666 (bottom . right)
667 (t . nil)))
668
669
670### Hippie expand
671
672At some point, will probably replace with [company](https://company-mode.github.io/).
673
674 (global-set-key (kbd "M-/") 'hippie-expand)
675
676
677### "[better defaults](https://git.sr.ht/~technomancy/better-defaults/tree/master/better-defaults.el)"
678
679Most of these come from technomancy's repo, linked above, just copy-pasted into here.
680
681 (cuss save-interprogram-paste-before-kill t)
682 (cuss apropos-do-all t)
683 (cuss mouse-yank-at-point t)
684 (cuss require-final-newline t)
685 (cuss visible-bell (not (string= (system-name) "larry")))
686 (cuss ediff-window-setup-function #'ediff-setup-windows-plain)
687
6881. Zap-up-to-char, not zap-to-char
689
690 Similarly to `ibuffer`, this is a Better default™.
691
692 (autoload 'zap-up-to-char "misc"
693 "Kill up to, but not including, ARGth occurrence of CHAR." t)
694
695 (global-set-key (kbd "M-z") 'zap-up-to-char)
696
6972. iBuffer
698
699 A Better Default™ for `C-x C-b`. I don't really use this, but everyone says it's worth it, so it's there.
700
701 (global-set-key (kbd "C-x C-b") 'ibuffer)
702 519
703 520
704### So-long-mode 521<a id="org6e4913f"></a>
705 522
706I figure, why not go ahead and make Emacs deal with really long lines better? Can't hurt, right? 523## Ignore case
707 524
708 (if (boundp 'global-so-long-mode) 525 (cuss completion-ignore-case t)
709 (global-so-long-mode)) 526 (cuss read-buffer-completion-ignore-case t)
527 (cuss read-file-name-completion-ignore-case t)
710 528
711 529
712### Change `just-one-space` to `cycle-space` 530<a id="org416dd18"></a>
713 531
714I keep forgetting to actually *use* this keybind (I think it's `M-SPC`?), but cycling spacing seems *way* more useful than the default `just-one-space` function. 532## Search
715 533
716 (defun acdw/cycle-spacing-1 () 534 (use-package ctrlf
717 (interactive) 535 :custom
718 (cycle-spacing -1)) 536 (ctrlf-show-match-count-at-eol nil)
537 :bind
538 ("C-s" . ctrlf-forward-regexp)
539 ("C-r" . ctrlf-backward-regexp)
540 ("C-M-s" . ctrlf-forward-literal)
541 ("C-M-r" . ctrlf-backward-literal)
542 :config
543 (ctrlf-mode +1))
719 544
720 (bind-key [remap just-one-space] #'acdw/cycle-spacing-1)
721 545
546<a id="orgb20768d"></a>
722 547
723# Persistence 548# Persistence
724 549
725Honestly, persistence across sessions was one of the best things about my well-tuned Vim setup. Here's where I try to repeat that with Emacs.
726
727
728## Auto-saves with [super-save](https://github.com/bbatsov/super-save)
729
730The default `auto-save` functionality isn't &#x2026; *enough* for me. I want to *actually* save the files, and I don't care about `#file#` stuff. So &#x2026; I use this package.
731
732 (use-package super-save
733 :custom
734 (auto-save-default nil)
735 (super-save-exclue '(".gpg"))
736 :config
737 (super-save-mode 1))
738
739
740## Backup files
741
742To be honest, I probably don't need backup files at all. At some point, I will probably delete this.
743
744 (cuss backup-directory-alist
745 `((".*" . ,(no-littering-expand-var-file-name "backup/"))))
746
747 (cuss backup-by-copying 1)
748 (cuss delete-old-versions -1)
749 (cuss version-control t)
750 (cuss vc-make-backup-files t)
751
752
753## Recent files
754
755Since I apparently *only* edit my `config.org`, this is also probably not necessary &#x2013; I'd be better off just adding a `(find-file (concat (user-emacs-directory "config.org")))` at the end 😎
756
757But until then, it's really nice to have a `recentf` list.
758
759 (require 'recentf)
760
761 (add-to-list 'recentf-exclude
762 '(no-littering-var-directory
763 no-littering-etc-directory))
764
765 (cuss recentf-max-menu-items 100)
766 (cuss recentf-max-saved-items 100)
767
768 (recentf-mode 1)
769
770
771### Easily navigate recent files
772
773Now I'm going through this, I might not need this function any more. I'll have to see how `consult` goes.
774
775 (defun recentf-find-file ()
776 "Find a recent file using `completing-read'."
777 (interactive)
778 (let ((file (completing-read "Recent file: " recentf-list nil t)))
779 (when file
780 (find-file file))))
781
782 (bind-key "C-x C-r" #'recentf-find-file)
783
784
785## Save places in visited files
786
787 (require 'saveplace)
788
789 (cuss save-place-file (no-littering-expand-var-file-name "places"))
790
791 (cuss save-place-forget-unreadable-files
792 (not (eq system-type 'windows-nt)))
793
794 (save-place-mode 1)
795 550
551<a id="org7dfee32"></a>
796 552
797## Save history 553## Save history
798 554
799 (require 'savehist) 555 (require 'savehist)
800 556
801 (cuss savehist-additional-variables 557 (cuss savehist-additional-variables
802 '(kill-ring 558 '(kill-ring
803 search-ring 559 search-ring
804 regexp-search-ring)) 560 regexp-search-ring))
561
562 (cuss savehist-save-minibuffer-history t)
563
564 (cuss history-length t)
565
566 (cuss history-delete-duplicates t)
567
568 (savehist-mode +1)
805 569
806 (cuss savehist-save-minibuffer-history t)
807
808 (cuss history-length t)
809
810 (cuss history-delete-duplicates t)
811 570
812 (savehist-mode 1) 571<a id="org0f20005"></a>
813 572
573## Save places in files
814 574
815## Undo: [undo-fu-session](https://gitlab.com/ideasman42/emacs-undo-fu-session) 575 (require 'saveplace)
576
577 (cuss save-place-forget-unreadable-files
578 (not (eq system-type 'windows-nt)))
579
580 (save-place-mode 1)
816 581
817The other Killer Feature of Neovim when I used it was the perisistent undo. I *think* this works the same. Honestly, undo is giving me a little grief recently; I need to look into it.
818 582
819Note to self: if I *do* switch away from `undo-fu`, look at [undohist](https://github.com/emacsorphanage/undohist). 583<a id="org6d1a477"></a>
820 584
821 (use-package undo-fu-session 585## Recent files
822 :after (no-littering undo-fu)
823 :custom
824 (undo-fu-session-incompatible-files
825 '("COMMIT_EDITMSG\\'"
826 "/git-rebase-todo\\'"))
827 (undo-fu-session-directory
828 (no-littering-expand-var-file-name "undos/"))
829 :config
830 (global-undo-fu-session-mode 1))
831
832
833# General editing
834
835
836## File encoding
837
838I just want to use UTF-8 everywhere, and end all files with UNIX line endings (`^J`, or `LF`). Hell, even Windows Notepad correctly reads UNIX files nowadays (though of course you can't configure it to *save* the files in UNIX-mode). However, since Emacs is ~40 years old, it has a billion different ways to set encodings. This is my best attempt at setting everything up how I want it.
839
840I'm going to be honest &#x2013; most of this is a stab in the dark.
841
842 (set-language-environment 'utf-8)
843 (set-terminal-coding-system 'utf-8)
844 (cuss locale-coding-system 'utf-8)
845 (set-default-coding-systems 'utf-8)
846 (set-selection-coding-system 'utf-8)
847 (prefer-coding-system 'utf-8)
848
849 ;; from https://www.emacswiki.org/emacs/EndOfLineTips
850
851 (defun acdw/no-junk-please-were-unixish ()
852 "Convert line endings to UNIX, dammit."
853 (let ((coding-str (symbol-name buffer-file-coding-system)))
854 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
855 (set-buffer-file-coding-system 'unix))))
856
857 (add-hook 'find-file-hooks #'acdw/no-junk-please-were-unixish)
858
859
860## [undo-fu](https://gitlab.com/ideasman42/emacs-undo-fu)
861
862I've heard that Emacs' undo is weird, so here I am, trying to make it &#x2026;. *less* weird. I keep forgetting I've installed this though, so I might uninstall it at some point.
863
864 (use-package undo-fu
865 :bind
866 ("C-/" . undo-fu-only-undo)
867 ("C-?" . undo-fu-only-redo))
868
869
870## Find/replace: [visual-regexp](https://github.com/benma/visual-regexp.el)
871
872Another replacement for a Killer Feature in Neovim &#x2013; the ease of regexp find/replace was so wonderful, because I could easily see *what* I'd be changing with a `%s` command, as well as *how* it'd change. This works&#x2026; pretty similarly. It could be a little better.
873
874 (use-package visual-regexp
875 :bind
876 ("C-c r" . 'vr/replace)
877 ("C-c q" . 'vr/query-replace))
878
879
880## Visual editing
881
882
883### [volatile-highlights](https://github.com/k-talo/volatile-highlights.el)
884 586
885Highlights text changed by certain operations. 587 (require 'recentf)
588
589 (cuss recentf-max-menu-items 100)
590 (cuss recentf-max-saved-items 100)
591
592 (with-eval-after-load 'no-littering
593 (add-to-list 'recentf-exclude no-littering-var-directory)
594 (add-to-list 'recentf-exclude no-littering-etc-directory))
595
596 (recentf-mode 1)
886 597
887 (use-package volatile-highlights
888 :config
889 (volatile-highlights-mode 1))
890 598
599<a id="org9368a6b"></a>
891 600
892### [expand-region](https://github.com/magnars/expand-region.el) 601### Easily navigate recent files
893 602
894I don't use this a *ton*, but not because it's not useful &#x2013; I just forget it's there sometimes. 603 (defun recentf-find-file ()
604 "Find a recent file using `completing-read'."
605 (interactive)
606 (let ((file (completing-read "Recent file: " recentf-list nil t)))
607 (when file
608 (find-file file))))
609
610 (global-set-key (kbd "C-x C-r") #'recentf-find-file)
895 611
896Basically, it allows you to do like a Kakoune-style incremental widening of the selection by semantic units.
897 612
898 (use-package expand-region 613<a id="orgbb4f91a"></a>
899 :bind
900 ("C-=" . er/expand-region)
901 ("C-+" . er/contract-region))
902 614
615## Undo
903 616
904## Clean up white space on save 617 (use-package undohist
618 :config
619 (undohist-initialize))
905 620
906I'm not sure if I'll *keep* this forever, because in combination with `super-save` I lose the final "thinking spaces" when I shift contexts to another window.
907 621
908 (add-hook 'before-save-hook #'whitespace-cleanup) 622<a id="org52b008a"></a>
909 (add-hook 'before-save-hook #'delete-trailing-whitespace)
910 623
624# Editing
911 625
912## Automatically revert a file to what it is on disk
913 626
914Revert a buffer to reflect what's on disk if it's changed outside of Emacs. 627<a id="orgce838ba"></a>
915 628
916 (global-auto-revert-mode 1) 629## Operate visually on lines
917 630
631 (global-visual-line-mode +1)
918 632
919# Writing
920 633
921Configurations related to writing prose or verse. 634<a id="org6f67996"></a>
922 635
636## Require a final newline
923 637
924## Word count: [wc-mode](https://github.com/bnbeckwith/wc-mode) 638 (cuss require-final-newline t)
925 639
926 (use-package wc-mode
927 :config
928 (rm/whitelist-add "WC")
929 :hook text-mode)
930 640
641<a id="orga2bdb3e"></a>
931 642
932## [visual-fill-column-mode](https://github.com/joostkremers/visual-fill-column) 643## Killing & Yanking
933 644
934Center the text part of the frame within a `fill-column`-sized area in the frame as a whole.
935 645
936 (use-package visual-fill-column 646<a id="org16c1a6b"></a>
937 :custom
938 (split-window-preferred-function
939 'visual-fill-column-split-window-sensibly)
940 (visual-fill-column-center-text t)
941 (fill-column 80)
942 :config
943 (advice-add 'text-scale-adjust
944 :after #'visual-fill-column-adjust)
945 :hook
946 (text-mode . visual-fill-column-mode))
947
948
949### Fix mouse bindings
950
951In `visual-fill-column-mode`, mouse bindings on the margins don't work. In fact, they don't work when *not* in `visual-fill-column-mode`. Let's bind those bindings.
952
953 (dolist (vec '([left-margin wheel-down]
954 [left-margin mouse-5]
955 [right-margin wheel-down]
956 [right-margin mouse-5]))
957 (bind-key vec 'scroll-down-command))
958
959 (dolist (vec '([left-margin wheel-up]
960 [left-margin mouse-4]
961 [right-margin wheel-up]
962 [right-margin mouse-4]))
963 (bind-key vec 'scroll-up-command))
964
965
966## [org-mode](https://orgmode.org/)
967
968Pretty self-explanatory, I think&#x2026;
969
970I need to break this config up and like, comment it better.
971
972 (use-package org
973 :custom
974 (org-startup-indented t)
975 (org-src-tab-acts-natively t)
976 (org-hide-emphasis-markers t)
977 (org-fontify-done-headline t)
978 (org-fontify-whole-heading-line t)
979 (org-fontify-quote-and-verse-blocks t)
980 (org-hide-leading-stars t)
981 (org-hidden-keywords '(author date title))
982 (org-src-window-setup 'current-window)
983 (org-pretty-entities t)
984 (org-ellipsis " ⋯ "))
985
986
987### Make bullets look like centered dots
988
989from [zzamboni.org](https://zzamboni.org/post/beautifying-org-mode-in-emacs/)
990
991 (font-lock-add-keywords
992 'org-mode
993 '(("^ *\\([-+]\\) "
994 (0 (prog1 ()
995 (compose-region (match-beginning 1)
996 (match-end 1)
997 "•"))))))
998
999
1000### [org-superstar](https://github.com/integral-dw/org-superstar-mode)
1001
1002 (use-package org-superstar
1003 :custom
1004 (org-superstar-headline-bullets-list
1005 '(?❧ ?✪ ?③ ?④ ?⑤ ?⑥ ?⑦ ?⑧ ?⑨ ?●))
1006 (org-superstar-cycle-headline-bullets nil)
1007 (org-superstar-item-bullet-alist
1008 '((?* . ?★)
1009 (?+ . ?‣)
1010 (?- . ?•)))
1011 :custom-face
1012 (org-superstar-header-bullet
1013 ((t (:weight normal))))
1014 :hook
1015 (org-mode . org-superstar-mode))
1016
1017
1018### Enable markdown export
1019
1020 (require 'ox-md)
1021
1022
1023### Ensure blank lines between headings and before contents
1024
1025from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#ensure-blank-lines-between-headings-and-before-contents)
1026
1027 ;;;###autoload
1028 (defun unpackaged/org-fix-blank-lines (&optional prefix)
1029 "Ensure that blank lines exist between headings and between
1030 headings and their contents. With prefix, operate on whole
1031 buffer. Ensures that blank lines exist after each headings's
1032 drawers."
1033 (interactive "P")
1034 (org-map-entries
1035 (lambda ()
1036 (org-with-wide-buffer
1037 ;; `org-map-entries' narrows the buffer, which prevents us
1038 ;; from seeing newlines before the current heading, so we
1039 ;; do this part widened.
1040 (while (not (looking-back "\n\n" nil))
1041 ;; Insert blank lines before heading.
1042 (insert "\n")))
1043 (let ((end (org-entry-end-position)))
1044 ;; Insert blank lines before entry content.
1045 (forward-line)
1046 (while (and (org-at-planning-p)
1047 (< (point) (point-max)))
1048 ;; Skip planning lines
1049 (forward-line))
1050 (while (re-search-forward org-drawer-regexp end t)
1051 ;; Skip drawers. You might think that
1052 ;; `org-at-drawer-p' would suffice, but for some reason
1053 ;; it doesn't work correctly when operating on hidden
1054 ;; text. This works, taken from
1055 ;; `org-agenda-get-some-entry-text'.
1056 (re-search-forward "^[ \t]*:END:.*\n?" end t)
1057 (goto-char (match-end 0)))
1058 (unless (or (= (point) (point-max))
1059 (org-at-heading-p)
1060 (looking-at-p "\n"))
1061 (insert "\n"))))
1062 t (if prefix
1063 nil
1064 'tree)))
1065
1066
1067### `org-return-dwim`
1068
1069from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#org-return-dwim)
1070
1071 (defun unpackaged/org-element-descendant-of (type element)
1072 "Return non-nil if ELEMENT is a descendant of TYPE.
1073 TYPE should be an element type, like `item' or `paragraph'.
1074 ELEMENT should be a list like that returned by
1075 `org-element-context'."
1076 ;; MAYBE: Use `org-element-lineage'.
1077 (when-let* ((parent (org-element-property :parent element)))
1078 (or (eq type (car parent))
1079 (unpackaged/org-element-descendant-of type parent))))
1080
1081 ;;;###autoload
1082 (defun unpackaged/org-return-dwim (&optional default)
1083 "A helpful replacement for `org-return'. With prefix, call `org-return'.
1084
1085 On headings, move point to position after entry content. In
1086 lists, insert a new item or end the list, with checkbox if
1087 appropriate. In tables, insert a new row or end the table."
1088 ;; Inspired by John Kitchin: http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/
1089 (interactive "P")
1090 (if default
1091 (org-return)
1092 (cond
1093 ;; Act depending on context around point.
1094
1095 ;; NOTE: I prefer RET to not follow links, but by uncommenting this block,
1096 ;; links will be followed.
1097
1098 ;; ((eq 'link (car (org-element-context)))
1099 ;; ;; Link: Open it.
1100 ;; (org-open-at-point-global))
1101
1102 ((org-at-heading-p)
1103 ;; Heading: Move to position after entry content.
1104 ;; NOTE: This is probably the most interesting feature of this function.
1105 (let ((heading-start (org-entry-beginning-position)))
1106 (goto-char (org-entry-end-position))
1107 (cond ((and (org-at-heading-p)
1108 (= heading-start (org-entry-beginning-position)))
1109 ;; Entry ends on its heading; add newline after
1110 (end-of-line)
1111 (insert "\n\n"))
1112 (t
1113 ;; Entry ends after its heading; back up
1114 (forward-line -1)
1115 (end-of-line)
1116 (when (org-at-heading-p)
1117 ;; At the same heading
1118 (forward-line)
1119 (insert "\n")
1120 (forward-line -1))
1121 ;; FIXME: looking-back is supposed to be called with more arguments.
1122 (while (not (looking-back (rx (repeat 3 (seq (optional blank) "\n")))))
1123 (insert "\n"))
1124 (forward-line -1)))))
1125
1126 ((org-at-item-checkbox-p)
1127 ;; Checkbox: Insert new item with checkbox.
1128 (org-insert-todo-heading nil))
1129
1130 ((org-in-item-p)
1131 ;; Plain list. Yes, this gets a little complicated...
1132 (let ((context (org-element-context)))
1133 (if (or (eq 'plain-list (car context)) ; First item in list
1134 (and (eq 'item (car context))
1135 (not (eq (org-element-property :contents-begin context)
1136 (org-element-property :contents-end context))))
1137 (unpackaged/org-element-descendant-of 'item context)) ; Element in list item, e.g. a link
1138 ;; Non-empty item: Add new item.
1139 (org-insert-item)
1140 ;; Empty item: Close the list.
1141 ;; TODO: Do this with org functions rather than operating on the text. Can't seem to find the right function.
1142 (delete-region (line-beginning-position) (line-end-position))
1143 (insert "\n"))))
1144
1145 ((when (fboundp 'org-inlinetask-in-task-p)
1146 (org-inlinetask-in-task-p))
1147 ;; Inline task: Don't insert a new heading.
1148 (org-return))
1149
1150 ((org-at-table-p)
1151 (cond ((save-excursion
1152 (beginning-of-line)
1153 ;; See `org-table-next-field'.
1154 (cl-loop with end = (line-end-position)
1155 for cell = (org-element-table-cell-parser)
1156 always (equal (org-element-property :contents-begin cell)
1157 (org-element-property :contents-end cell))
1158 while (re-search-forward "|" end t)))
1159 ;; Empty row: end the table.
1160 (delete-region (line-beginning-position) (line-end-position))
1161 (org-return))
1162 (t
1163 ;; Non-empty row: call `org-return'.
1164 (org-return))))
1165 (t
1166 ;; All other cases: call `org-return'.
1167 (org-return)))))
1168 647
1169 (bind-key "RET" #'unpackaged/org-return-dwim 'org-mode-map) 648### Replace selection when typing
1170 649
650 (delete-selection-mode +1)
1171 651
1172# Coding
1173 652
1174The Other Thing Emacs is Good For. 653<a id="orgea7fd73"></a>
1175 654
655### Save existing clipboard text into kill ring before replacing it
1176 656
1177## Formatting 657 (cuss save-interprogram-paste-before-kill t)
1178 658
1179 659
1180### Indenting: [aggressive-indent-mode](https://github.com/Malabarba/aggressive-indent-mode) 660<a id="org27f430f"></a>
1181 661
1182This automagically indents code on every change, as opposed to `electric-indent-mode`, which only does when I like, hit `RET` or whatever. As such, I can turn `electric-indent-mode` off. 662## So long mode
1183 663
1184 (use-package aggressive-indent 664 (when (fboundp 'global-so-long-mode)
1185 :init 665 (global-so-long-mode))
1186 (electric-indent-mode -1)
1187 :config
1188 (global-aggressive-indent-mode 1))
1189 666
1190 667
1191### [Smart tabs](https://github.com/jcsalomon/smarttabs) 668<a id="org8cc8ee8"></a>
1192 669
1193I really want to like, use tabs all the time. But I thought the `smart-tabs` package author made some good points about using tabs for semantic indentation, and spaces for the rest. So. 670# Files
1194 671
1195 (use-package smart-tabs-mode
1196 :custom
1197 (whitespace-style
1198 '(face trailing tabs spaces lines newline
1199 empty indentation space-before-tab
1200 space-mark tab-mark newline-mark))
1201 :config
1202 (smart-tabs-insinuate 'c 'c++ 'javascript 'java 'ruby))
1203 672
673<a id="org8ca2e9b"></a>
1204 674
1205## Display 675## Encoding
1206 676
1207 677
1208### Prettify symbols mode 678<a id="org54363a7"></a>
1209 679
1210By default, I think `prettify-symbols-mode` only changes `lambda` to `λ`. I should, at some point, add some prettified symbols. 680### UTF-8
1211 681
1212 (add-hook 'prog-mode-hook #'prettify-symbols-mode) 682 (set-language-environment 'utf-8)
683 (set-terminal-coding-system 'utf-8)
684 (cuss locale-coding-system 'utf-8)
685 (set-default-coding-systems 'utf-8)
686 (set-selection-coding-system 'utf-8)
687 (prefer-coding-system 'utf-8)
1213 688
1214 689
1215### Parentheses and frens 690<a id="orgeaed3bd"></a>
1216 691
12171. `show-paren-style` 692### Convert all files to UNIX-style line endings
1218 693
1219 A `mixed` `show-paren-style` means that, when both parentheses are visible, it just highlights them. If one is *not*, though, it highlights the entire block. 694from [Emacs Wiki](https://www.emacswiki.org/emacs/EndOfLineTips).
1220 695
1221 (cuss show-paren-style 'mixed) 696 (defun ewiki/no-junk-please-were-unixish ()
1222 (show-paren-mode 1) 697 "Convert line endings to UNIX, dammit."
698 (let ((coding-str (symbol-name buffer-file-coding-system)))
699 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
700 (set-buffer-file-coding-system 'unix))))
1223 701
12242. [smartparens](https://github.com/Fuco1/smartparens) 702I 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.
1225 703
1226 Automagically close pairs and stuff. See also [ParEdit](https://www.emacswiki.org/emacs/ParEdit) &#x2013; maybe test that one? 704 (add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish)
705 (add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish)
1227 706
1228 (use-package smartparens
1229 :init
1230 (defun acdw/setup-smartparens ()
1231 (require 'smartparens-config)
1232 (smartparens-mode 1))
1233 :hook
1234 (prog-mode . acdw/setup-smartparens))
1235 707
12363. [rainbow-delimiters](https://github.com/Fanael/rainbow-delimiters) 708<a id="org7239c47"></a>
1237 709
1238 Show different pairs of delimiters in diffferent colors. Pretty! Useful! 710## Backups
1239 711
1240 (use-package rainbow-delimiters 712 (cuss backup-by-copying 1)
1241 :hook (prog-mode . rainbow-delimiters-mode)) 713 (cuss delete-old-versions -1)
714 (cuss version-control t)
715 (cuss vc-make-backup-files t)
1242 716
1243 717
1244### [rainbow-mode](https://elpa.gnu.org/packages/rainbow-mode.html) 718<a id="org32fc658"></a>
1245 719
1246Show different colors *in that color*. Useful! Pretty! 720## Auto-saves
1247 721
1248 (use-package rainbow-mode 722 (auto-save-visited-mode 1)
1249 :custom
1250 (rainbow-x-colors nil)
1251 :hook prog-mode)
1252 723
1253 724
1254### Line numbers 725<a id="org94456e2"></a>
1255 726
1256I only want line numbers in `prog-mode`-derived modes. In addition, apparently `linum-mode` works better in TUI, but is slower that `display-line-numbers`. So I want to do some logic to see what to use. 727## Revert files
1257 728
1258 (defun acdw/enable-line-numbers () 729 (cuss auto-revert-verbose nil)
1259 "Enable line numbers, either through `display-line-numbers-mode' 730 (global-auto-revert-mode +1)
1260 or through `linum-mode'."
1261 (if (and (fboundp 'display-line-numbers-mode)
1262 (display-graphic-p))
1263 (progn
1264 (display-line-numbers-mode 1)
1265 (cuss display-line-numbers-width 2))
1266 (linum-mode 1)))
1267 731
1268 (add-hook 'prog-mode-hook #'acdw/enable-line-numbers)
1269 732
733<a id="orgb586b3b"></a>
1270 734
1271## Programming languages 735## Add a timestamp to files
1272 736
1273These are the programming languages I (don't really) use. 737 (add-hook 'before-save-hook #'time-stamp)
1274 738
1275 739
1276### Fish shell 740<a id="org738fbd9"></a>
1277 741
1278 (use-package fish-mode) 742# Programming
1279 743
1280 744
1281### Lisps 745<a id="org080eb2f"></a>
1282 746
12831. Common Lisp (SLIME) 747## Which function are we in?
1284 748
1285 (use-package slime 749 (which-function-mode +1)
1286 :when (executable-find "sbcl")
1287 :custom
1288 (inferior-lisp-program "sbcl")
1289 (slime-contribs '(slime-fancy)))
1290 750
12912. Fennel
1292 751
1293 (use-package fennel-mode 752<a id="org6bf5097"></a>
1294 :mode "\\.fnl\\'")
1295 753
1296 754# Writing
1297### Lua
1298
1299 (use-package lua-mode
1300 :mode "\\.lua\\'"
1301 :interpreter "lua")
1302 755
1303 756
1304### Web (HTML/CSS/JS) 757<a id="org6f01971"></a>
1305 758
1306 (use-package web-mode 759## Visual Fill Column
1307 :mode (("\\.ts\\'" . web-mode)
1308 ("\\.html?\\'" . web-mode)
1309 ("\\.css?\\'" . web-mode)
1310 ("\\.js\\'" . web-mode)))
1311 760
761 (use-package visual-fill-column
762 :custom
763 (split-window-preferred-function
764 'visual-fill-column-split-window-sensibly)
765 (visual-fill-column-center-text t)
766 (fill-column 80)
767 :config
768 (advice-add 'text-scale-adjust
769 :after #'visual-fill-column-adjust)
770 :hook
771 (text-mode . visual-fill-column-mode))
1312 772
1313### `~/.ssh/config`
1314 773
1315 (use-package ssh-config-mode) 774<a id="org03e747d"></a>
1316 775
776## Type nice-looking quote-type marks
1317 777
1318### Go 778 (use-package typo
779 :hook
780 (text-mode . typo-mode))
1319 781
1320 (use-package go-mode
1321 :mode "\\.go\\'"
1322 :hook
1323 (before-save . gofmt-before-save))
1324 782
783<a id="org9528516"></a>
1325 784
1326# Applications 785# Applications
1327 786
1328Of course, the real reason we love emacs is for the application layer. What is it they say?
1329
1330> Emacs is a great operating system, lacking only a decent editor.
1331
1332Yeah, that's it 😎
1333
1334
1335## Git: [magit](https://magit.vc/)
1336 787
1337The magical porcelain. 788<a id="orgd2a60aa"></a>
1338 789
1339 (use-package magit 790## Magit
1340 :bind
1341 ("C-x g" . magit-status)
1342 :custom-update
1343 (magit-no-confirm '(stage-all-changes))
1344 :config
1345 (add-hook 'magit-process-find-password-functions
1346 #'magit-process-password-auth-source))
1347 791
792 (use-package magit
793 :bind
794 ("C-x g" . magit-status))
1348 795
1349### Hook into `prescient`
1350 796
1351 (define-advice magit-list-refs 797<a id="org7339cf2"></a>
1352 (:around (orig &optional namespaces format sortby)
1353 prescient-sort)
1354 "Apply prescient sorting when listing refs."
1355 (let ((res (funcall orig namespaces format sortby)))
1356 (if (or sortby
1357 magit-list-refs-sortby
1358 (not selectrum-should-sort-p))
1359 res
1360 (prescient-sort res))))
1361 798
799# Appendices
1362 800
1363### Use `libgit` when I can build it (requires `cmake`)
1364 801
1365 (when (executable-find "cmake") 802<a id="org6070b2c"></a>
1366 (use-package libgit)
1367 (use-package magit-libgit))
1368 803
804## Emacs' files
1369 805
1370### Git "forge" capabilities
1371 806
1372 (use-package forge 807<a id="org0d720f6"></a>
1373 :after magit
1374 :unless (eq system-type 'windows-nt)
1375 :custom
1376 (forge-owned-accounts
1377 '(("duckwork"))))
1378 808
809### init.el
1379 810
1380## Dired 811 ;; init.el -*- lexical-binding: t -*-
1381 812
1382I'm still figuring out what all I can do with `dired`. 8131. Load config
1383 814
1384 (with-eval-after-load 'dired 815 from [Protesilaos Stavrou](https://protesilaos.com/dotemacs/#h:584c3604-55a1-49d0-9c31-abe46cb1f028).
1385 (cuss dired-dwim-target t) 816
1386 (cuss dired-listing-switches "-alDh") 817 (let* ((conf (expand-file-name "config"
818 user-emacs-directory))
819 (elc (concat conf ".elc"))
820 (el (concat conf ".el"))
821 (org (concat conf ".org")))
822 (cond ((file-exists-p elc) (load-file elc))
823 ((file-exists-p el) (load-file el))
824 (t (require 'org)
825 (org-babel-load-file org))))
1387 826
1388 (cuss wdired-allow-to-change-permissions t)
1389 (bind-key "C-c w" #'wdired-change-to-wdired-mode 'dired-mode-map))
1390 827
828<a id="orgd6bffd2"></a>
1391 829
1392### dired-subtree 830### early-init.el
1393 831
1394Part of the [dired-hacks](https://github.com/Fuco1/dired-hacks) package. 832 ;; early-init.el -*- lexical-binding: t; no-byte-compile: t; -*-
1395 833
1396 (use-package dired-subtree 834 (setq load-prefer-newer t)
1397 :bind (:map dired-mode-map 835 (setq frame-inhibit-implied-resize t)
1398 (("i" . dired-subtree-insert)
1399 (";" . dired-subtree-remove))))
1400 836
1401 837
1402## Proced 838<a id="org9c5b437"></a>
1403 839
1404The process editor. 840## Ease tangling and loading of Emacs' init
1405 841
1406 (defun acdw/setup-proced () 842 (defun acdw/tangle-and-load-init ()
1407 (variable-pitch-mode -1) 843 (interactive)
1408 (toggle-truncate-lines 1) 844 "If the current buffer is `config.org', tangle it, then byte-compile."
1409 (proced-toggle-auto-update 1)) 845 (let ((config (expand-file-name "config.org" user-emacs-directory)))
846 (when (string= (buffer-file-name) config)
847 (let ((prog-mode-hook nil))
848 (require 'org)
849 (org-babel-tangle-file config)
850 (org-md-export-to-markdown)
851
852 (dolist (file `(,(expand-file-name "init.el"
853 user-emacs-directory)
854 ,(expand-file-name "config.el"
855 user-emacs-directory)))
856 (byte-compile-file file t))))))
857
858 (add-hook 'after-save-hook #'acdw/tangle-and-load-init)
1410 859
1411 (add-hook 'proced-mode-hook #'acdw/setup-proced)
1412 860
861<a id="org1a4bb4d"></a>
1413 862
1414## Gemini (and gopher) 863## License
1415 864
865Copyright 2020 Case Duckworth <acdw@acdw.net>
1416 866
1417### [elpher](https://thelambdalab.xyz/elpher/) 867This work is free. You can redistribute it and/or modify it under the
868terms of the Do What the Fuck You Want To Public License, Version 2,
869as published by Sam Hocevar. See the `LICENSE` file, tangled from the
870following source block, for details.
1418 871
1419Actually, `elpher` is the reason I started using Emacs. So thanks, smol web denizens! 872 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
873
874 Version 2, December 2004
875
876 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
877
878 Everyone is permitted to copy and distribute verbatim or modified copies of
879 this license document, and changing it is allowed as long as the name is changed.
880
881 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
882
883 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
884
885 0. You just DO WHAT THE FUCK YOU WANT TO.
1420 886
1421Fun fact: these packages are *also* why I use `straight.el`, since they're none of them on GitHub.
1422 887
1423 (use-package elpher 888<a id="orga6047ee"></a>
1424 :straight (elpher
1425 :repo "git://thelambdalab.xyz/elpher.git")
1426 :custom
1427 (elpher-certificate-directory
1428 (no-littering-expand-var-file-name "elpher-certificates/"))
1429 (elpher-ipv4-always t)
1430 :custom-face
1431 (elpher-gemini-heading1
1432 ((t (:inherit (modus-theme-heading-1)))))
1433 (elpher-gemini-heading2
1434 ((t (:inherit (modus-theme-heading-2)))))
1435 (elpher-gemini-heading3
1436 ((t (:inherit (modus-theme-heading-3)))))
1437 :config
1438 (defun elpher:eww-browse-url (original url &optional new-window)
1439 "Handle gemini/gopher links with eww."
1440 (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
1441 (require 'elpher)
1442 (elpher-go url))
1443 (t (funcall original url new-window))))
1444 (advice-add 'eww-browse-url :around 'elpher:eww-browse-url)
1445 :bind (:map elpher-mode-map
1446 ("n" . elpher-next-link)
1447 ("p" . elpher-prev-link)
1448 ("o" . elpher-follow-current-link)
1449 ("G" . elpher-go-current))
1450 :hook
1451 (elpher-mode . visual-fill-column-mode))
1452 889
890### Note on the license
1453 891
1454### [gemini-mode](https://git.carcosa.net/jmcbray/gemini.el) 892It's highly likely that the WTFPL is completely incompatible with the
893GPL, for what should be fairly obvious reasons. To that, I say:
1455 894
1456A major mode for `text/gemini` files. I've changed the headings to match Elpher's. 895**SUE ME, RMS!**
1457
1458 (use-package gemini-mode
1459 :straight (gemini-mode
1460 :repo "https://git.carcosa.net/jmcbray/gemini.el.git")
1461 :mode "\\.\\(gemini|gmi\\)\\'"
1462 :custom-face
1463 (gemini-heading-face-1
1464 ((t (:inherit (elpher-gemini-heading1)))))
1465 (gemini-heading-face2
1466 ((t (:inherit (elpher-gemini-heading2)))))
1467 (gemini-heading-face3
1468 ((t (:inherit (elpher-gemini-heading3)))))
1469 :init
1470 (defun acdw/setup-gemini-mode ()
1471 (visual-fill-column-mode 1)
1472 (variable-pitch-mode -1))
1473 :hook
1474 (gemini-mode . acdw/setup-gemini-mode))
1475
1476
1477### [gemini-write](https://alexschroeder.ch/cgit/gemini-write/about/)
1478
1479Alex Schroeder's Emacs implementation of the Titan protocol. This is why I use his Gemini server, [Phoebe](https://alexschroeder.ch/cgit/phoebe/)!
1480
1481 (use-package gemini-write
1482 :straight (gemini-write
1483 :repo "https://alexschroeder.ch/cgit/gemini-write")
1484 :config
1485 (when (boundp 'acdw-secrets/elpher-gemini-tokens)
1486 (dolist (token acdw-secrets/elpher-gemini-tokens)
1487 (add-to-list 'elpher-gemini-tokens token))))
1488
1489
1490### [post-to-gemlog-blue](https://git.sr.ht/~acdw/post-to-gemlog-blue.el)
1491
1492My first (!) Emacs package, to allow posting to [gemlog.blue's web interface](https://gemlog.blue). I don't use gemlog.blue any more, but if I didn't have this package, no one would 😎
1493
1494 (use-package post-to-gemlog-blue
1495 :straight (post-to-gemlog-blue
1496 :repo "https://git.sr.ht/~acdw/post-to-gemlog-blue.el"))
1497
1498
1499## Pastebin: [0x0](https://git.sr.ht/~zge/nullpointer-emacs)
1500
1501Pastebins are so useful. Now I can use them from Emacs.
1502
1503 (use-package 0x0
1504 :custom
1505 (0x0-default-service 'ttm))
1506
1507
1508## [mu4e](https://www.djcbsoftware.nl/code/mu/mu4e.html)
1509
1510I've just recently started (again) using mu4e. We'll see how it goes.
1511
1512 (when (executable-find "mu")
1513 (add-to-list 'load-path
1514 "/usr/share/emacs/site-lisp/mu4e")
1515 (require 'mu4e)
1516
1517 (cuss mail-user-agent 'mu4e-user-agent)
1518
1519 (cuss mu4e-headers-skip-duplicates t)
1520 (cuss mu4e-view-show-images t)
1521 (cuss mu4e-view-show-addresses t)
1522 (cuss mu4e-compose-format-flowed t)
1523 (cuss mu4e-change-filenames-when-moving t)
1524 (cuss mu4e-attachments-dir "~/Downloads")
1525
1526 (cuss mu4e-maildir "~/.mail/fastmail")
1527 (cuss mu4e-refile-folder "/Archive")
1528 (cuss mu4e-sent-folder "/Sent")
1529 (cuss mu4e-drafts-folder "/Drafts")
1530 (cuss mu4e-trash-folder "/Trash")
1531
1532 (fset 'my-move-to-trash "mTrash")
1533 (define-key mu4e-headers-mode-map (kbd "d") 'my-move-to-trash)
1534 (define-key mu4e-view-mode-map (kbd "d") 'my-move-to-trash)
1535
1536 (cuss message-send-mail-function 'smtpmail-send-it)
1537 (cuss smtpmail-default-smtp-server "smtp.fastmail.com")
1538 (cuss smtpmail-smtp-server "smtp.fastmail.com")
1539 (cuss smtpmail-stream-type 'ssl)
1540 (cuss smtpmail-smtp-service 465)
1541 (cuss smtpmail-local-domain "acdw.net")
1542 (cuss mu4e-compose-signature
1543 "Best,\nCase\n")
1544
1545 (cuss mu4e-get-mail-command "mbsync -a")
1546 (cuss mu4e-update-interval 300)
1547
1548 (cuss mu4e-completing-read-function 'completing-read)
1549 (cuss message-kill-buffer-on-exit t)
1550 (cuss mu4e-confirm-quit nil)
1551
1552 (cuss mu4e-bookmarks
1553 '((
1554 :name "Unread"
1555 :query
1556 "flag:unread AND NOT flag:trashed AND NOT maildir:/Spam"
1557 :key ?u)
1558 (
1559 :name "Today"
1560 :query "date:today..now and not maildir:/Spam"
1561 :key ?t)
1562 (
1563 :name "This week"
1564 :query "date:7d..now and not maildir:/Spam"
1565 :hide-unread t
1566 :key ?w)))
1567
1568 (cuss mu4e-headers-fields
1569 '((:human-date . 12)
1570 (:flags . 6)
1571 (:mailing-list . 10)
1572 (:from-or-to . 22)
1573 (:subject)))
1574
1575 (defun acdw/setup-mu4e-view-mode ()
1576 (visual-fill-column-mode))
1577
1578 (add-hook 'mu4e-view-mode-hook #'acdw/setup-mu4e-view-mode))
1579
1580 ;; not sure about this...
1581 (use-package mu4e-dashboard
1582 :straight (mu4e-dashboard
1583 :host github
1584 :repo "rougier/mu4e-dashboard"
1585 :branch "main"))
1586
1587
1588<a id="orgb5347d4"></a>
1589
1590## KeePassXC integration
1591
1592I use KeePassXC, and I'd *like* to use KeePassXC to get passwords and stuff at home. So I'm trying this library out, since the secret-tool integration isn't built into the KeePassXC on Void. If this doesn't work, looks like I'll have to become a packager 😜
1593
1594 (when (eq system-type 'gnu/linux)
1595 (use-package sodium
1596 :straight (sodium
1597 :host github
1598 :repo "dakra/sodium.el"
1599 :build ("make"))
1600 :init
1601 (add-to-list 'load-path
1602 (expand-file-name "straight/repos/sodium.el"
1603 user-emacs-directory)))
1604 (use-package keepassxc
1605 :straight (keepassxc
1606 :host github
1607 :repo "dakra/keepassxc.el")
1608 :after (sodium)))
1609
1610
1611### libsodium integration
1612
1613I had to manually run `make` in the repo this time around, for some reason. Should probably look into that &#x2026; when it's not 1:00 AM.
1614
1615 (use-package sodium
1616 :straight (sodium
1617 :host github
1618 :repo "dakra/sodium.el"
1619 :build ("make"))
1620 :init
1621 (add-to-list 'load-path
1622 (expand-file-name "straight/repos/sodium.el"
1623 user-emacs-directory)))
1624
1625
1626# Appendix A: Scripts
1627
1628
1629## `emacsdc`
1630
1631Here's a wrapper script that'll start `emacs --daemon` if there isn't one, and then launche `emacsclient` on the arguments. I'd recommend installing with `ln -s emacsdc ~/.local/bin/` or something. Then you can set it as your `$EDITOR`!
1632
1633if ! emacsclient -nc "$@" 2>/dev/null; then
1634 emacs --daemon
1635 emacsclient -nc "$@"
1636 fi
1637
1638
1639# Appendix B: areas for further research
1640
1641- [ebuku](https://github.com/flexibeast/ebuku) (of course, I'd need [buku](https://github.com/jarun/buku) as well) &#x2013; bookmarks
1642- [KeePassXC as Secret Service](https://www.billdietrich.me/Authentication.html?expandall=1#KeePassXCandSecretService) &#x2013; see [14.7](#orgb5347d4)
1643- [Ignoramus](https://github.com/rolandwalker/ignoramus) &#x2013; this might not e necessary
1644- [Dynamic fonts](https://github.com/rolandwalker/dynamic-fonts) &#x2013; take a look @ this and compare with my fonts section
1645- [Simple clipboard integration](https://github.com/rolandwalker/simpleclip) &#x2013; test with Windows, maybe
1646- [visible mark](https://git.sr.ht/~iank/visible-mark) &#x2013; show where the marks are &#x2026;
1647- consider this Reddit thread: [speeding up magit](https://www.reddit.com/r/emacs/comments/k3xfa1/speeding_up_magit/)
1648
1649
1650## export org to ODT on Windows
1651
1652Windows doesn't have `zip` natively (though it *does* have `curl` &#x2013; go figure!), so the ODT export for Org-mode won't work. There *is* a [StackOverflow discussion](https://stackoverflow.com/questions/8625306/org-mode-zip-needed-how-to-over-come) that mentions `p7zip` and a possible batch file, but I couldn't get that to work with a little testing. It might need more work.
1653
1654Something that *did* work was downloading `zip.exe` from [Info-ZIP](http://infozip.sourceforge.net/), and placing it somewhere in `exec-path` &#x2013; though of course, *then* you need `unzip.exe`, apparently in the same folder. Git Portable ships with `unzip.exe`, for example, but even though it's in `exec-path`, org-export threw an error unless `zip` and `unzip` were in the *same* folder.
1655 896
1656So I might either (a) have to set up computers in this way when I use new ones, or (b) include both `zip.exe` and `unzip.exe` in *this* Git repo, or &#x2026; something else. A true quandry.
diff --git a/config.org b/config.org index 7ec4a00..c025f03 100644 --- a/config.org +++ b/config.org
@@ -1,315 +1,256 @@
1#+TITLE:Emacs configuration, literate style 1#+TITLE: Emacs, emacs, emacs
2#+AUTHOR:Case Duckworth 2#+AUTHOR: Case Duckworth
3#+PROPERTY: header-args :tangle init.el :comments both :mkdirp yes 3#+PROPERTY: header-args :tangle config.el :comments both :mkdirp yes
4#+EXPORT_FILE_NAME: README.md 4#+EXPORT_FILE_NAME: README.md
5#+OPTIONS: toc:nil 5#+BANKRUPTCY_COUNT: 3
6#+OPTIONS: title:t 6#+Time-stamp: <2020-12-08 23:51:18 acdw>
7#+BANKRUPTCY_COUNT: 2
8#+Time-stamp: <2020-12-07 08:25:11 acdw>
9 7
10This is my Emacs configuration. It's also a literate =org-mode= file. Yeah, I'm a cool guy. 8* Pave the way
9** Correct =exec-path=
11 10
12* About me 11 #+begin_src emacs-lisp
13 12 (let ((win-downloads "c:/Users/aduckworth/Downloads"))
14#+begin_src emacs-lisp :comments no 13 (dolist (path `(;; Linux
15;; init.el -*- lexical-binding: t -*- 14 ,(expand-file-name "bin"
16 (setq user-full-name "Case Duckworth" 15 user-emacs-directory)
17 user-mail-address "acdw@acdw.net") 16 ,(expand-file-name "~/bin")
18#+end_src 17 ,(expand-file-name "~/.local/bin")
19 18 ,(expand-file-name "~/Scripts")
20* License 19 ;; Windows
20 ,(expand-file-name "emacs/bin"
21 win-downloads)
22 ,(expand-file-name "PortableGit/bin"
23 win-downloads)
24 ,(expand-file-name "PortableGit/usr/bin"
25 win-downloads)))
26 (when (file-exists-p path)
27 (add-to-list 'exec-path path))))
28 #+end_src
21 29
22Copyright © 2020 Case Duckworth <acdw@acdw.net> 30** Package management
23 31
24This work is free. You can redistribute it and/or modify it under the terms of the Do What the Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See the =LICENSE= file, tangled from the following source block, for details. 32*** Straight.el
25 33
26#+begin_src text :tangle LICENSE :comments no 34 #+begin_src emacs-lisp
27 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 35 (defvar bootstrap-version)
36 (let ((bootstrap-file
37 (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
38 (bootstrap-version 5))
39 (unless (file-exists-p bootstrap-file)
40 (with-current-buffer
41 (url-retrieve-synchronously
42 "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
43 'silent 'inhibit-cookies)
44 (goto-char (point-max))
45 (eval-print-last-sexp)))
46 (load bootstrap-file nil 'nomessage))
47 #+end_src
28 48
29 Version 2, December 2004 49*** Use-package
30 50
31 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 51 #+begin_src emacs-lisp
52 (setq straight-use-package-by-default t)
53 (straight-use-package 'use-package)
54 #+end_src
32 55
33 Everyone is permitted to copy and distribute verbatim or modified copies of 56*** Extra use-package keywords
34 this license document, and changing it is allowed as long as the name is changed.
35 57
36 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 58**** :custom-update
37 59
38 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 60#+begin_src emacs-lisp
61 (straight-use-package
62 '(use-package-custom-update
63 :host "github"
64 :repo "a13/use-package-custom-update"))
39 65
40 0. You just DO WHAT THE FUCK YOU WANT TO. 66 (require 'use-package-custom-update)
41#+end_src 67#+end_src
42 68
43** Note on the license 69** Customize variables
44 70
45It's highly likely that the WTFPL is completely incompatible with the GPL, for what should be fairly obvious reasons. To that, I say: 71*** Put customizations in a separate file
46 72
47*SUE ME, RMS!* 73 #+begin_src emacs-lisp
48 74 (setq custom-file
49* Bootstrap 75 (expand-file-name "custom.el" user-emacs-directory))
50 76 #+end_src
51** Original init.el
52
53This file replaces itself with the actual configuration when it's first run. For easy installation, /this/ is the =init.el= file in git -- and you probably want to keep it that way. To keep git from trying to update =init.el= when it's re-tangled, type this in the repo:
54 77
55#+begin_src sh :tangle no 78*** A macro for ease of customization
56git update-index --assume-unchanged init.el
57#+end_src
58 79
59If, for some reason, you want to change this original file to be re-tracked, run this command: 80 #+begin_src emacs-lisp
81 (defmacro cuss (var val &optional docstring)
82 "Basically `:custom' from `use-package', broken out."
83 `(funcall (or (get ',var 'custom-set) #'set-default)
84 ',var ,val))
85 #+end_src
60 86
61#+begin_src sh :tangle no 87** Keep a tidy =~/.emacs=
62git update-index --no-assume-unchanged init.el
63#+end_src
64 88
65Otherwise, here's the actual, original =init.el= that tangles this Org file and gets us going. 89#+begin_src emacs-lisp
90 (use-package no-littering
91 :custom
92 (backup-directory-alist
93 `((".*" . ,(no-littering-expand-var-file-name "backup/"))))
94 (auto-save-file-name-transforms
95 `((".*" ,(no-littering-expand-var-file-name "autosaves/") t)))
96 (save-place-file
97 (no-littering-expand-var-file-name "places"))
98 (undo-fu-session-directory
99 (no-littering-expand-var-file-name "undos/"))
100 (undohist-directory
101 (no-littering-expand-var-file-name "undos/"))
102 (elpher-certificate-directory
103 (no-littering-expand-var-file-name "elpher-certificates/")))
66 104
67#+begin_src emacs-lisp :tangle no 105 (dolist (dir '("backup"
68 (require 'org) 106 "autosaves"
69 (find-file (concat user-emacs-directory "config.org")) 107 "undos"
70 (org-babel-tangle) 108 "elpher-certificates"))
71 (load-file (concat user-emacs-directory "early-init.el")) 109 (make-directory (no-littering-expand-var-file-name dir) t))
72 (load-file (concat user-emacs-directory "init.el"))
73 (byte-compile-file (concat user-emacs-directory "init.el"))
74#+end_src 110#+end_src
75 111
76*** TODO What I should do instead 112* Look and Feel
77 113
78Honestly, I should just change this "Original init.el" thing to a Makefile I can tangle in =config.org=, and track -- since it won't be overwritten or need any special =git= invocations to stop tracking it, I can edit it as I think about what would work best. I could also maybe give it more of a "cross-platform" vibe by installing, say, =straight.el= in the Makefile on Windows. One day ... 114** Simplify the UI
79 115
80** Tangling 116*** Tool bars and menu bars
81
82After our first tangle, each time we edit =config.org= we want to go ahead and re-tangle our config. To that end, I've written ~acdw/tangle-init~, which automatically tangles =config.org=.
83 117
84#+begin_src emacs-lisp 118#+begin_src emacs-lisp
85 (defun acdw/tangle-init () 119 (cuss default-frame-alist
86 "If the current buffer is `config.org', tangle it, then compile 120 '((tool-bar-lines . 0)
87 and load the resulting files." 121 (menu-bar-lines . 0)))
88 (when (equal (buffer-file-name)
89 (expand-file-name
90 (concat user-emacs-directory "config.org")))
91 ;; Tangle and load init.el and early-init.el
92 (require 'async)
93 (async-start
94 (lambda ()
95 (let ((prog-mode-hook nil))
96 (require 'org)
97 (org-babel-tangle-file
98 (expand-file-name
99 (concat user-emacs-directory "config.org")))))
100 (lambda (response)
101 (acdw/load-init)
102 (message "Tangled and loaded: %s" response)))))
103#+end_src
104
105Since I want to tangle every time I save =config.org=, I've added ~acdw/tangle-init~ to a hook.
106 122
107#+begin_src emacs-lisp 123 (menu-bar-mode -1)
108 (add-hook 'after-save-hook #'acdw/tangle-init) 124 (tool-bar-mode -1)
109#+end_src 125#+end_src
110 126
111Finally, I want an easier way to load the generated init files than the old =M-x load-file RET ~/.config/emacs/init.el RET=. So I've written ~acdw/load-init~ -- which also gets called at the end of the async part of ~acdw/tangle-init~. 127*** Scroll bars
112 128
113#+begin_src emacs-lisp 129#+begin_src emacs-lisp
114 (defun acdw/load-init () 130 (add-to-list 'default-frame-alist '(vertical-scroll-bars . nil))
115 "Load my init files." 131 (scroll-bar-mode -1)
116 (interactive)
117 (load-file (expand-file-name
118 (concat user-emacs-directory "early-init.el")))
119 (load-file (expand-file-name
120 (concat user-emacs-directory "init.el"))))
121#+end_src
122
123** Miscellaneous bootstrappy stuff
124 132
125*** Add directories to =load-path= 133 (add-to-list 'default-frame-alist '(horizontal-scroll-bars . nil))
134 (horizontal-scroll-bar-mode -1)
135#+end_src
126 136
127I also put lispy stuff in the =lisp/= subdirectory of my Emacs config, and under my SyncThing directory (for easy syncing ;P). 137*** Dialog boxen
128 138
129#+begin_src emacs-lisp 139#+begin_src emacs-lisp
130 (dolist (dir `(,(concat user-emacs-directory 140 (cuss use-dialog-box nil)
131 (convert-standard-filename "lisp/"))
132 ,(expand-file-name "~/Sync/elisp/")))
133 (add-to-list 'load-path dir))
134
135#+end_src 141#+end_src
136 142
137*** TODO Require my secrets 143*** Shorten confirmations
138
139While this is like, the /dumbest/ way to do this, it's what I'm doing right now. I'm going to slap a TODO on here because I really should make it better -- like, =auth-sources= hooked into KeePassXC somehow... ? Maybe follow [[https://www.billdietrich.me/Authentication.html?expandall=1#KeePassXCandSecretService][Bill Dietrich's setup]].
140 144
141#+begin_src emacs-lisp 145#+begin_src emacs-lisp
142 (require 'acdw-secrets) 146 (fset 'yes-or-no-p #'y-or-n-p)
143#+end_src 147#+end_src
144 148
145* Early initiation 149*** Remove the bell
146:PROPERTIES:
147:header-args: :tangle early-init.el
148:END:
149
150Starting with version 27.1, Emacs loads =early-init.el= /before/ =init.el=, setting up early stuff like package management, etc. Since I use an alternative package manager, I have to bootstrap it here.
151
152Of course, I also want to set some really early-on settings here too, like =load-prefer-newer= -- why not?
153 150
154#+begin_src emacs-lisp :comments no 151#+begin_src emacs-lisp
155;; early-init.el -*- lexical-binding: t; no-byte-compile: t -*- 152 (cuss visible-bell (not (string= (system-name) "larry")))
156 (setq load-prefer-newer t)
157#+end_src 153#+end_src
158 154
159** Increase the garbage collector 155*** Tell Ediff to setup windows better
160
161Let's try to speed startup times by increasing the garbage collector's threshold while running init. Note the hook afterwards that restores it to a reasonable default.
162 156
163#+begin_src emacs-lisp 157#+begin_src emacs-lisp
164 (setq gc-cons-threshold (* 100 100 1000)) 158 (declare-function ediff-setup-windows-plain "ediff-wind.el")
165 159 (cuss ediff-window-setup-function #'ediff-setup-windows-plain)
166 (add-hook 'after-init-hook
167 (lambda ()
168 (setq gc-cons-threshold (* 100 100 100))
169 (message "gc-cons-threshold restored to %S"
170 gc-cons-threshold)))
171#+end_src 160#+end_src
172 161
173** Add more paths to the =exec-path= 162** Tweak the remaining UI
174 163
175When using Windows (at work), I need to use the PortableGit installation I've downloaded, since I don't have Admin privileges. 164*** Window dividers
176 165
177#+begin_src emacs-lisp 166#+begin_src emacs-lisp
178 (when (eq system-type 'windows-nt) 167 (add-to-list 'default-frame-alist '(right-divider-width . 2))
179 (dolist (path '("c:/Users/aduckworth/Downloads/emacs/bin" 168 (add-to-list 'default-frame-alist '(bottom-divider-width . 2))
180 "C:/Users/aduckworth/Downloads/PortableGit/bin"
181 "C:/Users/aduckworth/Downloads/PortableGit/usr/bin"))
182 (add-to-list 'exec-path path)))
183#+end_src 169#+end_src
184 170
185Elsewhere, I want to add a few more paths to the =exec-path= as well, since I store scripts in a couple of places at ~. 171*** Fringes
186 172
187#+begin_src emacs-lisp 173#+begin_src emacs-lisp
188 (dolist (path `(,(expand-file-name "bin" 174 (add-to-list 'default-frame-alist '(left-fringe-width . 2))
189 user-emacs-directory) 175 (add-to-list 'default-frame-alist '(right-fringe-width . 2))
190 ,(expand-file-name "~/bin")
191 ,(expand-file-name "~/.local/bin")
192 ,(expand-file-name "~/Scripts")))
193 (add-to-list 'exec-path path))
194#+end_src 176#+end_src
195 177
196** Bootstrap [[https://github.com/raxod502/straight.el][straight.el]] 178*** Minibuffer
197 179
198So far, this is the best package manager I've used. It allows for /truly/ declarative package management (if I don't specify a package here, it doesn't get loaded), easy installation from pretty much any source (as long as it's got a git repo), /and/ it hooks into =use-package=! 180**** Setup the minibuffer frame
199 181
200The one annoying thing is that this bootstrap code doesn't work on Windows for some reason. I'm too lazy to really try and figure out why, so when I need to bootstrap on Windows (pretty rare, TBH), I just [[https://github.com/raxod502/straight.el/archive/master.zip][download the master-branch zip file]] and extract it to =~/.emacs.d/straight/repos/=.
201
202#+NAME: straight-bootstrap
203#+begin_src emacs-lisp 182#+begin_src emacs-lisp
204 (defvar bootstrap-version) 183 (cuss minibuffer-frame-alist
205 (let ((bootstrap-file 184 '((width . 80)
206 (expand-file-name "straight/repos/straight.el/bootstrap.el" 185 (height . 2)
207 user-emacs-directory)) 186 (vertical-scrollbars . nil)))
208 (bootstrap-version 5))
209 (unless (file-exists-p bootstrap-file)
210 (with-current-buffer
211 (url-retrieve-synchronously
212 "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
213 'silent 'inhibit-cookies)
214 (goto-char (point-max))
215 (eval-print-last-sexp)))
216 (load bootstrap-file nil 'nomessage))
217#+end_src
218
219** ... but first: override the definition of straight.el to use the =develop= branch
220
221For the KeePassXC bits later, I need the =develop= branch of straight, so I can pass a =:build= keyword. I can do this, but I have to override the recipe for =straight.el= itself. I do that here. For more information, see [[https://github.com/raxod502/straight.el#overriding-recipes][the README]].
222
223#+begin_src emacs-lisp :noweb yes :tangle no
224 (setq straight-repository-branch "develop")
225 187
226 <<straight-bootstrap>> 188 (set-window-scroll-bars (minibuffer-window) nil nil)
227#+end_src 189#+end_src
228 190
229** Use [[https://jwiegley.github.io/use-package/][use-package]] 191**** Keep the cursor from going into the prompt
230
231Like I said, =straight.el= hooks into =use-package= easily. These two lines get the latter to use the former by default.
232 192
233#+begin_src emacs-lisp 193#+begin_src emacs-lisp
234 (setq straight-use-package-by-default t) 194 (cuss minibuffer-prompt-properties
235 (straight-use-package 'use-package) 195 '(read-only t cursor-intangible t face minibuffer-prompt))
236#+end_src 196#+end_src
237 197
238** Keep =~/.emacs.d= tidy with [[https://github.com/emacscollective/no-littering][no-littering]] 198*** Tabs
239 199
240I'll be honest -- I don't really notice this package. But I think that's the point. It keeps Emacs (and packages) from throwing files all over the place, so I have a clean =ls -l=. Since I want to run this code as early as possible, I use the =straight-use-package= form instead of =use-package=. 200**** Show the tabs as current buffer, plus window count
241 201
242#+begin_src emacs-lisp 202#+begin_src emacs-lisp
243 (straight-use-package 'no-littering) 203 (cuss tab-bar-tab-name-function #'tab-bar-tab-name-current-with-count)
244 (require 'no-littering)
245#+end_src 204#+end_src
246 205
247** Additional =use-package= keywords 206**** Only show the tab bar when there's more than one tab
248 207
249*** [[https://github.com/a13/use-package-custom-update][:custom-update]] 208#+begin_src emacs-lisp
250 209 (cuss tab-bar-show 1)
251The =:custom-update= keyword lets me do this:
252
253#+begin_src emacs-lisp :tangle no
254 (use-package package
255 :custom-update
256 (package-list '(1 2 3)))
257#+end_src
258
259instead of this:
260
261#+begin_src emacs-lisp :tangle no
262 (use-package package
263 :config
264 (add-to-list 'package-list '(1 2 3)))
265#+end_src 210#+end_src
266 211
267It's not ... perfect, but it's kind of nice. 212*** Cursor
268 213
269#+begin_src emacs-lisp 214#+begin_src emacs-lisp
270 (use-package use-package-custom-update 215 (cuss cursor-type 'bar)
271 :straight (use-package-custom-update 216 (cuss cursor-in-non-selected-windows 'hollow)
272 :host github
273 :repo "a13/use-package-custom-update"))
274#+end_src 217#+end_src
275 218
276** Setup [[https://github.com/jwiegley/emacs-async][async]] 219*** Buffer names
277
278I thought this was included in Emacs at first, but it's not -- so we need to install and require it.
279 220
280#+begin_src emacs-lisp 221#+begin_src emacs-lisp
281 (straight-use-package 'async) 222 (require 'uniquify)
282 (require 'async) 223 (cuss uniquify-buffer-name-style 'forward)
283#+end_src 224#+end_src
284 225
285* Macros 226*** Buffer boundaries
286 227
287** Customizing variables 228#+begin_src emacs-lisp
229 (cuss indicate-buffer-boundaries
230 '((top . right)
231 (bottom . right)
232 (t . nil)))
288 233
289I like =use-package= a lot, but I don't like using those shims you see in a lot of other Emacs configs where they use ~(use-package emacs)~ forms and stuff like that -- it just feels dirty. Plus, =straight= gets confused about those packages sometimes. So, since I'm actually /configuring/ Emacs in this Org file, which is nicely organized anyway, I can just set settings the old-school way. 234 (cuss indicate-empty-lines t)
235#+end_src
290 236
291Except. Using =setq= is actually /not/ recommended any more, because =customize-set-variable= is more expressive and can include side-effects. However, not all settings are customizable, /and/ =customize-set-variable= is like, way longer to type. So I've decided to write a little macro (my first!) to copy =use-package='s =:custom= keyword, except ... /outside/ =use-package=. I've called it =cuss=, because I have a terrible sense of humor. 237** Startup
292 238
293#+begin_src emacs-lisp 239#+begin_src emacs-lisp
294 (defmacro cuss (var val) 240 (cuss inhibit-startup-buffer-menu t)
295 "Basically `use-package''s `:custom', but without using either." 241 (cuss inhibit-start-screen t)
296 `(progn 242 (cuss initial-buffer-choice t)
297 (funcall (or (get ',var 'custom-set) #'set-default) 243 (cuss initial-scratch-message ";; Hi there!\n")
298 ',var ,val)))
299#+end_src 244#+end_src
300 245
301* Theme: [[https://protesilaos.com/modus-themes/][Modus]] 246** Theme
302
303Protesilaos Stavrou's /excellent/ theme pair. At some point I'll probably write my own that's really minimal and does some funky stuff with faces, but until then, these really are the best I've used.
304
305He's recently updated the themes to 1.0.0, with a refactor and betterment; my config here reflects that change.
306 247
307#+begin_src emacs-lisp 248#+begin_src emacs-lisp
308 (use-package modus-themes 249 (use-package modus-themes
309 :straight (modus-themes 250 :straight (modus-themes
310 :host gitlab 251 :host gitlab
311 :repo "protesilaos/modus-themes" 252 :repo "protesilaos/modus-themes"
312 :branch "main") 253 :branch "main")
313 :custom 254 :custom
314 (modus-themes-slanted-constructs t) 255 (modus-themes-slanted-constructs t)
315 (modus-themes-bold-constructs t) 256 (modus-themes-bold-constructs t)
@@ -340,351 +281,143 @@ He's recently updated the themes to 1.0.0, with a refactor and betterment; my co
340 (load-theme 'modus-operandi t)) 281 (load-theme 'modus-operandi t))
341#+end_src 282#+end_src
342 283
343Due to the new =modus-themes-load-operandi= and =modus-themes-load-vivendi= funcitons, I don't need =theme-changer= any more -- but I still need to set up the themes to change at sunrise and sunset. Well, I'll do that later -- for now I'll use a key to toggle them. 284*** Fonts
344
345#+begin_src emacs-lisp
346 (global-set-key (kbd "<f10>") #'modus-themes-toggle)
347#+end_src
348
349* GUI
350
351** Frame defaults
352
353I want no toolbar, menubar, or scrollbars (ideally I'd have a vertical scrollbar if necessary, but apparently that's too much to ask the Emacs devs); and fringes and window dividers 2 pixels wide.
354
355#+begin_src emacs-lisp
356 (cuss default-frame-alist
357 '((tool-bar-lines . 0)
358 (menu-bar-lines . 0)
359 (vertical-scroll-bars . nil)
360 (horizontal-scroll-bars . nil)
361 (right-divider-width . 2)
362 (bottom-divider-width . 2)
363 (left-fringe-width . 2)
364 (right-fringe-width . 2)))
365#+end_src
366
367** Minibuffer window/frame defaults
368
369Of course, on the minibuffer, I want to make sure there's no scrollbar -- even if I change my mind on =vertical-scroll-bars=, above.
370
371#+begin_src emacs-lisp
372 (cuss minibuffer-frame-alist
373 '((width . 80)
374 (height . 2)
375 (vertical-scrollbars . nil)))
376
377 (set-window-scroll-bars (minibuffer-window) nil nil)
378#+end_src
379
380** Remove unneeded GUI elements
381
382The [[*Frame defaults][Frame Defaults]] section sets up the frame to be free of visual clutter, but /this/ section allows us to toggle that clutter's visibility easily, with one call to each of these functions.
383
384#+begin_src emacs-lisp
385 (menu-bar-mode -1)
386 (tool-bar-mode -1)
387 (scroll-bar-mode -1)
388 (horizontal-scroll-bar-mode -1)
389#+end_src
390
391** Silky scrolling
392
393from [[https://pizza.eli.li/wiki/emacs-config/][elioat]]. I think it's causing a slowdown in scrolling for me, so I'm disabling it until I figure that out.
394
395#+begin_src emacs-lisp :tangle no
396 (cuss scroll-margin 0)
397 (cuss scroll-conservatively 10000)
398 (cuss scroll-preserve-screen-position t)
399 (cuss auto-window-vscroll nil)
400#+end_src
401
402** Tabs
403
404I'm kind of getting into Emacs tabs -- but I like not showing the =tab-bar= when there's only one.
405
406#+begin_src emacs-lisp
407 (cuss tab-bar-show 1)
408
409 (cuss tab-bar-tab-name-function 'tab-bar-tab-name-current-with-count)
410#+end_src
411
412** Word wrap and operate visually
413
414=global-visual-line-mode= is one of those which, in my opinion, should be a default. There's only one place I don't want to wrap words, and that's in =dired=, which I can set individually in its config.
415
416#+begin_src emacs-lisp
417 (global-visual-line-mode 1)
418#+end_src
419
420** Modeline
421
422*** [[https://github.com/Malabarba/smart-mode-line][smart-mode-line]]
423
424#+begin_src emacs-lisp
425 (use-package smart-mode-line
426 :custom
427 (sml/no-confirm-load-theme t)
428 :config
429 (sml/setup))
430#+end_src
431
432*** [[https://github.com/Malabarba/rich-minority][rich-minority]]
433
434=smart-mode-line= comes with =rich-minority= for taking care of minor modes in the modeline, so I'm not going to /also/ use =diminish= or anything. However, =rich-minority= has kind of a hinky way of adding modes to the whitelist, so I had to write my own function to do so.
435
436This confuration means that, by default, no minor modes are shown; if you want a minor mode to be shown (like =word-count-mode= for me), call ~(rm/whitelist-add "REGEXP")~.
437
438#+begin_src emacs-lisp
439 (defun rm/whitelist-add (regexp)
440 "Add a REGEXP to the whitelist for `rich-minority'."
441 (if (listp 'rm--whitelist-regexps)
442 (add-to-list 'rm--whitelist-regexps regexp)
443 (setq rm--whitelist-regexps `(,regexp)))
444 (setq rm-whitelist
445 (mapconcat 'identity rm--whitelist-regexps "\\|")))
446
447 (use-package rich-minority
448 :config
449 (rm/whitelist-add "^$"))
450#+end_src
451
452*** Which-function-mode
453
454Show the name of the current function in the modeline. Also works in Org mode to display the current header. Very cool!
455
456#+begin_src emacs-lisp
457 (which-function-mode 1)
458#+end_src
459
460** Minibuffer
461
462*** Keep cursor from going into the prompt
463
464from [[http://ergoemacs.org/emacs/emacs_stop_cursor_enter_prompt.html][Ergo Emacs]].
465
466#+begin_src emacs-lisp
467 (cuss minibuffer-prompt-properties
468 '(read-only t cursor-intangible t face minibuffer-prompt))
469#+end_src
470
471** Show =^L= as a line
472
473I like using the form-feed character to separate pages, it turns out. 'Tis nice. This package turns that character into a nice long line.
474
475#+begin_src emacs-lisp
476 (use-package form-feed
477 :hook
478 ((text-mode prog-mode) . form-feed-mode))
479#+end_src
480
481** Cursor
482
483I want my cursor to be a bar in focused windows, but a hollow box in non-focused windows.
484
485#+begin_src emacs-lisp
486 (cuss cursor-type 'bar)
487 (cuss cursor-in-non-selected-windows 'hollow)
488#+end_src
489
490** Buffer decorations
491*** Show buffer boundaries
492 285
493These little L-shaped graphics at the top and bottom of buffers don't do anything, but I like 'em. 286**** Define fonts
494 287
495#+begin_src emacs-lisp 288#+begin_src emacs-lisp
496 (cuss indicate-buffer-boundaries
497 '((top . right)
498 (bottom . right)
499 (t . nil)))
500#+end_src
501
502*** Indicate empty lines at the end of the buffer
503#+begin_src emacs-lisp
504 (cuss indicate-empty-lines t)
505#+end_src
506
507* Typesetting
508
509** Fonts
510This is the best way I've come up with to specify a number of different fonts that apply depending on what's applied. To be honest, I didn't really come up with the =font-candidate= function, though -- I got it from the [[https://www.emacswiki.org/emacs/SetFonts#toc11]["Testing if fonts are available?"]] section of the SetFonts page on EmacsWiki.
511
512See [[https://emacs.stackexchange.com/questions/12351/when-to-call-find-font-if-launching-emacs-in-daemon-mode][this StackExchange question and answer]] for more information on why I have these font settings applied in a hook.
513
514#+begin_src emacs-lisp
515 (require 'cl)
516 (defun font-candidate (&rest fonts) 289 (defun font-candidate (&rest fonts)
517 (loop for font in fonts 290 (catch :font
518 when (find-font (font-spec :name font)) 291 (dolist (font fonts)
519 return font)) 292 (if (find-font (font-spec :name font))
293 (throw :font font)))))
520 294
521 (defun acdw/setup-fonts () 295 (defun acdw/setup-fonts ()
522 "Setup fonts. This has to happen after the frame is set up for 296 "Setup fonts. This has to happen after the frame is setup for
523 the first time, so add it to `focus-in-hook'. It removes 297 the first time, so it should be added to `window-setup-hook'. It
524 itself." 298 removes itself from that hook."
525 (interactive) 299 (interactive)
526 (set-face-attribute 'default nil 300 (set-face-attribute 'default nil
527 :font 301 :font
528 (font-candidate 302 (font-candidate
529 "Libertinus Mono-11" 303 "Libertinus Mono-11"
530 "Linux Libertine Mono O-11" 304 "Linux Libertine Mono O-11"
531 "Go Mono-10" 305 "Go Mono-10"
532 "Consolas-10")) 306 "Consolas-10"))
533 307
534 (set-face-attribute 'fixed-pitch nil 308 (set-face-attribute 'fixed-pitch nil
535 :font 309 :font
536 (font-candidate 310 (font-candidate
537 "Libertinus Mono-11" 311 "Libertinus Mono-11"
538 "Linux Libertine Mono O-11" 312 "Linux Libertine Mono O-11"
539 "Go Mono-10" 313 "Go Mono-10"
540 "Consolas-10")) 314 "Consolas-10"))
541 315
542 (set-face-attribute 'variable-pitch nil 316 (set-face-attribute 'variable-pitch nil
543 :font 317 :font
544 (font-candidate 318 (font-candidate
545 "Libertinus Serif-14" 319 "Libertinus Serif-13"
546 "Linux Libertine O-12" 320 "Linux Libertine O-12"
547 "Georgia-11")) 321 "Georgia-11"))
548
549 (remove-hook 'focus-in-hook #'acdw/setup-fonts))
550
551 (add-hook 'focus-in-hook #'acdw/setup-fonts)
552#+end_src
553
554** [[https://github.com/rolandwalker/unicode-fonts][unicode-fonts]]
555 322
556This does something similar to the above code, but for the entirety of the Unicode field (I think). 323 (remove-hook 'window-setup-hook #'acdw/setup-fonts))
557 324
558#+begin_src emacs-lisp 325 (add-hook 'window-setup-hook #'acdw/setup-fonts)
559 (use-package unicode-fonts
560 :config
561 (unicode-fonts-setup))
562#+end_src 326#+end_src
563 327
564** Variable pitch faces 328**** Variable-pitch in text modes
565
566One reason I like the Modus themes so much is that they have /excellent/ support for variable-pitch faces, and mixing them with fixed-pitch faces in, say, Org Mode. That means I can enable =variable-pitch-mode= in all my =text-mode=-derived buffers.
567 329
568#+begin_src emacs-lisp 330#+begin_src emacs-lisp
569 (add-hook 'text-mode-hook #'variable-pitch-mode) 331 (add-hook 'text-mode-hook #'variable-pitch-mode)
570#+end_src 332#+end_src
571 333
572** Padding 334**** Line spacing
573
574This has been taken from [[https://lepisma.xyz/2017/10/28/ricing-org-mode/]["Ricing Org Mode"]] -- of course, I want the typographic niceties everywhere.
575 335
576#+begin_src emacs-lisp 336#+begin_src emacs-lisp
577 (cuss line-spacing 0.1) 337 (cuss line-spacing 0.1)
578#+end_src 338#+end_src
579 339
580* Ease of use 340**** Unicode fonts
581
582** Startup
583
584I want a minimal screen when I start Emacs. Based on the beauty of configs like [[https://github.com/rougier/elegant-emacs][Nicolas Rougier's]] [[https://github.com/rougier/emacs-splash][splash screen]] [[https://github.com/rougier/nano-emacs][experiments]], I might try my hand at some kind of splash screen or dashboard -- but until then, a simple "Hi there!" will suffice 😎
585 341
586#+begin_src emacs-lisp 342#+begin_src emacs-lisp
587 (cuss inhibit-startup-buffer-menu t) 343 (use-package unicode-fonts
588 (cuss inhibit-startup-screen t) 344 :config
589 (cuss initial-buffer-choice t) 345 (unicode-fonts-setup))
590 (cuss initial-scratch-message ";; Hi there!\n")
591#+end_src
592
593** Don't use =customize=
594
595I use customize to discover different things Emacs can do, but I (a) don't want to write the customizations to my =init.el= and (b) I don't want to load them on startup. One source of truth for me thanks!
596
597#+begin_src emacs-lisp
598 (cuss custom-file
599 (no-littering-expand-etc-file-name "custom.el"))
600#+end_src 346#+end_src
601 347
602** Completing-read niceties 348* Interactivity
603
604=completing-read= is Emacs's selection-narrowing-slash-completion framework thing. There's a bunch of packages for it, including =ido=, =icomplete=, =ivy=, and =helm=. I use raxod52's =selectrum= and others, which /extend/ without /clobbering/ existing Emacs functionality. Plus they seem to run faster, at least on Windows.
605
606*** [[https://github.com/raxod502/selectrum][selectrum]]
607 349
608=selectrum= is the basic /sorting and selecting items from a list/ functionality. It's a drop-in replacement for =ido= or the really basic tab-completion Emacs has for, say, =find-file=. 350** Selectrum
609 351
610#+begin_src emacs-lisp 352#+begin_src emacs-lisp
611 (use-package selectrum 353 (use-package selectrum
612 :config 354 :config
613 (selectrum-mode 1)) 355 (selectrum-mode +1))
614#+end_src 356#+end_src
615 357
616*** [[https://github.com/raxod502/prescient.el][prescient]] 358** Prescient
617
618=prescient= helps =selectrum= be more intelligent about sorting the candidates in a list -- it's in charge of the /filtering and sorting/ bit of =completing-read= and friends. It has an algorithm that works well enough for me, though I keep hearing about [[https://github.com/oantolin/orderless][orderless]], enough to maybe try it as well sometime.
619 359
620#+begin_src emacs-lisp 360#+begin_src emacs-lisp
621 (use-package prescient 361 (use-package prescient
622 :config 362 :config
623 (prescient-persist-mode 1)) 363 (prescient-persist-mode +1))
624 364
625 (use-package selectrum-prescient 365 (use-package selectrum-prescient
626 :after (selectrum prescient) 366 :after (selectrum prescient)
627 :config 367 :config
628 (selectrum-prescient-mode 1)) 368 (selectrum-prescient-mode +1))
629#+end_src 369#+end_src
630 370
631*** [[https://github.com/minad/cconsult][consult]] 371** Consult
632
633=consult= is the newest package I have with this setup, and it kind of brings the =selectrum= experience up to par with =ivy='s -- it provides functions that list, say, recently used files /alongside/ buffers, allow you to search lines and go to them, etc. It seems pretty nice so far.
634
635By the way, the [[https://www.reddit.com/r/emacs/comments/k3c0u7][Reddit announcement thread for consult]] has a great comment by the author detailing [[https://www.reddit.com/r/emacs/comments/k3c0u7/consult_counselswiper_alternative_for/ge460z3/][the differences between different completing-read implementations]] that actually is what convinced me to try =consult=.
636 372
637#+begin_src emacs-lisp 373#+begin_src emacs-lisp
638 (use-package consult 374 (use-package consult
639 :after (selectrum) 375 :after (selectrum)
640 :straight (consult 376 :straight (consult
641 :host github 377 :host github
642 :repo "minad/consult") 378 :repo "minad/consult")
643 :bind (("C-x b" . consult-buffer) 379 :bind
644 ("C-x 4 b" . consult-buffer-other-window) 380 (("C-x b" . consult-buffer)
645 ("C-x 5 b" . consult-buffer-other-frame) 381 ("C-x 4 b" . consult-buffer-other-window)
646 ("M-g o" . consult-outline) 382 ("C-x 5 b" . consult-buffer-other-frame)
647 ("M-g l" . consult-line) 383 ("M-g o" . consult-outline)
648 ("M-y" . consult-yank-pop) 384 ("M-g l" . consult-line)
649 ("<help> a" . consult-apropos)) 385 ("M-y" . consult-yank-pop)
386 ("<help> a" . consult-apropos))
650 :init 387 :init
651 (fset 'multi-occur #'consult-multi-occur)) 388 (fset 'multi-occur #'consult-multi-occur))
652#+end_src 389#+end_src
653 390
654*** [[https://github.com/minad/marginalia/][Marginalia]] 391** Marginalia
655
656These provide /marginalia/ in the minibuffer. Until like, December 4, 2020, they were part of =consult=. So let's try them out.
657 392
658#+begin_src emacs-lisp 393#+begin_src emacs-lisp
659 (use-package marginalia 394 (use-package marginalia
660 :straight (marginalia 395 :straight (marginalia
661 :host github 396 :host github
662 :repo "minad/marginalia" 397 :repo "minad/marginalia"
663 :branch "main") 398 :branch "main")
399 :custom
400 (marginalia-annotators
401 '((command . marginalia-annotate-command-full)
402 (customize-group . marginalia-annotate-customize-group)
403 (variable . marginalia-annotate-variable)
404 (face . marginalia-annotate-face)
405 (symbol . marginalia-annotate-symbol)
406 (variable . marginalia-annotate-variable)
407 (package . marginalia-annotate-package)))
664 :init 408 :init
665 (marginalia-mode) 409 (marginalia-mode +1))
666 ;; Enable richer annotations for M-x.
667 ;; Only keybindings are shown by default, in order to reduce noise for this very common command.
668 ;; * marginalia-annotate-symbol: Annotate with the documentation string
669 ;; * marginalia-annotate-command-binding (default): Annotate only with the keybinding
670 ;; * marginalia-annotate-command-full: Annotate with the keybinding and the documentation string
671 (setf (alist-get 'command marginalia-annotator-alist)
672 #'marginalia-annotate-command-full))
673#+end_src 410#+end_src
674 411
675*** Ignore case 412** Ignore case
676
677I don't like holding the Shift key if I can help it.
678 413
679#+BEGIN_SRC emacs-lisp 414#+begin_src emacs-lisp
680 (cuss completion-ignore-case t) 415 (cuss completion-ignore-case t)
681 (cuss read-buffer-completion-ignore-case t) 416 (cuss read-buffer-completion-ignore-case t)
682 (cuss read-file-name-completion-ignore-case t) 417 (cuss read-file-name-completion-ignore-case t)
683#+END_SRC 418#+end_src
684
685** [[https://github.com/raxod502/ctrlf][ctrlf]]
686 419
687The biggest reason I use this over the default functionality of =C-s= is that =ctrlf-forward-*= wraps the search around by default. 420** Search
688 421
689#+begin_src emacs-lisp 422#+begin_src emacs-lisp
690 (use-package ctrlf 423 (use-package ctrlf
@@ -696,388 +429,184 @@ The biggest reason I use this over the default functionality of =C-s= is that =c
696 ("C-M-s" . ctrlf-forward-literal) 429 ("C-M-s" . ctrlf-forward-literal)
697 ("C-M-r" . ctrlf-backward-literal) 430 ("C-M-r" . ctrlf-backward-literal)
698 :config 431 :config
699 (ctrlf-mode 1)) 432 (ctrlf-mode +1))
700#+end_src
701
702** [[https://github.com/justbur/emacs-which-key][which-key]]
703
704This package is really helpful for discovering functionality. When I get more adept in my Emacs-fu, I might remove this.
705
706#+begin_src emacs-lisp
707 (use-package which-key
708 :custom
709 (which-key-popup-type 'minibuffer)
710 (which-key-separator " ")
711 (which-key-prefix-prefix "+")
712 :config
713 (which-key-mode))
714#+end_src
715
716** Miscellaneous settings
717
718Maybe a better title for this section is *Other settings* -- or maybe I should put them somewhere else entirely.
719
720*** Set =view-mode= when in a read-only file
721
722=view-mode= gives easy-to-use keybindings, like Space for page-down, etc., which are nice to have when you can't edit the file anyway.
723
724#+begin_src emacs-lisp
725 (cuss view-read-only t)
726#+end_src
727
728*** Don't use dialog boxen
729
730#+begin_src emacs-lisp
731 (cuss use-dialog-box nil)
732#+end_src
733
734*** Enable all functions
735
736By default, Emacs disables some commands, because NeWbIeS wOuLd GeT cOnFuSeD or some ish. I just want to use the dang editor!
737
738#+begin_src emacs-lisp
739 (cuss disabled-command-function nil)
740#+end_src
741
742*** Shorter confirmations
743
744Instead of making me type /yes/ or /no/, just let me hit the /y/ or /n/ key.
745
746#+begin_src emacs-lisp
747 (fset 'yes-or-no-p #'y-or-n-p)
748#+end_src 433#+end_src
749 434
750*** Uniquify buffer names 435* Persistence
751
752This names buffers with the same basename (e.g., =~/.config/emacs/config.org= and =~/.emacs.d/config.org=) in a better way than the default (=config.org<1>=, etc).
753
754#+begin_src emacs-lisp
755 (require 'uniquify)
756 (cuss uniquify-buffer-name-style 'forward)
757#+end_src
758
759*** Hippie expand
760
761At some point, will probably replace with [[https://company-mode.github.io/][company]].
762
763#+begin_src emacs-lisp
764 (global-set-key (kbd "M-/") 'hippie-expand)
765#+end_src
766
767*** Delete the selection
768
769Like modern editors, if I have text selected and start typing – just /delete the selection/.
770
771#+BEGIN_SRC emacs-lisp
772 (delete-selection-mode 1)
773#+end_src
774
775*** "[[https://git.sr.ht/~technomancy/better-defaults/tree/master/better-defaults.el][better defaults]]"
776
777Most of these come from technomancy's repo, linked above, just copy-pasted into here.
778
779#+begin_src emacs-lisp
780 (cuss save-interprogram-paste-before-kill t)
781 (cuss apropos-do-all t)
782 (cuss mouse-yank-at-point t)
783 (cuss require-final-newline t)
784 (cuss visible-bell (not (string= (system-name) "larry")))
785 (cuss ediff-window-setup-function #'ediff-setup-windows-plain)
786#+end_src
787
788**** Zap-up-to-char, not zap-to-char
789
790Similarly to =ibuffer=, this is a Better default™.
791
792Of course, could be even betterered with [[https://github.com/mrkkrp/zzz-to-char][zzz-to-char]].
793
794#+begin_src emacs-lisp
795 (autoload 'zap-up-to-char "misc"
796 "Kill up to, but not including, ARGth occurrence of CHAR." t)
797
798 (global-set-key (kbd "M-z") 'zap-up-to-char)
799#+end_src
800
801**** iBuffer
802 436
803A Better Default™ for =C-x C-b=. I don't really use this, but everyone says it's worth it, so it's there. 437** Save history
804 438
805#+begin_src emacs-lisp 439#+begin_src emacs-lisp
806 (global-set-key (kbd "C-x C-b") 'ibuffer) 440 (require 'savehist)
807#+end_src
808
809*** So-long-mode
810
811I figure, why not go ahead and make Emacs deal with really long lines better? Can't hurt, right?
812 441
813#+begin_src emacs-lisp 442 (cuss savehist-additional-variables
814 (if (boundp 'global-so-long-mode) 443 '(kill-ring
815 (global-so-long-mode)) 444 search-ring
816#+end_src 445 regexp-search-ring))
817 446
818*** Change =just-one-space= to =cycle-space= 447 (cuss savehist-save-minibuffer-history t)
819 448
820I keep forgetting to actually /use/ this keybind (I think it's =M-SPC=?), but cycling spacing seems /way/ more useful than the default =just-one-space= function. 449 (cuss history-length t)
821 450
822#+begin_src emacs-lisp 451 (cuss history-delete-duplicates t)
823 (defun acdw/cycle-spacing-1 ()
824 (interactive)
825 (cycle-spacing -1))
826 452
827 (bind-key [remap just-one-space] #'acdw/cycle-spacing-1) 453 (savehist-mode +1)
828#+end_src 454#+end_src
829 455
830* Persistence 456** Save places in files
831
832Honestly, persistence across sessions was one of the best things about my well-tuned Vim setup. Here's where I try to repeat that with Emacs.
833
834** Auto-saves with [[https://github.com/bbatsov/super-save][super-save]]
835
836The default =auto-save= functionality isn't ... /enough/ for me. I want to /actually/ save the files, and I don't care about =#file#= stuff. So ... I use this package.
837 457
838#+begin_src emacs-lisp 458#+begin_src emacs-lisp
839 (use-package super-save 459 (require 'saveplace)
840 :custom
841 (auto-save-default nil)
842 (super-save-exclue '(".gpg"))
843 :config
844 (super-save-mode 1))
845#+end_src
846
847** Backup files
848
849To be honest, I probably don't need backup files at all. At some point, I will probably delete this.
850 460
851#+begin_src emacs-lisp 461 (cuss save-place-forget-unreadable-files
852 (cuss backup-directory-alist 462 (not (eq system-type 'windows-nt)))
853 `((".*" . ,(no-littering-expand-var-file-name "backup/"))))
854 463
855 (cuss backup-by-copying 1) 464 (save-place-mode 1)
856 (cuss delete-old-versions -1)
857 (cuss version-control t)
858 (cuss vc-make-backup-files t)
859#+end_src 465#+end_src
860 466
861** Recent files 467** Recent files
862 468
863Since I apparently /only/ edit my =config.org=, this is also probably not necessary -- I'd be better off just adding a ~(find-file (concat (user-emacs-directory "config.org")))~ at the end 😎
864
865But until then, it's really nice to have a =recentf= list.
866
867#+begin_src emacs-lisp 469#+begin_src emacs-lisp
868 (require 'recentf) 470 (require 'recentf)
869 471
870 (add-to-list 'recentf-exclude
871 '(no-littering-var-directory
872 no-littering-etc-directory))
873
874 (cuss recentf-max-menu-items 100) 472 (cuss recentf-max-menu-items 100)
875 (cuss recentf-max-saved-items 100) 473 (cuss recentf-max-saved-items 100)
876 474
475 (with-eval-after-load 'no-littering
476 (add-to-list 'recentf-exclude no-littering-var-directory)
477 (add-to-list 'recentf-exclude no-littering-etc-directory))
478
877 (recentf-mode 1) 479 (recentf-mode 1)
878#+end_src 480#+end_src
879 481
880*** Easily navigate recent files 482*** Easily navigate recent files
881 483
882Now I'm going through this, I might not need this function any more. I'll have to see how =consult= goes.
883
884#+begin_src emacs-lisp 484#+begin_src emacs-lisp
885 (defun recentf-find-file () 485 (defun recentf-find-file ()
886 "Find a recent file using `completing-read'." 486 "Find a recent file using `completing-read'."
887 (interactive) 487 (interactive)
888 (let ((file (completing-read "Recent file: " recentf-list nil t))) 488 (let ((file (completing-read "Recent file: " recentf-list nil t)))
889 (when file 489 (when file
890 (find-file file)))) 490 (find-file file))))
891 491
892 (bind-key "C-x C-r" #'recentf-find-file) 492 (global-set-key (kbd "C-x C-r") #'recentf-find-file)
893#+end_src 493#+end_src
894 494
895** Save places in visited files 495** Undo
896 496
897#+begin_src emacs-lisp 497#+begin_src emacs-lisp
898 (require 'saveplace) 498 (use-package undohist
899 499 :config
900 (cuss save-place-file (no-littering-expand-var-file-name "places")) 500 (undohist-initialize))
901
902 (cuss save-place-forget-unreadable-files
903 (not (eq system-type 'windows-nt)))
904
905 (save-place-mode 1)
906#+end_src 501#+end_src
907 502
908** Save history 503* Editing
909
910#+begin_src emacs-lisp
911 (require 'savehist)
912
913 (cuss savehist-additional-variables
914 '(kill-ring
915 search-ring
916 regexp-search-ring))
917
918 (cuss savehist-save-minibuffer-history t)
919 504
920 (cuss history-length t) 505** Operate visually on lines
921 506
922 (cuss history-delete-duplicates t) 507#+begin_src emacs-lisp
923 508 (global-visual-line-mode +1)
924 (savehist-mode 1)
925#+end_src 509#+end_src
926 510
927** Undo: [[https://gitlab.com/ideasman42/emacs-undo-fu-session][undo-fu-session]] 511** Require a final newline
928
929The other Killer Feature of Neovim when I used it was the perisistent undo. I /think/ this works the same. Honestly, undo is giving me a little grief recently; I need to look into it.
930
931Note to self: if I /do/ switch away from =undo-fu=, look at [[https://github.com/emacsorphanage/undohist][undohist]].
932 512
933#+begin_src emacs-lisp 513#+begin_src emacs-lisp
934 (use-package undo-fu-session 514 (cuss require-final-newline t)
935 :after (no-littering undo-fu)
936 :custom
937 (undo-fu-session-incompatible-files
938 '("COMMIT_EDITMSG\\'"
939 "/git-rebase-todo\\'"))
940 (undo-fu-session-directory
941 (no-littering-expand-var-file-name "undos/"))
942 :config
943 (global-undo-fu-session-mode 1))
944#+end_src 515#+end_src
945 516
946* General editing 517** Killing & Yanking
947
948** File encoding
949 518
950I just want to use UTF-8 everywhere, and end all files with UNIX line endings (=^J=, or =LF=). Hell, even Windows Notepad correctly reads UNIX files nowadays (though of course you can't configure it to /save/ the files in UNIX-mode). However, since Emacs is ~40 years old, it has a billion different ways to set encodings. This is my best attempt at setting everything up how I want it. 519*** Replace selection when typing
951
952I'm going to be honest -- most of this is a stab in the dark.
953 520
954#+begin_src emacs-lisp 521#+begin_src emacs-lisp
955 (set-language-environment 'utf-8) 522 (delete-selection-mode +1)
956 (set-terminal-coding-system 'utf-8)
957 (cuss locale-coding-system 'utf-8)
958 (set-default-coding-systems 'utf-8)
959 (set-selection-coding-system 'utf-8)
960 (prefer-coding-system 'utf-8)
961
962 ;; from https://www.emacswiki.org/emacs/EndOfLineTips
963
964 (defun acdw/no-junk-please-were-unixish ()
965 "Convert line endings to UNIX, dammit."
966 (let ((coding-str (symbol-name buffer-file-coding-system)))
967 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
968 (set-buffer-file-coding-system 'unix))))
969
970 (add-hook 'find-file-hooks #'acdw/no-junk-please-were-unixish)
971#+end_src 523#+end_src
972 524
973** [[https://gitlab.com/ideasman42/emacs-undo-fu][undo-fu]] 525*** Save existing clipboard text into kill ring before replacing it
974
975I've heard that Emacs' undo is weird, so here I am, trying to make it .... /less/ weird. I keep forgetting I've installed this though, so I might uninstall it at some point.
976 526
977#+begin_src emacs-lisp 527#+begin_src emacs-lisp
978 (use-package undo-fu 528 (cuss save-interprogram-paste-before-kill t)
979 :bind
980 ("C-/" . undo-fu-only-undo)
981 ("C-?" . undo-fu-only-redo))
982#+end_src 529#+end_src
983 530
984** Find/replace: [[https://github.com/benma/visual-regexp.el][visual-regexp]] 531** So long mode
985
986Another replacement for a Killer Feature in Neovim -- the ease of regexp find/replace was so wonderful, because I could easily see /what/ I'd be changing with a =%s= command, as well as /how/ it'd change. This works... pretty similarly. It could be a little better.
987 532
988#+begin_src emacs-lisp 533#+begin_src emacs-lisp
989 (use-package visual-regexp 534 (when (fboundp 'global-so-long-mode)
990 :bind 535 (global-so-long-mode))
991 ("C-c r" . 'vr/replace)
992 ("C-c q" . 'vr/query-replace))
993#+end_src 536#+end_src
994 537
995** Visual editing 538* Files
539
540** Encoding
541*** UTF-8
996 542
997*** [[https://github.com/k-talo/volatile-highlights.el][volatile-highlights]] 543 #+begin_src emacs-lisp
544 (set-language-environment 'utf-8)
545 (set-terminal-coding-system 'utf-8)
546 (cuss locale-coding-system 'utf-8)
547 (set-default-coding-systems 'utf-8)
548 (set-selection-coding-system 'utf-8)
549 (prefer-coding-system 'utf-8)
550 #+end_src
998 551
999Highlights text changed by certain operations. 552*** Convert all files to UNIX-style line endings
1000 553
1001#+begin_src emacs-lisp 554 from [[https://www.emacswiki.org/emacs/EndOfLineTips][Emacs Wiki]].
1002 (use-package volatile-highlights
1003 :config
1004 (volatile-highlights-mode 1))
1005#+end_src
1006 555
1007*** [[https://github.com/magnars/expand-region.el][expand-region]] 556 #+begin_src emacs-lisp
1008 557 (defun ewiki/no-junk-please-were-unixish ()
1009I don't use this a /ton/, but not because it's not useful -- I just forget it's there sometimes. 558 "Convert line endings to UNIX, dammit."
559 (let ((coding-str (symbol-name buffer-file-coding-system)))
560 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
561 (set-buffer-file-coding-system 'unix))))
562 #+end_src
1010 563
1011Basically, it allows you to do like a Kakoune-style incremental widening of the selection by semantic units. 564 I 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.
1012 565
1013 #+begin_src emacs-lisp 566 #+begin_src emacs-lisp
1014 (use-package expand-region 567 (add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish)
1015 :bind 568 (add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish)
1016 ("C-=" . er/expand-region)
1017 ("C-+" . er/contract-region))
1018 #+end_src 569 #+end_src
1019 570
1020** Clean up white space on save 571** Backups
1021
1022I'm not sure if I'll /keep/ this forever, because in combination with =super-save= I lose the final "thinking spaces" when I shift contexts to another window.
1023 572
1024#+begin_src emacs-lisp 573#+begin_src emacs-lisp
1025 (add-hook 'before-save-hook #'whitespace-cleanup) 574 (cuss backup-by-copying 1)
1026 (add-hook 'before-save-hook #'delete-trailing-whitespace) 575 (cuss delete-old-versions -1)
576 (cuss version-control t)
577 (cuss vc-make-backup-files t)
1027#+end_src 578#+end_src
1028 579
1029** [[https://github.com/nflath/hungry-delete][hungry-delete]] 580** Auto-saves
1030
1031I find myself typing delete /way/ too much. I really like Emacs's =TAB= functionality -- it tabs to where I need and that's it -- but backspace leaves much to be desired. Enter =hungry-delete=.
1032
1033Also of interest: [[https://github.com/hrehfeld/emacs-smart-hungry-delete][smart-hungry-delete]].
1034 581
1035#+begin_src emacs-lisp 582#+begin_src emacs-lisp
1036 (use-package hungry-delete 583 (auto-save-visited-mode 1)
1037 :custom
1038 (hungry-delete-join-reluctantly t)
1039 :custom-update
1040 (hungry-delete-except-modes
1041 '(emacs-lisp-mode
1042 lisp-mode
1043 fennel-mode))
1044 (global-hungry-delete-mode))
1045 :config
1046#+end_src 584#+end_src
1047 585
1048** Automatically revert a file to what it is on disk 586** Revert files
1049
1050Revert a buffer to reflect what's on disk if it's changed outside of Emacs.
1051 587
1052#+begin_src emacs-lisp 588#+begin_src emacs-lisp
1053 (global-auto-revert-mode 1)
1054 (cuss auto-revert-verbose nil) 589 (cuss auto-revert-verbose nil)
590 (global-auto-revert-mode +1)
1055#+end_src 591#+end_src
1056 592
1057** Add a timestamp 593** Add a timestamp to files
1058
1059This'll add a timestamp to a file when I save it, if the first 8 lines includes the string =Time-stamp: <>=.
1060 594
1061#+begin_src emacs-lisp 595#+begin_src emacs-lisp
1062 (add-hook 'before-save-hook #'time-stamp) 596 (add-hook 'before-save-hook #'time-stamp)
1063#+end_src 597#+end_src
1064 598
1065* Writing 599* Programming
1066 600
1067Configurations related to writing prose or verse. 601** Which function are we in?
1068
1069** Word count: [[https://github.com/bnbeckwith/wc-mode][wc-mode]]
1070 602
1071#+begin_src emacs-lisp 603#+begin_src emacs-lisp
1072 (use-package wc-mode 604 (which-function-mode +1)
1073 :config
1074 (rm/whitelist-add "WC")
1075 :hook text-mode)
1076#+end_src 605#+end_src
1077 606
1078** [[https://github.com/joostkremers/visual-fill-column][visual-fill-column-mode]] 607* Writing
1079 608
1080Center the text part of the frame within a =fill-column=-sized area in the frame as a whole. 609** Visual Fill Column
1081 610
1082#+begin_src emacs-lisp 611#+begin_src emacs-lisp
1083 (use-package visual-fill-column 612 (use-package visual-fill-column
@@ -1088,855 +617,122 @@ Center the text part of the frame within a =fill-column=-sized area in the frame
1088 (fill-column 80) 617 (fill-column 80)
1089 :config 618 :config
1090 (advice-add 'text-scale-adjust 619 (advice-add 'text-scale-adjust
1091 :after #'visual-fill-column-adjust) 620 :after #'visual-fill-column-adjust)
1092 :hook 621 :hook
1093 (text-mode . visual-fill-column-mode)) 622 (text-mode . visual-fill-column-mode))
1094#+end_src 623#+end_src
1095 624
1096*** Fix mouse bindings 625** Type nice-looking quote-type marks
1097
1098In =visual-fill-column-mode=, mouse bindings on the margins don't work. In fact, they don't work when /not/ in =visual-fill-column-mode=. Let's bind those bindings.
1099
1100#+begin_src emacs-lisp
1101 (dolist (vec '([left-margin wheel-down]
1102 [right-margin wheel-down]))
1103 (bind-key vec 'scroll-down-command))
1104
1105 (dolist (vec '([left-margin wheel-up]
1106 [right-margin wheel-up]))
1107 (bind-key vec 'scroll-up-command))
1108#+end_src
1109
1110=mouse-4= and =mouse-5= are also =wheel-up= and =wheel-down=, but they're reversed on *larry*, which uses "natural scrolling." I don't know, I like it.
1111
1112#+begin_src emacs-lisp
1113 (dolist (vec '([left-margin mouse-4]
1114 [right-margin mouse-4]))
1115 (if (string= system-name "larry")
1116 (bind-key vec 'scroll-down-command)
1117 (bind-key vec 'scroll-up-command)))
1118
1119 (dolist (vec '([left-margin mouse-5]
1120 [right-margin mouse-5]))
1121 (if (string= system-name "larry")
1122 (bind-key vec 'scroll-up-command)
1123 (bind-key vec 'scroll-down-command)))
1124#+end_src
1125
1126** [[https://orgmode.org/][org-mode]]
1127
1128Pretty self-explanatory, I think...
1129
1130I need to break this config up and like, comment it better.
1131
1132#+begin_src emacs-lisp
1133 (use-package org
1134 :custom
1135 (org-startup-indented t)
1136 (org-src-tab-acts-natively t)
1137 (org-src-fontify-natively t)
1138 (org-confirm-babel-evaluate nil)
1139 (org-hide-emphasis-markers t)
1140 (org-fontify-done-headline t)
1141 (org-fontify-whole-heading-line t)
1142 (org-fontify-quote-and-verse-blocks t)
1143 (org-hide-leading-stars nil)
1144 (org-hidden-keywords '(author date title))
1145 (org-src-window-setup 'current-window)
1146 (org-pretty-entities t)
1147 (org-ellipsis " ⋯ "))
1148#+end_src
1149
1150*** Make bullets look like centered dots
1151
1152from [[https://zzamboni.org/post/beautifying-org-mode-in-emacs/][zzamboni.org]]
1153
1154#+begin_src emacs-lisp :tangle no
1155 (font-lock-add-keywords
1156 'org-mode
1157 '(("^ *\\([-+]\\) "
1158 (0 (prog1 ()
1159 (compose-region (match-beginning 1)
1160 (match-end 1)
1161 "•"))))))
1162#+end_src
1163
1164*** [[https://github.com/integral-dw/org-superstar-mode][org-superstar]]
1165
1166#+begin_src emacs-lisp
1167 (use-package org-superstar
1168 :custom
1169 (org-superstar-headline-bullets-list
1170 '(?—))
1171 (org-superstar-cycle-headline-bullets nil)
1172 (org-superstar-item-bullet-alist
1173 '((?* . ?★)
1174 (?+ . ?‣)
1175 (?- . ?•)))
1176 (org-superstar-special-todo-items t)
1177 (org-superstar-leading-bullet '(" ."))
1178 :custom-face
1179 (org-superstar-header-bullet
1180 ((t (:weight normal))))
1181 :hook
1182 (org-mode . org-superstar-mode))
1183#+end_src
1184
1185*** Enable markdown export
1186
1187#+begin_src emacs-lisp
1188 (require 'ox-md)
1189#+end_src
1190
1191*** Ensure blank lines between headings and before contents
1192
1193from [[https://github.com/alphapapa/unpackaged.el#ensure-blank-lines-between-headings-and-before-contents][unpackaged.el]]
1194
1195#+begin_src emacs-lisp
1196 ;;;###autoload
1197 (defun unpackaged/org-fix-blank-lines (&optional prefix)
1198 "Ensure that blank lines exist between headings and between
1199 headings and their contents. With prefix, operate on whole
1200 buffer. Ensures that blank lines exist after each headings's
1201 drawers."
1202 (interactive "P")
1203 (org-map-entries
1204 (lambda ()
1205 (org-with-wide-buffer
1206 ;; `org-map-entries' narrows the buffer, which prevents us
1207 ;; from seeing newlines before the current heading, so we
1208 ;; do this part widened.
1209 (while (not (looking-back "\n\n" nil))
1210 ;; Insert blank lines before heading.
1211 (insert "\n")))
1212 (let ((end (org-entry-end-position)))
1213 ;; Insert blank lines before entry content.
1214 (forward-line)
1215 (while (and (org-at-planning-p)
1216 (< (point) (point-max)))
1217 ;; Skip planning lines
1218 (forward-line))
1219 (while (re-search-forward org-drawer-regexp end t)
1220 ;; Skip drawers. You might think that
1221 ;; `org-at-drawer-p' would suffice, but for some reason
1222 ;; it doesn't work correctly when operating on hidden
1223 ;; text. This works, taken from
1224 ;; `org-agenda-get-some-entry-text'.
1225 (re-search-forward "^[ \t]*:END:.*\n?" end t)
1226 (goto-char (match-end 0)))
1227 (unless (or (= (point) (point-max))
1228 (org-at-heading-p)
1229 (looking-at-p "\n"))
1230 (insert "\n"))))
1231 t (if prefix
1232 nil
1233 'tree)))
1234#+end_src
1235
1236*** ~org-return-dwim~
1237
1238from [[https://github.com/alphapapa/unpackaged.el#org-return-dwim][unpackaged.el]]
1239
1240#+begin_src emacs-lisp
1241 (defun unpackaged/org-element-descendant-of (type element)
1242 "Return non-nil if ELEMENT is a descendant of TYPE.
1243 TYPE should be an element type, like `item' or `paragraph'.
1244 ELEMENT should be a list like that returned by
1245 `org-element-context'."
1246 ;; MAYBE: Use `org-element-lineage'.
1247 (when-let* ((parent (org-element-property :parent element)))
1248 (or (eq type (car parent))
1249 (unpackaged/org-element-descendant-of type parent))))
1250
1251 ;;;###autoload
1252 (defun unpackaged/org-return-dwim (&optional default)
1253 "A helpful replacement for `org-return'. With prefix, call `org-return'.
1254
1255 On headings, move point to position after entry content. In
1256 lists, insert a new item or end the list, with checkbox if
1257 appropriate. In tables, insert a new row or end the table."
1258 ;; Inspired by John Kitchin: http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/
1259 (interactive "P")
1260 (if default
1261 (org-return)
1262 (cond
1263 ;; Act depending on context around point.
1264
1265 ;; NOTE: I prefer RET to not follow links, but by uncommenting this block,
1266 ;; links will be followed.
1267
1268 ;; ((eq 'link (car (org-element-context)))
1269 ;; ;; Link: Open it.
1270 ;; (org-open-at-point-global))
1271
1272 ((org-at-heading-p)
1273 ;; Heading: Move to position after entry content.
1274 ;; NOTE: This is probably the most interesting feature of this function.
1275 (let ((heading-start (org-entry-beginning-position)))
1276 (goto-char (org-entry-end-position))
1277 (cond ((and (org-at-heading-p)
1278 (= heading-start (org-entry-beginning-position)))
1279 ;; Entry ends on its heading; add newline after
1280 (end-of-line)
1281 (insert "\n\n"))
1282 (t
1283 ;; Entry ends after its heading; back up
1284 (forward-line -1)
1285 (end-of-line)
1286 (when (org-at-heading-p)
1287 ;; At the same heading
1288 (forward-line)
1289 (insert "\n")
1290 (forward-line -1))
1291 ;; FIXME: looking-back is supposed to be called with more arguments.
1292 (while (not (looking-back (rx (repeat 3 (seq (optional blank) "\n")))))
1293 (insert "\n"))
1294 (forward-line -1)))))
1295
1296 ((org-at-item-checkbox-p)
1297 ;; Checkbox: Insert new item with checkbox.
1298 (org-insert-todo-heading nil))
1299
1300 ((org-in-item-p)
1301 ;; Plain list. Yes, this gets a little complicated...
1302 (let ((context (org-element-context)))
1303 (if (or (eq 'plain-list (car context)) ; First item in list
1304 (and (eq 'item (car context))
1305 (not (eq (org-element-property :contents-begin context)
1306 (org-element-property :contents-end context))))
1307 (unpackaged/org-element-descendant-of 'item context)) ; Element in list item, e.g. a link
1308 ;; Non-empty item: Add new item.
1309 (org-insert-item)
1310 ;; Empty item: Close the list.
1311 ;; TODO: Do this with org functions rather than operating on the text. Can't seem to find the right function.
1312 (delete-region (line-beginning-position) (line-end-position))
1313 (insert "\n"))))
1314
1315 ((when (fboundp 'org-inlinetask-in-task-p)
1316 (org-inlinetask-in-task-p))
1317 ;; Inline task: Don't insert a new heading.
1318 (org-return))
1319
1320 ((org-at-table-p)
1321 (cond ((save-excursion
1322 (beginning-of-line)
1323 ;; See `org-table-next-field'.
1324 (cl-loop with end = (line-end-position)
1325 for cell = (org-element-table-cell-parser)
1326 always (equal (org-element-property :contents-begin cell)
1327 (org-element-property :contents-end cell))
1328 while (re-search-forward "|" end t)))
1329 ;; Empty row: end the table.
1330 (delete-region (line-beginning-position) (line-end-position))
1331 (org-return))
1332 (t
1333 ;; Non-empty row: call `org-return'.
1334 (org-return))))
1335 (t
1336 ;; All other cases: call `org-return'.
1337 (org-return)))))
1338
1339 (bind-key "RET" #'unpackaged/org-return-dwim 'org-mode-map)
1340#+end_src
1341
1342** “Typographical editing” with [[https://github.com/jorgenschaefer/typoel][Typo]]
1343
1344When I'm writing, I've been annoyed at the straight quotes.
1345 626
1346#+begin_src emacs-lisp 627#+begin_src emacs-lisp
1347 (use-package typo 628 (use-package typo
1348 :hook
1349 (text-mode . typo-mode))
1350#+end_src
1351
1352* Coding
1353
1354The Other Thing Emacs is Good For.
1355
1356** Formatting
1357
1358*** Indenting: [[https://github.com/Malabarba/aggressive-indent-mode][aggressive-indent-mode]]
1359
1360This automagically indents code on every change, as opposed to =electric-indent-mode=, which only does when I like, hit =RET= or whatever. As such, I can turn =electric-indent-mode= off.
1361
1362#+begin_src emacs-lisp
1363 (use-package aggressive-indent
1364 :init
1365 (electric-indent-mode -1)
1366 :config
1367 (global-aggressive-indent-mode 1))
1368#+end_src
1369
1370*** [[https://github.com/jcsalomon/smarttabs][Smart tabs]]
1371
1372I really want to like, use tabs all the time. But I thought the =smart-tabs= package author made some good points about using tabs for semantic indentation, and spaces for the rest. So.
1373
1374#+begin_src emacs-lisp
1375 (use-package smart-tabs-mode
1376 :custom
1377 (whitespace-style
1378 '(face trailing tabs spaces lines newline
1379 empty indentation space-before-tab
1380 space-mark tab-mark newline-mark))
1381 :config
1382 (smart-tabs-insinuate 'c 'c++ 'javascript 'java 'ruby))
1383#+end_src
1384
1385** Display
1386
1387*** Prettify symbols mode
1388
1389By default, I think =prettify-symbols-mode= only changes =lambda= to =λ=. I should, at some point, add some prettified symbols.
1390
1391#+begin_src emacs-lisp
1392 (add-hook 'prog-mode-hook #'prettify-symbols-mode)
1393#+end_src
1394
1395*** Parentheses and frens
1396
1397**** =show-paren-style=
1398
1399A =mixed= =show-paren-style= means that, when both parentheses are visible, it just highlights them. If one is /not/, though, it highlights the entire block.
1400
1401#+begin_src emacs-lisp
1402 (cuss show-paren-style 'mixed)
1403 (cuss show-paren-delay 0)
1404
1405 (show-paren-mode 1)
1406#+end_src
1407
1408**** [[https://github.com/Fuco1/smartparens][smartparens]]
1409
1410Automagically close pairs and stuff. See also [[https://www.emacswiki.org/emacs/ParEdit][ParEdit]] -- maybe test that one?
1411
1412#+begin_src emacs-lisp
1413 (use-package smartparens
1414 :init
1415 (defun acdw/setup-smartparens ()
1416 (require 'smartparens-config)
1417 (smartparens-mode 1))
1418 :hook 629 :hook
1419 (prog-mode . acdw/setup-smartparens)) 630 (text-mode . typo-mode))
1420#+end_src
1421
1422**** [[https://github.com/Fanael/rainbow-delimiters][rainbow-delimiters]]
1423
1424Show different pairs of delimiters in diffferent colors. Pretty! Useful!
1425
1426#+begin_src emacs-lisp
1427 (use-package rainbow-delimiters
1428 :hook (prog-mode . rainbow-delimiters-mode))
1429#+end_src
1430
1431*** [[https://elpa.gnu.org/packages/rainbow-mode.html][rainbow-mode]]
1432
1433Show different colors /in that color/. Useful! Pretty!
1434
1435#+begin_src emacs-lisp
1436 (use-package rainbow-mode
1437 :custom
1438 (rainbow-x-colors nil)
1439 :hook prog-mode)
1440#+end_src
1441
1442*** Line numbers
1443
1444I only want line numbers in =prog-mode=-derived modes. In addition, apparently =linum-mode= works better in TUI, but is slower that =display-line-numbers=. So I want to do some logic to see what to use.
1445
1446#+begin_src emacs-lisp
1447 (defun acdw/enable-line-numbers ()
1448 "Enable line numbers, either through `display-line-numbers-mode'
1449 or through `linum-mode'."
1450 (if (and (fboundp 'display-line-numbers-mode)
1451 (display-graphic-p))
1452 (progn
1453 (display-line-numbers-mode 1)
1454 (cuss display-line-numbers-width 2))
1455 (linum-mode 1)))
1456
1457 (add-hook 'prog-mode-hook #'acdw/enable-line-numbers)
1458#+end_src
1459
1460*** [[https://github.com/tarsius/hl-todo][hl-todo]]
1461
1462#+begin_src emacs-lisp
1463 (use-package hl-todo
1464 :hook (prog-mode . hl-todo-mode))
1465#+end_src
1466
1467** Programming languages
1468
1469These are the programming languages I (don't really) use.
1470
1471*** Fish shell
1472
1473#+begin_src emacs-lisp
1474 (use-package fish-mode)
1475#+end_src
1476
1477*** Lisps
1478
1479**** Common Lisp (SLIME)
1480
1481 #+begin_src emacs-lisp
1482 (use-package slime
1483 :when (executable-find "sbcl")
1484 :custom
1485 (inferior-lisp-program "sbcl")
1486 (slime-contribs '(slime-fancy)))
1487 #+end_src
1488
1489**** Fennel
1490
1491#+begin_src emacs-lisp
1492 (use-package fennel-mode
1493 :mode "\\.fnl\\'")
1494#+end_src
1495
1496*** Lua
1497
1498#+begin_src emacs-lisp
1499 (use-package lua-mode
1500 :mode "\\.lua\\'"
1501 :interpreter "lua")
1502#+end_src
1503
1504*** Web (HTML/CSS/JS)
1505
1506#+begin_src emacs-lisp
1507 (use-package web-mode
1508 :mode (("\\.ts\\'" . web-mode)
1509 ("\\.html?\\'" . web-mode)
1510 ("\\.css?\\'" . web-mode)
1511 ("\\.js\\'" . web-mode)))
1512#+end_src
1513
1514*** =~/.ssh/config=
1515
1516#+begin_src emacs-lisp
1517 (use-package ssh-config-mode)
1518#+end_src
1519
1520*** Go
1521
1522#+begin_src emacs-lisp
1523 (use-package go-mode
1524 :mode "\\.go\\'"
1525 :hook
1526 (before-save . gofmt-before-save))
1527#+end_src 631#+end_src
1528 632
1529* Applications 633* Applications
1530 634
1531Of course, the real reason we love emacs is for the application layer. What is it they say? 635** Magit
1532
1533#+begin_quote
1534Emacs is a great operating system, lacking only a decent editor.
1535#+end_quote
1536
1537Yeah, that's it 😎
1538
1539** Git: [[https://magit.vc/][magit]]
1540
1541The magical porcelain.
1542 636
1543#+begin_src emacs-lisp 637#+begin_src emacs-lisp
1544 (use-package magit 638 (use-package magit
1545 :bind 639 :bind
1546 ("C-x g" . magit-status) 640 ("C-x g" . magit-status))
1547 :custom-update 641#+end_src
1548 (magit-no-confirm '(stage-all-changes)) 642
1549 :config 643* Appendices
1550 (add-hook 'magit-process-find-password-functions 644** Emacs' files
1551 #'magit-process-password-auth-source)) 645*** init.el
1552#+end_src 646 :PROPERTIES:
1553 647 :header-args: :tangle init.el
1554*** Hook into =prescient= 648 :END:
1555 649
1556#+begin_src emacs-lisp 650 #+begin_src emacs-lisp :comments no
1557 (define-advice magit-list-refs 651 ;; init.el -*- lexical-binding: t -*-
1558 (:around (orig &optional namespaces format sortby) 652 #+end_src
1559 prescient-sort) 653**** Load config
1560 "Apply prescient sorting when listing refs." 654
1561 (let ((res (funcall orig namespaces format sortby))) 655 from [[https://protesilaos.com/dotemacs/#h:584c3604-55a1-49d0-9c31-abe46cb1f028][Protesilaos Stavrou]].
1562 (if (or sortby 656
1563 magit-list-refs-sortby 657 #+begin_src emacs-lisp
1564 (not selectrum-should-sort-p)) 658 (let* ((conf (expand-file-name "config"
1565 res 659 user-emacs-directory))
1566 (prescient-sort res)))) 660 (elc (concat conf ".elc"))
1567#+end_src 661 (el (concat conf ".el"))
1568 662 (org (concat conf ".org")))
1569*** Use =libgit= when I can build it (requires =cmake=) 663 (cond ((file-exists-p elc) (load-file elc))
1570 664 ((file-exists-p el) (load-file el))
1571#+begin_src emacs-lisp 665 (t (require 'org)
1572 (when (executable-find "cmake") 666 (org-babel-load-file org))))
1573 (use-package libgit) 667 #+end_src
1574 (use-package magit-libgit)) 668
1575#+end_src 669*** early-init.el
1576 670 :PROPERTIES:
1577*** Git "forge" capabilities 671 :header-args: :tangle early-init.el
1578 672 :END:
1579#+begin_src emacs-lisp 673
1580 (use-package forge 674 #+begin_src emacs-lisp :comments no
1581 :after magit 675 ;; early-init.el -*- lexical-binding: t; no-byte-compile: t; -*-
1582 :unless (eq system-type 'windows-nt) 676 #+end_src
1583 :custom 677
1584 (forge-owned-accounts 678 #+begin_src emacs-lisp
1585 '(("duckwork")))) 679 (setq load-prefer-newer t)
1586#+end_src 680 (setq frame-inhibit-implied-resize t)
1587 681 #+end_src
1588** Dired 682
1589 683** Ease tangling and loading of Emacs' init
1590I'm still figuring out what all I can do with =dired=.
1591
1592#+begin_src emacs-lisp
1593 (with-eval-after-load 'dired
1594 (cuss dired-dwim-target t)
1595 (cuss dired-listing-switches "-alDh")
1596
1597 (cuss wdired-allow-to-change-permissions t)
1598 (bind-key "C-c w" #'wdired-change-to-wdired-mode 'dired-mode-map))
1599#+end_src
1600
1601*** dired-subtree
1602
1603Part of the [[https://github.com/Fuco1/dired-hacks][dired-hacks]] package.
1604
1605#+begin_src emacs-lisp
1606 (use-package dired-subtree
1607 :bind (:map dired-mode-map
1608 (("i" . dired-subtree-insert)
1609 (";" . dired-subtree-remove))))
1610#+end_src
1611
1612** Proced
1613
1614The process editor.
1615
1616#+begin_src emacs-lisp
1617 (defun acdw/setup-proced ()
1618 (variable-pitch-mode -1)
1619 (toggle-truncate-lines 1)
1620 (proced-toggle-auto-update 1))
1621 684
1622 (add-hook 'proced-mode-hook #'acdw/setup-proced) 685 #+begin_src emacs-lisp
1623#+end_src 686 (defun acdw/tangle-and-load-init ()
1624 687 (interactive)
1625** Gemini (and gopher) 688 "If the current buffer is `config.org', tangle it, then byte-compile."
1626 689 (let ((config (expand-file-name "config.org" user-emacs-directory)))
1627*** [[https://thelambdalab.xyz/elpher/][elpher]] 690 (when (string= (buffer-file-name) config)
1628 691 (let ((prog-mode-hook nil))
1629Actually, =elpher= is the reason I started using Emacs. So thanks, smol web denizens! 692 (require 'org)
1630 693 (org-babel-tangle-file config)
1631Fun fact: these packages are /also/ why I use =straight.el=, since they're none of them on GitHub. 694 (org-md-export-to-markdown)
1632 695
1633#+BEGIN_SRC emacs-lisp 696 (dolist (file `(,(expand-file-name "init.el"
1634 (use-package elpher 697 user-emacs-directory)
1635 :straight (elpher 698 ,(expand-file-name "config.el"
1636 :repo "git://thelambdalab.xyz/elpher.git") 699 user-emacs-directory)))
1637 :custom 700 (byte-compile-file file t))))))
1638 (elpher-certificate-directory 701
1639 (no-littering-expand-var-file-name "elpher-certificates/")) 702 (add-hook 'after-save-hook #'acdw/tangle-and-load-init)
1640 (elpher-ipv4-always t) 703 #+end_src
1641 :custom-face 704** License
1642 (elpher-gemini-heading1 705 :PROPERTIES:
1643 ((t (:inherit (modus-theme-heading-1))))) 706 :header-args: :tangle LICENSE :comments no
1644 (elpher-gemini-heading2 707 :END:
1645 ((t (:inherit (modus-theme-heading-2)))))
1646 (elpher-gemini-heading3
1647 ((t (:inherit (modus-theme-heading-3)))))
1648 :config
1649 (defun elpher:eww-browse-url (original url &optional new-window)
1650 "Handle gemini/gopher links with eww."
1651 (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
1652 (require 'elpher)
1653 (elpher-go url))
1654 (t (funcall original url new-window))))
1655 (advice-add 'eww-browse-url :around 'elpher:eww-browse-url)
1656 :bind (:map elpher-mode-map
1657 ("n" . elpher-next-link)
1658 ("p" . elpher-prev-link)
1659 ("o" . elpher-follow-current-link)
1660 ("G" . elpher-go-current))
1661 :hook
1662 (elpher-mode . visual-fill-column-mode))
1663#+end_src
1664
1665*** [[https://git.carcosa.net/jmcbray/gemini.el][gemini-mode]]
1666
1667A major mode for =text/gemini= files. I've changed the headings to match Elpher's.
1668
1669#+BEGIN_SRC emacs-lisp
1670 (use-package gemini-mode
1671 :straight (gemini-mode
1672 :repo "https://git.carcosa.net/jmcbray/gemini.el.git")
1673 :mode "\\.\\(gemini|gmi\\)\\'"
1674 :custom-face
1675 (gemini-heading-face-1
1676 ((t (:inherit (elpher-gemini-heading1)))))
1677 (gemini-heading-face2
1678 ((t (:inherit (elpher-gemini-heading2)))))
1679 (gemini-heading-face3
1680 ((t (:inherit (elpher-gemini-heading3)))))
1681 :init
1682 (defun acdw/setup-gemini-mode ()
1683 (visual-fill-column-mode 1)
1684 (variable-pitch-mode -1))
1685 :hook
1686 (gemini-mode . acdw/setup-gemini-mode))
1687#+end_src
1688
1689*** [[https://alexschroeder.ch/cgit/gemini-write/about/][gemini-write]]
1690
1691Alex Schroeder's Emacs implementation of the Titan protocol. This is why I use his Gemini server, [[https://alexschroeder.ch/cgit/phoebe/][Phoebe]]!
1692
1693#+BEGIN_SRC emacs-lisp
1694 (use-package gemini-write
1695 :straight (gemini-write
1696 :repo "https://alexschroeder.ch/cgit/gemini-write")
1697 :config
1698 (when (boundp 'acdw-secrets/elpher-gemini-tokens)
1699 (dolist (token acdw-secrets/elpher-gemini-tokens)
1700 (add-to-list 'elpher-gemini-tokens token))))
1701#+end_src
1702
1703*** [[https://git.sr.ht/~acdw/post-to-gemlog-blue.el][post-to-gemlog-blue]]
1704
1705My first (!) Emacs package, to allow posting to [[https://gemlog.blue][gemlog.blue's web interface]]. I don't use gemlog.blue any more, but if I didn't have this package, no one would 😎
1706
1707#+BEGIN_SRC emacs-lisp
1708 (use-package post-to-gemlog-blue
1709 :straight (post-to-gemlog-blue
1710 :repo "https://git.sr.ht/~acdw/post-to-gemlog-blue.el"))
1711#+END_SRC
1712
1713** Pastebin: [[https://git.sr.ht/~zge/nullpointer-emacs][0x0]]
1714
1715Pastebins are so useful. Now I can use them from Emacs.
1716
1717#+BEGIN_SRC emacs-lisp
1718 (use-package 0x0
1719 :custom
1720 (0x0-default-service 'ttm))
1721#+END_SRC
1722
1723** [[https://www.djcbsoftware.nl/code/mu/mu4e.html][mu4e]]
1724
1725I've just recently started (again) using mu4e. We'll see how it goes.
1726
1727#+begin_src emacs-lisp
1728 (when (executable-find "mu")
1729 (add-to-list 'load-path
1730 "/usr/share/emacs/site-lisp/mu4e")
1731 (require 'mu4e)
1732
1733 (cuss mail-user-agent 'mu4e-user-agent)
1734
1735 (cuss mu4e-headers-skip-duplicates t)
1736 (cuss mu4e-view-show-images t)
1737 (cuss mu4e-view-show-addresses t)
1738 (cuss mu4e-compose-format-flowed t)
1739 (cuss mu4e-change-filenames-when-moving t)
1740 (cuss mu4e-attachments-dir "~/Downloads")
1741
1742 (cuss mu4e-maildir "~/.mail/fastmail")
1743 (cuss mu4e-refile-folder "/Archive")
1744 (cuss mu4e-sent-folder "/Sent")
1745 (cuss mu4e-drafts-folder "/Drafts")
1746 (cuss mu4e-trash-folder "/Trash")
1747
1748 (fset 'my-move-to-trash "mTrash")
1749 (define-key mu4e-headers-mode-map (kbd "d") 'my-move-to-trash)
1750 (define-key mu4e-view-mode-map (kbd "d") 'my-move-to-trash)
1751
1752 (cuss message-send-mail-function 'smtpmail-send-it)
1753 (cuss smtpmail-default-smtp-server "smtp.fastmail.com")
1754 (cuss smtpmail-smtp-server "smtp.fastmail.com")
1755 (cuss smtpmail-stream-type 'ssl)
1756 (cuss smtpmail-smtp-service 465)
1757 (cuss smtpmail-local-domain "acdw.net")
1758 (cuss mu4e-compose-signature
1759 "Best,\nCase\n")
1760
1761 (cuss mu4e-get-mail-command "mbsync -a")
1762 (cuss mu4e-update-interval 300)
1763
1764 (cuss mu4e-completing-read-function 'completing-read)
1765 (cuss message-kill-buffer-on-exit t)
1766 (cuss mu4e-confirm-quit nil)
1767
1768 (cuss mu4e-bookmarks
1769 '((
1770 :name "Unread"
1771 :query
1772 "flag:unread AND NOT flag:trashed AND NOT maildir:/Spam"
1773 :key ?u)
1774 (
1775 :name "Today"
1776 :query "date:today..now and not maildir:/Spam"
1777 :key ?t)
1778 (
1779 :name "This week"
1780 :query "date:7d..now and not maildir:/Spam"
1781 :hide-unread t
1782 :key ?w)))
1783
1784 (cuss mu4e-headers-fields
1785 '((:human-date . 12)
1786 (:flags . 6)
1787 (:mailing-list . 10)
1788 (:from-or-to . 22)
1789 (:subject)))
1790
1791 (defun acdw/setup-mu4e-view-mode ()
1792 (visual-fill-column-mode))
1793
1794 (add-hook 'mu4e-view-mode-hook #'acdw/setup-mu4e-view-mode))
1795
1796 ;; not sure about this...
1797 (use-package mu4e-dashboard
1798 :straight (mu4e-dashboard
1799 :host github
1800 :repo "rougier/mu4e-dashboard"
1801 :branch "main"))
1802
1803#+end_src
1804
1805** KeePassXC integration
1806
1807I use KeePassXC, and I'd /like/ to use KeePassXC to get passwords and stuff at home. So I'm trying this library out, since the secret-tool integration isn't built into the KeePassXC on Void. If this doesn't work, looks like I'll have to become a packager 😜
1808
1809#+begin_src emacs-lisp :noweb yes :tangle no
1810 (when (eq system-type 'gnu/linux)
1811 <<use-package-sodium>>
1812 (use-package keepassxc
1813 :straight (keepassxc
1814 :host github
1815 :repo "dakra/keepassxc.el")
1816 :after (sodium)))
1817#+end_src
1818
1819*** libsodium integration
1820
1821I had to manually run ~make~ in the repo this time around, for some reason. Should probably look into that ... when it's not 1:00 AM.
1822
1823#+NAME: use-package-sodium
1824#+begin_src emacs-lisp :tangle no
1825 (use-package sodium
1826 :straight (sodium
1827 :host github
1828 :repo "dakra/sodium.el"
1829 :build ("make"))
1830 :init
1831 (add-to-list 'load-path
1832 (expand-file-name "straight/repos/sodium.el"
1833 user-emacs-directory)))
1834#+end_src
1835
1836** [[https://github.com/skeeto/elfeed][elfeed]]
1837
1838Let's use Emacs as a feed reader! A number of these tweaks are from [[https://karthinks.com/software/lazy-elfeed/]["Lazy Elfeed"]].
1839
1840#+begin_src emacs-lisp
1841 (use-package elfeed
1842 :when (executable-find "curl")
1843 :hook
1844 (elfeed-show-mode . visual-fill-column-mode)
1845 (kill-emacs . elfeed-db-compact))
1846#+end_src
1847
1848*** [[elfeed-org][elfeed-org]]
1849
1850This way, I can configure my feeds in an [[file:elfeed.org][org file]]!
1851
1852#+begin_src emacs-lisp
1853 (use-package elfeed-org
1854 :custom
1855 (rmh-elfeed-org-files
1856 (list (expand-file-name "elfeed.org"
1857 user-emacs-directory)))
1858 :init
1859 (elfeed-org))
1860#+end_src
1861
1862** Emacs Web WOWser
1863
1864I can /not/ get over how hilarious this name is 😜
1865
1866#+begin_src emacs-lisp
1867 (use-package eww
1868 :custom
1869 (shr-animate-image nil)
1870 :bind (:map eww-mode-map
1871 ("b" . #'eww-back-url)
1872 ("f" . #'eww-forward-url))
1873 :config
1874 (require 'url-cookie)
1875 (cuss url-cookie-confirmation t))
1876#+end_src
1877
1878** TODO eshell
1879
1880look at [[https://github.com/dieggsy/esh-autosuggest/][esh-autosuggest]] and [[https://www.masteringemacs.org/article/complete-guide-mastering-eshell][mastering eshell]] and stuff. idk.
1881oh and [[https://github.com/kyagi/shell-pop-el][shell pop]] too.
1882
1883** [[https://github.com/politza/pdf-tools][PDF Tools]]
1884
1885There's a few things that have to be installed to use PDF Tools, but I've got them installed on =larry=. Once I write them down, I'll expand this out to both my linux machines.
1886
1887#+begin_src emacs-lisp
1888 (when (string= (system-name) "larry")
1889 (use-package pdf-tools
1890 :init
1891 (pdf-loader-install)))
1892#+end_src
1893
1894* Appendix A: Scripts
1895
1896** ~emacsdc~
1897
1898Here's a wrapper script that'll start =emacs --daemon= if there isn't one, and then launche =emacsclient= on the arguments. I'd recommend installing with ~ln -s emacsdc ~/.local/bin/~ or something. Then you can set it as your ~$EDITOR~!
1899
1900#+begin_src sh :shebang "#!/bin/sh" :tangle bin/emacsdc
1901 if ! emacsclient -nc "$@" 2>/dev/null; then
1902 emacs --daemon
1903 emacsclient -nc "$@"
1904 fi
1905#+end_src
1906
1907* Appendix B: areas for further research
1908
1909- [[https://github.com/caisah/emacs.dz][big list of popular emacs configs]]
1910
1911** TODO [[https://github.com/flexibeast/ebuku][ebuku]] (of course, I'd need [[https://github.com/jarun/buku][buku]] as well) -- bookmarks
1912** TODO [[https://github.com/rolandwalker/ignoramus][Ignoramus]] -- this might not e necessary
1913** TODO [[https://git.sr.ht/~iank/visible-mark][visible mark]] -- show where the marks are ...
1914** TODO consider this Reddit thread: [[https://www.reddit.com/r/emacs/comments/k3xfa1/speeding_up_magit/][speeding up magit]]
1915** TODO [[https://github.com/legalnonsense/org-visual-outline][org-visual-outline]] -- interesting org organization tool
1916** TODO export org to ODT on Windows
1917
1918Windows doesn't have =zip= natively (though it /does/ have =curl= -- go figure!), so the ODT export for Org-mode won't work. There /is/ a [[https://stackoverflow.com/questions/8625306/org-mode-zip-needed-how-to-over-come][StackOverflow discussion]] that mentions =p7zip= and a possible batch file, but I couldn't get that to work with a little testing. It might need more work.
1919 708
1920Something that /did/ work was downloading =zip.exe= from [[http://infozip.sourceforge.net/][Info-ZIP]], and placing it somewhere in =exec-path= -- though of course, /then/ you need =unzip.exe=, apparently in the same folder. Git Portable ships with =unzip.exe=, for example, but even though it's in =exec-path=, org-export threw an error unless =zip= and =unzip= were in the /same/ folder. 709 Copyright 2020 Case Duckworth <acdw@acdw.net>
1921 710
1922So I might either (a) have to set up computers in this way when I use new ones, or (b) include both =zip.exe= and =unzip.exe= in /this/ Git repo, or ... something else. A true quandry. 711 This work is free. You can redistribute it and/or modify it under the
712 terms of the Do What the Fuck You Want To Public License, Version 2,
713 as published by Sam Hocevar. See the =LICENSE= file, tangled from the
714 following source block, for details.
1923 715
1924** TODO Fix slowdown on =C-x 8 RET= 716 #+begin_src text
717 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
1925 718
1926I think it has something to do with the package =consult=, because it was /slow/, but not *this slow* before installing it. Since it's slow anyway, I'm thinking I should figure out how to turn off =selectrum= when selecting a Unicode character anyway. Maybe advice? 719 Version 2, December 2004
1927 720
1928** TODO Figure out Org-mode TODOs 721 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
1929 722
1930I need some standard once, and also some specific ones for this section. 723 Everyone is permitted to copy and distribute verbatim or modified copies of
724 this license document, and changing it is allowed as long as the name is changed.
1931 725
1932** TODO Add =C-z= as a me-mode map 726 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
1933 727
1934I saw someone do this, and honestly it's a great idea. I could use it for my applications. Just have to find it ...... 728 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1935 729
1936** TODO Really think about [[https://github.com/abo-abo/avy][avy]] again 730 0. You just DO WHAT THE FUCK YOU WANT TO.
731 #+end_src
1937 732
1938It could actually be pretty useful, and it could be hooked into things like [[https://github.com/abo-abo/ace-link][ace-link]]. 733*** Note on the license
1939 734
1940** TODO Test out [[https://github.com/magnars/multiple-cursors.el][multiple cursors]] 735 It's highly likely that the WTFPL is completely incompatible with the
736 GPL, for what should be fairly obvious reasons. To that, I say:
1941 737
1942Allegedly it's really cool. 738 *SUE ME, RMS!*