diff options
Diffstat (limited to 'README.md')
-rw-r--r-- | README.md | 2030 |
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 @@ | |||
1 | This 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 | 4 | 1. [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) | |
13 | Copyright © 2020 Case Duckworth <acdw@acdw.net> | 12 | 2. [A macro for ease of customization](#org2cf1d1a) |
14 | 13 | 4. [Keep a tidy `~/.emacs`](#orga6c0096) | |
15 | This 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. | 14 | 2. [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 | 33 | 3. [Interactivity](#org6cbcfe5) | |
35 | It'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 | 40 | 4. [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) | |
45 | This 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: | 44 | 1. [Easily navigate recent files](#org9368a6b) |
46 | 45 | 4. [Undo](#orgbb4f91a) | |
47 | git update-index --assume-unchanged init.el | 46 | 5. [Editing](#org52b008a) |
48 | 47 | 1. [Operate visually on lines](#orgce838ba) | |
49 | If, 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) | |
53 | Otherwise, here's the actual, original `init.el` that tangles this Org file and gets us going. | 52 | 4. [So long mode](#org27f430f) |
54 | 53 | 6. [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 | 61 | 7. [Programming](#org738fbd9) | |
63 | ### TODO What I should do instead | 62 | 1. [Which function are we in?](#org080eb2f) |
64 | 63 | 8. [Writing](#org6bf5097) | |
65 | Honestly, 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 … | 64 | 1. [Visual Fill Column](#org6f01971) |
66 | 65 | 2. [Type nice-looking quote-type marks](#org03e747d) | |
67 | 66 | 9. [Applications](#org9528516) | |
68 | ## Tangling | 67 | 1. [Magit](#orgd2a60aa) |
69 | 68 | 10. [Appendices](#org7339cf2) | |
70 | After 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" | |
91 | Since 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") | |
95 | Finally, 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`. | 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 | ||
110 | I 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) | |
120 | While 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 [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 | |||
127 | Starting 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 | |||
129 | Of course, I also want to set some really early-on settings here too, like `load-prefer-newer` – 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 | |||
137 | Let'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 | |||
150 | When 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 | |||
158 | Elsewhere, 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 | |||
170 | So 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 | |||
172 | The 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 | ## … but first: override the definition of straight.el to use the `develop` branch | ||
190 | |||
191 | For 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 | |||
212 | Like 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 | |||
220 | I'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`. | ||
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 | ||
231 | The `: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 | ||
237 | instead of this: | 138 | ### Extra use-package keywords |
238 | 139 | ||
239 | (use-package package | 140 | 1. :custom-update |
240 | :config | ||
241 | (add-to-list 'package-list '(1 2 3))) | ||
242 | 141 | ||
243 | It's not … 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 | |||
253 | I thought this was included in Emacs at first, but it's not – 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 | ||
264 | I 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. | 150 | <a id="org7cae7fe"></a> |
265 | 151 | ||
266 | Except. 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. | 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 | ||
277 | Protesilaos 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 | ||
279 | The 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 | ||
320 | I 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 | ||
337 | I 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 | ||
352 | Of course, on the minibuffer, I want to make sure there's no scrollbar – 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 | ||
364 | The [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 | ||
374 | I'm kind of getting into Emacs tabs – 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 | ||
404 | This 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 | ||
424 | from [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 | ||
432 | I 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 | 286 | 1. 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 | 295 | 2. Keep the cursor from going into the prompt |
440 | 296 | ||
441 | I 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 | ||
305 | 1. 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 | ||
452 | This 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 ["Testing if fonts are available?"](https://www.emacswiki.org/emacs/SetFonts#toc11) section of the SetFonts page on EmacsWiki. | 309 | 2. Only show the tab bar when there's more than one tab |
453 | 310 | ||
454 | See [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 | ||
497 | This 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) | |
506 | One 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 | |||
513 | This has been taken from ["Ricing Org Mode"](https://lepisma.xyz/2017/10/28/ricing-org-mode/) – 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 | ||
523 | I 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 – 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 – 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 – 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 | |||
395 | 1. 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 | |||
435 | 2. Variable-pitch in text modes | ||
436 | |||
437 | (add-hook 'text-mode-hook #'variable-pitch-mode) | ||
438 | |||
439 | 3. Line spacing | ||
440 | |||
441 | (cuss line-spacing 0.1) | ||
442 | |||
443 | 4. 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 | ||
563 | By 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 | |||
587 | I 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 | |||
596 | The 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 | |||
612 | This 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 | |||
623 | Maybe a better title for this section is **Other settings** – 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 | |
640 | By 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))) | |
647 | Instead 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 | |||
654 | This 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 | |||
662 | These 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 | |||
672 | At 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 | |||
679 | Most 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 | |||
688 | 1. 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 | |||
697 | 2. 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 | ||
706 | I 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 | ||
714 | I 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 | ||
725 | Honestly, 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 | |||
730 | The 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. | ||
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 | |||
742 | To 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 | |||
755 | Since 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 😎 | ||
756 | |||
757 | But 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 | |||
773 | Now 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 | ||
817 | The 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 | ||
819 | Note 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 | |||
838 | I 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 | |||
840 | I'm going to be honest – 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 | |||
862 | I'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. | ||
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 | |||
872 | Another 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. | ||
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 | ||
885 | Highlights 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 | ||
894 | I don't use this a *ton*, but not because it's not useful – 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 | ||
896 | Basically, 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 | ||
906 | I'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 | ||
914 | Revert 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 | ||
921 | Configurations 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 | ||
934 | Center 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 | |||
951 | In `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 | |||
968 | Pretty self-explanatory, I think… | ||
969 | |||
970 | I 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 | |||
989 | from [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 | |||
1025 | from [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 | |||
1069 | from [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 | ||
1174 | The 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 | ||
1182 | This 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 | ||
1193 | I 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 | ||
1210 | By 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 | ||
1217 | 1. `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. | 694 | from [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 | ||
1224 | 2. [smartparens](https://github.com/Fuco1/smartparens) | 702 | 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. |
1225 | 703 | ||
1226 | Automagically close pairs and stuff. See also [ParEdit](https://www.emacswiki.org/emacs/ParEdit) – 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 | ||
1236 | 3. [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 | ||
1246 | Show 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 | ||
1256 | I 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 | ||
1273 | These 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 | ||
1283 | 1. 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 | ||
1291 | 2. 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 | ||
1328 | Of 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 | |||
1332 | Yeah, that's it 😎 | ||
1333 | |||
1334 | |||
1335 | ## Git: [magit](https://magit.vc/) | ||
1336 | 787 | ||
1337 | The 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 | ||
1382 | I'm still figuring out what all I can do with `dired`. | 813 | 1. 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 | ||
1394 | Part 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 | ||
1404 | The 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 | ||
865 | Copyright 2020 Case Duckworth <acdw@acdw.net> | ||
1416 | 866 | ||
1417 | ### [elpher](https://thelambdalab.xyz/elpher/) | 867 | This work is free. You can redistribute it and/or modify it under the |
868 | terms of the Do What the Fuck You Want To Public License, Version 2, | ||
869 | as published by Sam Hocevar. See the `LICENSE` file, tangled from the | ||
870 | following source block, for details. | ||
1418 | 871 | ||
1419 | Actually, `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 | ||
1421 | Fun 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) | 892 | It's highly likely that the WTFPL is completely incompatible with the |
893 | GPL, for what should be fairly obvious reasons. To that, I say: | ||
1455 | 894 | ||
1456 | A 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 | |||
1479 | Alex 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 | |||
1492 | My 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 | |||
1501 | Pastebins 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 | |||
1510 | I'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 | |||
1592 | I 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 | |||
1613 | I 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. | ||
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 | |||
1631 | Here'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 | |||
1633 | if ! 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) – bookmarks | ||
1642 | - [KeePassXC as Secret Service](https://www.billdietrich.me/Authentication.html?expandall=1#KeePassXCandSecretService) – see [14.7](#orgb5347d4) | ||
1643 | - [Ignoramus](https://github.com/rolandwalker/ignoramus) – this might not e necessary | ||
1644 | - [Dynamic fonts](https://github.com/rolandwalker/dynamic-fonts) – take a look @ this and compare with my fonts section | ||
1645 | - [Simple clipboard integration](https://github.com/rolandwalker/simpleclip) – test with Windows, maybe | ||
1646 | - [visible mark](https://git.sr.ht/~iank/visible-mark) – show where the marks are … | ||
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 | |||
1652 | Windows 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 [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 | |||
1654 | Something that *did* work was downloading `zip.exe` from [Info-ZIP](http://infozip.sourceforge.net/), 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. | ||
1655 | 896 | ||
1656 | So 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. | ||