summary refs log tree commit diff stats
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md2030
1 files changed, 635 insertions, 1395 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.