diff options
-rw-r--r-- | README.md | 1248 |
1 files changed, 745 insertions, 503 deletions
diff --git a/README.md b/README.md index d6b2457..44219ec 100644 --- a/README.md +++ b/README.md | |||
@@ -1,13 +1,17 @@ | |||
1 | Why the hell not, let’s do this again. | 1 | # Basics |
2 | 2 | ||
3 | 3 | ||
4 | # Basics | 4 | ## Disclaimer |
5 | |||
6 | ;; config.el -*- lexical-binding: t -*- | ||
7 | ;; This file is automatically tangled from config.org. | ||
8 | ;; Hand edits will be overwritten! | ||
5 | 9 | ||
6 | 10 | ||
7 | ## About me | 11 | ## About me |
8 | 12 | ||
9 | (setq user-full-name "Case Duckworth" | 13 | (setq user-full-name "Case Duckworth" |
10 | user-mail-address "acdw@acdw.net") | 14 | user-mail-address "acdw@acdw.net") |
11 | 15 | ||
12 | 16 | ||
13 | ## Correct `exec-path` | 17 | ## Correct `exec-path` |
@@ -16,25 +20,25 @@ Straight depends on Git, so I need to tell Emacs where different paths are. | |||
16 | 20 | ||
17 | (let ((win-downloads "c:/Users/aduckworth/Downloads")) | 21 | (let ((win-downloads "c:/Users/aduckworth/Downloads")) |
18 | (dolist (path (list | 22 | (dolist (path (list |
19 | ;; Linux | 23 | ;; Linux |
20 | (expand-file-name "bin" | 24 | (expand-file-name "bin" |
21 | user-emacs-directory) | 25 | user-emacs-directory) |
22 | (expand-file-name "~/bin") | 26 | (expand-file-name "~/bin") |
23 | (expand-file-name "~/.local/bin") | 27 | (expand-file-name "~/.local/bin") |
24 | (expand-file-name "~/Scripts") | 28 | (expand-file-name "~/Scripts") |
25 | ;; Windows | 29 | ;; Windows |
26 | (expand-file-name "emacs/bin" | 30 | (expand-file-name "emacs/bin" |
27 | win-downloads) | 31 | win-downloads) |
28 | (expand-file-name "m/usr/bin" | 32 | (expand-file-name "m/usr/bin" |
29 | win-downloads) | 33 | win-downloads) |
30 | (expand-file-name "m/mingw64/bin" | 34 | (expand-file-name "m/mingw64/bin" |
31 | win-downloads) | 35 | win-downloads) |
32 | (expand-file-name "PortableGit/bin" | 36 | (expand-file-name "PortableGit/bin" |
33 | win-downloads) | 37 | win-downloads) |
34 | (expand-file-name "PortableGit/usr/bin" | 38 | (expand-file-name "PortableGit/usr/bin" |
35 | win-downloads))) | 39 | win-downloads))) |
36 | (when (file-exists-p path) | 40 | (when (file-exists-p path) |
37 | (add-to-list 'exec-path path)))) | 41 | (add-to-list 'exec-path path)))) |
38 | 42 | ||
39 | 43 | ||
40 | ## Package management | 44 | ## Package management |
@@ -49,21 +53,21 @@ bootstrap code from straight's repo in a function. | |||
49 | "Bootstrap straight.el." | 53 | "Bootstrap straight.el." |
50 | (defvar bootstrap-version) | 54 | (defvar bootstrap-version) |
51 | (let ((bootstrap-file | 55 | (let ((bootstrap-file |
52 | (expand-file-name | 56 | (expand-file-name |
53 | "straight/repos/straight.el/bootstrap.el" | 57 | "straight/repos/straight.el/bootstrap.el" |
54 | user-emacs-directory)) | 58 | user-emacs-directory)) |
55 | (bootstrap-version 5)) | 59 | (bootstrap-version 5)) |
56 | (unless (file-exists-p bootstrap-file) | 60 | (unless (file-exists-p bootstrap-file) |
57 | (with-current-buffer | 61 | (with-current-buffer |
58 | (url-retrieve-synchronously | 62 | (url-retrieve-synchronously |
59 | (concat | 63 | (concat |
60 | "https://raw.githubusercontent.com/" | 64 | "https://raw.githubusercontent.com/" |
61 | "raxod502/straight.el/" | 65 | "raxod502/straight.el/" |
62 | "develop/install.el") | 66 | "develop/install.el") |
63 | 'silent 'inhibit-cookies) | 67 | 'silent 'inhibit-cookies) |
64 | (goto-char (point-max)) | 68 | (goto-char (point-max)) |
65 | (eval-print-last-sexp))) | 69 | (eval-print-last-sexp))) |
66 | (load bootstrap-file nil 'nomessage))) | 70 | (load bootstrap-file nil 'nomessage))) |
67 | 71 | ||
68 | Now, I'll *try* running it regular-style, ignoring the errors. If it | 72 | Now, I'll *try* running it regular-style, ignoring the errors. If it |
69 | doesn't work, I'll call git directly and clone the repo myself. | 73 | doesn't work, I'll call git directly and clone the repo myself. |
@@ -71,15 +75,15 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
71 | (unless (ignore-errors (acdw/bootstrap-straight)) | 75 | (unless (ignore-errors (acdw/bootstrap-straight)) |
72 | (message "%s" "Straight.el didn't bootstrap correctly. Cloning directly...") | 76 | (message "%s" "Straight.el didn't bootstrap correctly. Cloning directly...") |
73 | (call-process "git" nil | 77 | (call-process "git" nil |
74 | (get-buffer-create "*bootstrap-straight-messages*") nil | 78 | (get-buffer-create "*bootstrap-straight-messages*") nil |
75 | "clone" | 79 | "clone" |
76 | "https://github.com/raxod502/straight.el" | 80 | "https://github.com/raxod502/straight.el" |
77 | (expand-file-name "straight/repos/straight.el" | 81 | (expand-file-name "straight/repos/straight.el" |
78 | user-emacs-directory)) | 82 | user-emacs-directory)) |
79 | (acdw/bootstrap-straight)) | 83 | (acdw/bootstrap-straight)) |
80 | 84 | ||
81 | 85 | ||
82 | ## Customize macros | 86 | ## Ease-of-configuring functions |
83 | 87 | ||
84 | 88 | ||
85 | ### Emulate use-package’s `:custom` | 89 | ### Emulate use-package’s `:custom` |
@@ -87,9 +91,9 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
87 | (defmacro cuss (var val &optional docstring) | 91 | (defmacro cuss (var val &optional docstring) |
88 | "Basically, `:custom' from `use-package', but without `use-package'." | 92 | "Basically, `:custom' from `use-package', but without `use-package'." |
89 | (declare (doc-string 3) | 93 | (declare (doc-string 3) |
90 | (indent 2)) | 94 | (indent 2)) |
91 | `(funcall (or (get ',var 'custom-set) #'set-default) | 95 | `(funcall (or (get ',var 'custom-set) #'set-default) |
92 | ',var ,val)) | 96 | ',var ,val)) |
93 | 97 | ||
94 | 98 | ||
95 | ### Emulate use-package’s `:custom-face`, but better | 99 | ### Emulate use-package’s `:custom-face`, but better |
@@ -109,6 +113,16 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
109 | (add-hook 'after-init-hook #'acdw/set-custom-faces)) | 113 | (add-hook 'after-init-hook #'acdw/set-custom-faces)) |
110 | 114 | ||
111 | 115 | ||
116 | ### Determine whether any Emacs frame is focused or not | ||
117 | |||
118 | This comes in handy when I want to garbage collect, say, or save recent files. | ||
119 | |||
120 | (defun acdw/when-unfocused (func &rest args) | ||
121 | "Run FUNC with ARGS only if all frames are out of focus." | ||
122 | (if (seq-every-p #'null (mapcar #'frame-focus-state (frame-list))) | ||
123 | (apply func args))) | ||
124 | |||
125 | |||
112 | ## Clean `.emacs.d` | 126 | ## Clean `.emacs.d` |
113 | 127 | ||
114 | (straight-use-package 'no-littering) | 128 | (straight-use-package 'no-littering) |
@@ -140,25 +154,13 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
140 | 154 | ||
141 | 1. Tool bars and menu bars | 155 | 1. Tool bars and menu bars |
142 | 156 | ||
143 | (cuss default-frame-alist | 157 | (menu-bar-mode -1) |
144 | '((tool-bar-lines . 0) | 158 | (tool-bar-mode -1) |
145 | (menu-bar-lines .0)) | ||
146 | "Setup the default frame alist.") | ||
147 | |||
148 | (menu-bar-mode -1) | ||
149 | (tool-bar-mode -1) | ||
150 | 159 | ||
151 | 2. Scroll bars | 160 | 2. Scroll bars |
152 | 161 | ||
153 | (add-to-list 'default-frame-alist | 162 | (scroll-bar-mode -1) |
154 | '(vertical-scroll-bars . nil)) | 163 | (horizontal-scroll-bar-mode -1) |
155 | |||
156 | (scroll-bar-mode -1) | ||
157 | |||
158 | (add-to-list 'default-frame-alist | ||
159 | '(horizontal-scroll-bars . nil)) | ||
160 | |||
161 | (horizontal-scroll-bar-mode -1) | ||
162 | 164 | ||
163 | 165 | ||
164 | ### Dialogs | 166 | ### Dialogs |
@@ -168,94 +170,130 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
168 | 170 | ||
169 | 1. Yes or no questions | 171 | 1. Yes or no questions |
170 | 172 | ||
171 | (fset 'yes-or-no-p #'y-or-n-p) | 173 | (fset 'yes-or-no-p #'y-or-n-p) |
172 | 174 | ||
173 | 2. The Bell | 175 | 2. The Bell |
174 | 176 | ||
175 | (defun acdw/ring-bell-function () | 177 | from [EmacsWiki](https://www.emacswiki.org/emacs/AlarmBell#h5o-3). |
176 | "Ring the bell." | 178 | |
177 | (let ((orig-face (face-foreground 'mode-line))) | 179 | (setq visible-bell nil |
178 | (set-face-foreground 'mode-line "#F2804F") | 180 | ring-bell-function 'flash-mode-line) |
179 | (run-with-idle-timer | ||
180 | 0.1 nil | ||
181 | (lambda (fg) | ||
182 | (set-face-foreground 'mode-line fg)) | ||
183 | orig-face))) | ||
184 | 181 | ||
185 | (cuss ring-bell-function #'acdw/ring-bell-function) | 182 | (defun flash-mode-line () |
183 | (invert-face 'mode-line) | ||
184 | (run-with-timer 0.1 nil #'invert-face 'mode-line)) | ||
186 | 185 | ||
187 | 186 | ||
188 | ### Frames | 187 | ### Frames |
189 | 188 | ||
190 | 1. Fringes | 189 | 1. Fringes |
191 | 190 | ||
192 | (cuss indicate-empty-lines t | 191 | (cuss indicate-empty-lines t |
193 | "Show an indicator on the left fringe of empty lines past the | 192 | "Show an indicator on the left fringe of empty lines past the |
194 | end of the buffer.") | 193 | end of the buffer.") |
195 | (cuss indicate-buffer-boundaries 'right | 194 | (cuss indicate-buffer-boundaries 'right |
196 | "Indicate the beginning and end of the buffer and whether it | 195 | "Indicate the beginning and end of the buffer and whether it |
197 | scrolls off-window in the right fringe.") | 196 | scrolls off-window in the right fringe.") |
198 | 197 | ||
199 | 2. Minibuffer | 198 | 2. Minibuffer |
200 | 199 | ||
201 | (cuss minibuffer-prompt-properties | 200 | (cuss minibuffer-prompt-properties |
202 | '(read-only t cursor-intangible t face minibuffer-prompt) | 201 | '(read-only t cursor-intangible t face minibuffer-prompt) |
203 | "Keep the cursor away from the minibuffer prompt.") | 202 | "Keep the cursor away from the minibuffer prompt.") |
204 | 203 | ||
205 | 3. Tabs | 204 | 3. Tabs |
206 | 205 | ||
207 | (cuss tab-bar-tab-name-function | 206 | (cuss tab-bar-tab-name-function |
208 | #'tab-bar-tab-name-current-with-count | 207 | #'tab-bar-tab-name-current-with-count |
209 | "Show the tab name as the name of the current buffer, plus a | 208 | "Show the tab name as the name of the current buffer, plus a |
210 | count of the windows in the tab.") | 209 | count of the windows in the tab.") |
211 | 210 | ||
212 | (cuss tab-bar-show 1 | 211 | (cuss tab-bar-show 1 |
213 | "Show the tab bar, when there's more than one tab.") | 212 | "Show the tab bar, when there's more than one tab.") |
214 | 213 | ||
215 | 214 | ||
216 | ### Windows | 215 | ### Windows |
217 | 216 | ||
218 | 1. Winner mode | 217 | 1. Winner mode |
219 | 218 | ||
220 | (when (fboundp 'winner-mode) | 219 | (when (fboundp 'winner-mode) |
221 | (winner-mode +1)) | 220 | (winner-mode +1)) |
222 | 221 | ||
223 | 2. Switch windows | 222 | 2. Switch windows |
224 | 223 | ||
225 | (global-set-key (kbd "M-o") #'other-window) | 224 | (global-set-key (kbd "M-o") #'other-window) |
226 | 225 | ||
227 | 226 | ||
228 | ### Buffers | 227 | ### Buffers |
229 | 228 | ||
230 | 1. Uniquify buffers | 229 | 1. Uniquify buffers |
231 | 230 | ||
232 | (require 'uniquify) | 231 | (require 'uniquify) |
233 | (cuss uniquify-buffer-name-style 'forward | 232 | (cuss uniquify-buffer-name-style 'forward |
234 | "Uniquify buffers' names by going up the path trees until they | 233 | "Uniquify buffers' names by going up the path trees until they |
235 | become unique.") | 234 | become unique.") |
236 | 235 | ||
237 | 2. Startup buffers | 236 | 2. Startup buffers |
238 | 237 | ||
239 | (cuss inhibit-startup-screen t | 238 | (cuss inhibit-startup-screen t |
240 | "Don't show Emacs' startup buffer.") | 239 | "Don't show Emacs' startup buffer.") |
241 | 240 | ||
242 | (cuss initial-buffer-choice t | 241 | (cuss initial-buffer-choice t |
243 | "Start with *scratch*.") | 242 | "Start with *scratch*.") |
244 | 243 | ||
245 | (cuss initial-scratch-message "" | 244 | (cuss initial-scratch-message "" |
246 | "Empty *scratch* buffer.") | 245 | "Empty *scratch* buffer.") |
246 | |||
247 | 3. Kill the current buffer | ||
248 | |||
249 | (defun acdw/kill-a-buffer (&optional prefix) | ||
250 | "Kill a buffer based on the following rules: | ||
251 | |||
252 | C-x k ⇒ Kill current buffer & window | ||
253 | C-u C-x k ⇒ Kill OTHER window and its buffer | ||
254 | C-u C-u C-x C-k ⇒ Kill all other buffers and windows | ||
255 | |||
256 | Prompt only if there are unsaved changes." | ||
257 | (interactive "P") | ||
258 | (pcase (or (car prefix) 0) | ||
259 | ;; C-x k ⇒ Kill current buffer & window | ||
260 | (0 (kill-current-buffer) | ||
261 | (unless (one-window-p) (delete-window))) | ||
262 | ;; C-u C-x k ⇒ Kill OTHER window and its buffer | ||
263 | (4 (other-window 1) | ||
264 | (kill-current-buffer) | ||
265 | (unless (one-window-p) (delete-window))) | ||
266 | ;; C-u C-u C-x C-k ⇒ Kill all other buffers and windows | ||
267 | (16 (mapc 'kill-buffer (delq (current-buffer) (buffer-list))) | ||
268 | (delete-other-windows)))) | ||
269 | |||
270 | (define-key ctl-x-map "k" #'acdw/kill-a-buffer) | ||
271 | |||
272 | 1. Remap `C-x M-k` to bring up the buffer-killing menu | ||
273 | |||
274 | (define-key ctl-x-map (kbd "M-k") #'kill-buffer) | ||
275 | |||
276 | 4. Immortal `*scratch*` buffer | ||
277 | |||
278 | (defun immortal-scratch () | ||
279 | (if (eq (current-buffer) (get-buffer "*scratch*")) | ||
280 | (progn (bury-buffer) | ||
281 | nil) | ||
282 | t)) | ||
283 | |||
284 | (add-hook 'kill-buffer-query-functions 'immortal-scratch) | ||
247 | 285 | ||
248 | 286 | ||
249 | ### Modeline | 287 | ### Modeline |
250 | 288 | ||
251 | 1. Smart mode line | 289 | 1. Smart mode line |
252 | 290 | ||
253 | (straight-use-package 'smart-mode-line) | 291 | (straight-use-package 'smart-mode-line) |
254 | 292 | ||
255 | (cuss sml/no-confirm-load-theme t | 293 | (cuss sml/no-confirm-load-theme t |
256 | "Pass the NO-CONFIRM flag to `load-theme'.") | 294 | "Pass the NO-CONFIRM flag to `load-theme'.") |
257 | 295 | ||
258 | (sml/setup) | 296 | (sml/setup) |
259 | 297 | ||
260 | 2. Rich minority | 298 | 2. Rich minority |
261 | 299 | ||
@@ -263,112 +301,129 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
263 | instead of `diminish` or another package. I do have to write this | 301 | instead of `diminish` or another package. I do have to write this |
264 | helper function, though, to add things to the whitelist. | 302 | helper function, though, to add things to the whitelist. |
265 | 303 | ||
266 | (defun rm/whitelist-add (regexp) | 304 | (defun rm/whitelist-add (regexp) |
267 | "Add a REGEXP to the whitelist for `rich-minority'." | 305 | "Add a REGEXP to the whitelist for `rich-minority'." |
268 | (if (listp 'rm--whitelist-regexps) | 306 | (if (listp 'rm--whitelist-regexps) |
269 | (add-to-list 'rm--whitelist-regexps regexp) | 307 | (add-to-list 'rm--whitelist-regexps regexp) |
270 | (setq rm--whitelist-regexps `(,regexp))) | 308 | (setq rm--whitelist-regexps `(,regexp))) |
271 | (setq rm-whitelist | 309 | (setq rm-whitelist |
272 | (mapconcat 'identity rm--whitelist-regexps "\\|"))) | 310 | (mapconcat 'identity rm--whitelist-regexps "\\|"))) |
273 | 311 | ||
274 | (straight-use-package 'rich-minority) | 312 | (straight-use-package 'rich-minority) |
275 | 313 | ||
276 | (rm/whitelist-add "^$") | 314 | (rm/whitelist-add "^$") |
277 | 315 | ||
278 | 316 | ||
279 | ### Theme | 317 | ### Theme |
280 | 318 | ||
281 | 1. Modus Themes | 319 | 1. Modus Themes |
282 | 320 | ||
283 | (straight-use-package 'modus-themes) | 321 | (straight-use-package 'modus-themes) |
322 | |||
323 | (cuss modus-themes-slanted-constructs t | ||
324 | "Use more slanted constructs.") | ||
325 | (cuss modus-themes-bold-constructs t | ||
326 | "Use more bold constructs.") | ||
284 | 327 | ||
285 | (cuss modus-themes-slanted-constructs t | 328 | (cuss modus-themes-region 'bg-only |
286 | "Use more slanted constructs.") | 329 | "Only highlight the background of the selected region.") |
287 | (cuss modus-themes-bold-constructs t | ||
288 | "Use more bold constructs.") | ||
289 | 330 | ||
290 | (cuss modus-themes-region 'bg-only | 331 | (cuss modus-themes-org-blocks 'grayscale |
291 | "Only highlight the background of the selected region.") | 332 | "Show org-blocks with a grayscale background.") |
333 | (cuss modus-themes-headings | ||
334 | '((1 . line) | ||
335 | (t . t)) | ||
336 | "Highlight top headings with `line' style, and others by default.") | ||
292 | 337 | ||
293 | (cuss modus-themes-org-blocks 'grayscale | 338 | (cuss modus-themes-scale-headings t |
294 | "Show org-blocks with a grayscale background.") | 339 | "Scale headings by the ratios below.") |
295 | (cuss modus-themes-headings | 340 | (cuss modus-themes-scale-1 1.1) |
296 | '((1 . line) | 341 | (cuss modus-themes-scale-2 1.15) |
297 | (t . t)) | 342 | (cuss modus-themes-scale-3 1.21) |
298 | "Highlight top headings with `line' style, and others by default.") | 343 | (cuss modus-themes-scale-4 1.27) |
344 | (cuss modus-themes-scale-5 1.33) | ||
299 | 345 | ||
300 | (cuss modus-themes-scale-headings t | 346 | (load-theme 'modus-operandi t) |
301 | "Scale headings by the ratios below.") | 347 | |
302 | (cuss modus-themes-scale-1 1.1) | 348 | 2. Change themes based on time of day |
303 | (cuss modus-themes-scale-2 1.15) | 349 | |
304 | (cuss modus-themes-scale-3 1.21) | 350 | (cuss calendar-latitude 30.4515) |
305 | (cuss modus-themes-scale-4 1.27) | 351 | (cuss calendar-longitude -91.1871) |
306 | (cuss modus-themes-scale-5 1.33) | 352 | |
353 | ;; sunrise | ||
354 | (run-at-time (nth 1 (split-string (sunrise-sunset))) | ||
355 | (* 60 60 24) | ||
356 | (lambda () | ||
357 | (modus-themes-load-operandi))) | ||
307 | 358 | ||
308 | (load-theme 'modus-operandi t) | 359 | ;; sunset |
360 | (run-at-time (nth 4 (split-string (sunrise-sunset))) | ||
361 | (* 60 60 24) | ||
362 | (lambda () | ||
363 | (modus-themes-load-vivendi))) | ||
309 | 364 | ||
310 | 365 | ||
311 | ### Fonts | 366 | ### Fonts |
312 | 367 | ||
313 | 1. Define fonts | 368 | 1. Define fonts |
314 | 369 | ||
315 | (defun set-face-from-alternatives (face fonts) | 370 | (defun set-face-from-alternatives (face fonts) |
316 | (catch :return | 371 | (catch :return |
317 | (dolist (font fonts) | 372 | (dolist (font fonts) |
318 | (when (find-font (font-spec :family (car font))) | 373 | (when (find-font (font-spec :family (car font))) |
319 | (apply #'set-face-attribute `(,face | 374 | (apply #'set-face-attribute `(,face |
320 | nil | 375 | nil |
321 | :family (car font) | 376 | :family (car font) |
322 | ,@(cdr font))) | 377 | ,@(cdr font))) |
323 | (throw :return font))))) | 378 | (throw :return font))))) |
324 | 379 | ||
325 | (defun acdw/setup-fonts () | 380 | (defun acdw/setup-fonts () |
326 | "Setup fonts. This has to happen after the frame is setup for | 381 | "Setup fonts. This has to happen after the frame is setup for |
327 | the first time, so it should be added to `window-setup-hook'. It | 382 | the first time, so it should be added to `window-setup-hook'. It |
328 | removes itself from that hook." | 383 | removes itself from that hook." |
329 | (interactive) | 384 | (interactive) |
330 | (when (display-graphic-p) | 385 | (when (display-graphic-p) |
331 | (set-face-from-alternatives 'default | 386 | (set-face-from-alternatives 'default |
332 | '(("Input Mono" | 387 | '(("Input Mono" |
333 | :height 105) | 388 | :height 105) |
334 | ("Go Mono" | 389 | ("Go Mono" |
335 | :height 100) | 390 | :height 100) |
336 | ("Consolas" | 391 | ("Consolas" |
337 | :height 100))) | 392 | :height 100))) |
338 | 393 | ||
339 | (set-face-from-alternatives 'fixed-pitch | 394 | (set-face-from-alternatives 'fixed-pitch |
340 | '(("Input Mono") | 395 | '(("Input Mono") |
341 | ("Go Mono") | 396 | ("Go Mono") |
342 | ("Consolas"))) | 397 | ("Consolas"))) |
343 | 398 | ||
344 | (set-face-from-alternatives 'variable-pitch | 399 | (set-face-from-alternatives 'variable-pitch |
345 | '(("Input Serif") | 400 | '(("Input Serif") |
346 | ("Georgia"))) | 401 | ("Georgia"))) |
347 | 402 | ||
348 | (remove-function after-focus-change-function #'acdw/setup-fonts))) | 403 | (remove-function after-focus-change-function #'acdw/setup-fonts))) |
349 | 404 | ||
350 | (add-function :before after-focus-change-function #'acdw/setup-fonts) | 405 | (add-function :before after-focus-change-function #'acdw/setup-fonts) |
351 | 406 | ||
352 | 2. Custom faces | 407 | 2. Custom faces |
353 | 408 | ||
354 | (cussface '(font-lock-comment-face | 409 | (cussface '(font-lock-comment-face |
355 | ((t (:inherit (custom-comment italic variable-pitch)))))) | 410 | ((t (:inherit (custom-comment italic variable-pitch)))))) |
356 | 411 | ||
357 | 3. Line spacing | 412 | 3. Line spacing |
358 | 413 | ||
359 | (cuss line-spacing 0.1 | 414 | (cuss line-spacing 0.1 |
360 | "Add 10% extra space below each line.") | 415 | "Add 10% extra space below each line.") |
361 | 416 | ||
362 | 4. Underlines | 417 | 4. Underlines |
363 | 418 | ||
364 | (cuss x-underline-at-descent-line t | 419 | (cuss x-underline-at-descent-line t |
365 | "Draw the underline at the same place as the descent line.") | 420 | "Draw the underline at the same place as the descent line.") |
366 | 421 | ||
367 | 5. Unicode Fonts | 422 | 5. Unicode Fonts |
368 | 423 | ||
369 | (straight-use-package 'unicode-fonts) | 424 | (straight-use-package 'unicode-fonts) |
370 | (require 'unicode-fonts) | 425 | (require 'unicode-fonts) |
371 | (unicode-fonts-setup) | 426 | (unicode-fonts-setup) |
372 | 427 | ||
373 | 428 | ||
374 | ## Interactivity | 429 | ## Interactivity |
@@ -378,81 +433,81 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
378 | 433 | ||
379 | 1. Shadow file names in `completing-read`. | 434 | 1. Shadow file names in `completing-read`. |
380 | 435 | ||
381 | (cuss file-name-shadow-properties '(invisible t)) | 436 | (cuss file-name-shadow-properties '(invisible t)) |
382 | 437 | ||
383 | (file-name-shadow-mode +1) | 438 | (file-name-shadow-mode +1) |
384 | 439 | ||
385 | 2. Ignore case in `completing-read` | 440 | 2. Ignore case in `completing-read` |
386 | 441 | ||
387 | (cuss completion-ignore-case t) | 442 | (cuss completion-ignore-case t) |
388 | (cuss read-buffer-completion-ignore-case t) | 443 | (cuss read-buffer-completion-ignore-case t) |
389 | (cuss read-file-name-completion-ignore-case t) | 444 | (cuss read-file-name-completion-ignore-case t) |
390 | 445 | ||
391 | 3. Minibuffer recursivity | 446 | 3. Minibuffer recursivity |
392 | 447 | ||
393 | (cuss enable-recursive-minibuffers t) | 448 | (cuss enable-recursive-minibuffers t) |
394 | (minibuffer-depth-indicate-mode +1) | 449 | (minibuffer-depth-indicate-mode +1) |
395 | 450 | ||
396 | 4. Selectrum | 451 | 4. Selectrum |
397 | 452 | ||
398 | (straight-use-package 'selectrum) | 453 | (straight-use-package 'selectrum) |
399 | (require 'selectrum) | 454 | (require 'selectrum) |
400 | (selectrum-mode +1) | 455 | (selectrum-mode +1) |
401 | 456 | ||
402 | 5. Prescient | 457 | 5. Prescient |
403 | 458 | ||
404 | (straight-use-package 'prescient) | 459 | (straight-use-package 'prescient) |
405 | (require 'prescient) | 460 | (require 'prescient) |
406 | (prescient-persist-mode +1) | 461 | (prescient-persist-mode +1) |
407 | 462 | ||
408 | (straight-use-package 'selectrum-prescient) | 463 | (straight-use-package 'selectrum-prescient) |
409 | (require 'selectrum-prescient) | 464 | (require 'selectrum-prescient) |
410 | (selectrum-prescient-mode +1) | 465 | (selectrum-prescient-mode +1) |
411 | 466 | ||
412 | 6. Consult | 467 | 6. Consult |
413 | 468 | ||
414 | (straight-use-package '(consult | 469 | (straight-use-package '(consult |
415 | :host github | 470 | :host github |
416 | :repo "minad/consult")) | 471 | :repo "minad/consult")) |
417 | (require 'consult) | 472 | (require 'consult) |
418 | 473 | ||
419 | (straight-use-package '(consult-selectrum | 474 | (straight-use-package '(consult-selectrum |
420 | :host github | 475 | :host github |
421 | :repo "minad/consult")) | 476 | :repo "minad/consult")) |
422 | (require 'consult-selectrum) | 477 | (require 'consult-selectrum) |
423 | 478 | ||
424 | (with-eval-after-load 'consult | 479 | (with-eval-after-load 'consult |
425 | (define-key ctl-x-map "b" #'consult-buffer) | 480 | (define-key ctl-x-map "b" #'consult-buffer) |
426 | (define-key ctl-x-map (kbd "C-r") #'consult-buffer) | 481 | (define-key ctl-x-map (kbd "C-r") #'consult-buffer) |
427 | (define-key ctl-x-map "4b" #'consult-buffer-other-window) | 482 | (define-key ctl-x-map "4b" #'consult-buffer-other-window) |
428 | (define-key ctl-x-map "5b" #'consult-buffer-other-frame) | 483 | (define-key ctl-x-map "5b" #'consult-buffer-other-frame) |
429 | 484 | ||
430 | (define-key goto-map "o" #'consult-outline) | 485 | (define-key goto-map "o" #'consult-outline) |
431 | (define-key goto-map "g" #'consult-line) | 486 | (define-key goto-map "g" #'consult-line) |
432 | (define-key goto-map (kbd "M-g") #'consult-line) | 487 | (define-key goto-map (kbd "M-g") #'consult-line) |
433 | (define-key goto-map "l" #'consult-line) | 488 | (define-key goto-map "l" #'consult-line) |
434 | (define-key goto-map "m" #'consult-mark) | 489 | (define-key goto-map "m" #'consult-mark) |
435 | (define-key goto-map "i" #'consult-imenu) | 490 | (define-key goto-map "i" #'consult-imenu) |
436 | (define-key goto-map "e" #'consult-error) | 491 | (define-key goto-map "e" #'consult-error) |
437 | 492 | ||
438 | (global-set-key (kbd "M-y") #'consult-yank-pop) | 493 | (global-set-key (kbd "M-y") #'consult-yank-pop) |
439 | 494 | ||
440 | (define-key help-map "a" #'consult-apropos) | 495 | (define-key help-map "a" #'consult-apropos) |
441 | 496 | ||
442 | (fset 'multi-occur #'consult-multi-occur)) | 497 | (fset 'multi-occur #'consult-multi-occur)) |
443 | 498 | ||
444 | 7. Marginalia | 499 | 7. Marginalia |
445 | 500 | ||
446 | (straight-use-package '(marginalia | 501 | (straight-use-package '(marginalia |
447 | :host github | 502 | :host github |
448 | :repo "minad/marginalia" | 503 | :repo "minad/marginalia" |
449 | :branch "main")) | 504 | :branch "main")) |
450 | 505 | ||
451 | (cuss marginalia-annotators | 506 | (cuss marginalia-annotators |
452 | '(marginalia-annotators-heavy | 507 | '(marginalia-annotators-heavy |
453 | marginalia-annotators-light)) | 508 | marginalia-annotators-light)) |
454 | 509 | ||
455 | (marginalia-mode +1) | 510 | (marginalia-mode +1) |
456 | 511 | ||
457 | 512 | ||
458 | ### Completion | 513 | ### Completion |
@@ -460,6 +515,20 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
460 | (global-set-key (kbd "M-/") #'hippie-expand) | 515 | (global-set-key (kbd "M-/") #'hippie-expand) |
461 | 516 | ||
462 | 517 | ||
518 | ### Garbage collection | ||
519 | |||
520 | (straight-use-package 'gcmh) | ||
521 | (gcmh-mode +1) | ||
522 | |||
523 | (defun dotfiles--gc-on-last-frame-out-of-focus () | ||
524 | "GC if all frames are inactive." | ||
525 | (if (seq-every-p #'null (mapcar #'frame-focus-state (frame-list))) | ||
526 | (garbage-collect))) | ||
527 | |||
528 | (add-function :after after-focus-change-function | ||
529 | #'dotfiles--gc-on-last-frame-out-of-focus) | ||
530 | |||
531 | |||
463 | ## Keyboard | 532 | ## Keyboard |
464 | 533 | ||
465 | 534 | ||
@@ -472,15 +541,21 @@ doesn't work, I'll call git directly and clone the repo myself. | |||
472 | 541 | ||
473 | (defvar acdw/map | 542 | (defvar acdw/map |
474 | (let ((map (make-sparse-keymap)) | 543 | (let ((map (make-sparse-keymap)) |
475 | (c-z (global-key-binding "\C-z"))) | 544 | (c-z (global-key-binding "\C-z"))) |
476 | (global-unset-key "\C-z") | 545 | (global-unset-key "\C-z") |
477 | (define-key global-map "\C-z" map) | 546 | (define-key global-map "\C-z" map) |
478 | (define-key map "\C-z" c-z) | 547 | (define-key map "\C-z" c-z) |
479 | map)) | 548 | map)) |
480 | 549 | ||
481 | (run-hooks 'acdw/map-defined-hook) | 550 | (run-hooks 'acdw/map-defined-hook) |
482 | 551 | ||
483 | 552 | ||
553 | ### Show keybindings | ||
554 | |||
555 | (straight-use-package 'which-key) | ||
556 | (which-key-mode +1) | ||
557 | |||
558 | |||
484 | ## Mouse | 559 | ## Mouse |
485 | 560 | ||
486 | 561 | ||
@@ -494,7 +569,7 @@ from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_ti | |||
494 | "Like `mwheel-scroll' but preserve screen position. | 569 | "Like `mwheel-scroll' but preserve screen position. |
495 | See `scroll-preserve-screen-position'." | 570 | See `scroll-preserve-screen-position'." |
496 | (let ((scroll-preserve-screen-position :always)) | 571 | (let ((scroll-preserve-screen-position :always)) |
497 | (apply original arguments))) | 572 | (apply original arguments))) |
498 | 573 | ||
499 | 574 | ||
500 | ## Persistence | 575 | ## Persistence |
@@ -505,9 +580,9 @@ from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_ti | |||
505 | (require 'savehist) | 580 | (require 'savehist) |
506 | 581 | ||
507 | (cuss savehist-additional-variables | 582 | (cuss savehist-additional-variables |
508 | '(kill-ring | 583 | '(kill-ring |
509 | search-ring | 584 | search-ring |
510 | regexp-search-ring) | 585 | regexp-search-ring) |
511 | "Other variables to save alongside the minibuffer history.") | 586 | "Other variables to save alongside the minibuffer history.") |
512 | 587 | ||
513 | (cuss history-length t | 588 | (cuss history-length t |
@@ -544,8 +619,20 @@ from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_ti | |||
544 | 619 | ||
545 | (recentf-mode +1) | 620 | (recentf-mode +1) |
546 | 621 | ||
547 | ;; save the recentf-list every 5 minutes | 622 | ;; save recentf list when focusing away |
548 | (run-at-time nil (* 5 60) 'recentf-save-list) | 623 | (defun acdw/maybe-save-recentf () |
624 | "Save `recentf-file' when out of focus, but only if we haven't | ||
625 | in five minutes." | ||
626 | (defvar recentf-last-save (time-convert nil 'integer) | ||
627 | "How long it's been since we last saved the recentf list.") | ||
628 | |||
629 | (when (> (time-convert (time-since recentf-last-save) 'integer) | ||
630 | (* 60 5)) | ||
631 | (setq recentf-last-save (time-convert nil 'integer)) | ||
632 | (acdw/when-unfocused #'recentf-save-list))) | ||
633 | |||
634 | (add-function :after after-focus-change-function | ||
635 | #'acdw/maybe-save-recentf) | ||
549 | 636 | ||
550 | 637 | ||
551 | ## Undo | 638 | ## Undo |
@@ -560,14 +647,14 @@ from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_ti | |||
560 | (require 'undo-fu-session) | 647 | (require 'undo-fu-session) |
561 | 648 | ||
562 | (cuss undo-fu-session-incompatible-files | 649 | (cuss undo-fu-session-incompatible-files |
563 | '("/COMMIT_EDITMSG\\'" | 650 | '("/COMMIT_EDITMSG\\'" |
564 | "/git-rebase-todo\\'") | 651 | "/git-rebase-todo\\'") |
565 | "A list of files that are incompatible with the concept of undo sessions.") | 652 | "A list of files that are incompatible with the concept of undo sessions.") |
566 | 653 | ||
567 | (with-eval-after-load 'no-littering | 654 | (with-eval-after-load 'no-littering |
568 | (let ((dir (no-littering-expand-var-file-name "undos"))) | 655 | (let ((dir (no-littering-expand-var-file-name "undos"))) |
569 | (make-directory dir 'parents) | 656 | (make-directory dir 'parents) |
570 | (cuss undo-fu-session-directory dir))) | 657 | (cuss undo-fu-session-directory dir))) |
571 | 658 | ||
572 | (global-undo-fu-session-mode +1) | 659 | (global-undo-fu-session-mode +1) |
573 | 660 | ||
@@ -579,30 +666,30 @@ from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_ti | |||
579 | 666 | ||
580 | 1. UTF-8 | 667 | 1. UTF-8 |
581 | 668 | ||
582 | (set-language-environment "UTF-8") | 669 | (set-language-environment "UTF-8") |
583 | (set-terminal-coding-system 'utf-8) | 670 | (set-terminal-coding-system 'utf-8) |
584 | (cuss locale-coding-system 'utf-8) | 671 | (cuss locale-coding-system 'utf-8) |
585 | (set-default-coding-systems 'utf-8) | 672 | (set-default-coding-systems 'utf-8) |
586 | (set-selection-coding-system 'utf-8) | 673 | (set-selection-coding-system 'utf-8) |
587 | (prefer-coding-system 'utf-8) | 674 | (prefer-coding-system 'utf-8) |
588 | 675 | ||
589 | 2. Convert all files to UNIX-style line endings | 676 | 2. Convert all files to UNIX-style line endings |
590 | 677 | ||
591 | from [Emacs Wiki](https://www.emacswiki.org/emacs/EndOfLineTips). | 678 | from [Emacs Wiki](https://www.emacswiki.org/emacs/EndOfLineTips). |
592 | 679 | ||
593 | (defun ewiki/no-junk-please-were-unixish () | 680 | (defun ewiki/no-junk-please-were-unixish () |
594 | "Convert line endings to UNIX, dammit." | 681 | "Convert line endings to UNIX, dammit." |
595 | (let ((coding-str (symbol-name buffer-file-coding-system))) | 682 | (let ((coding-str (symbol-name buffer-file-coding-system))) |
596 | (when (string-match "-\\(?:dos\\|mac\\)$" coding-str) | 683 | (when (string-match "-\\(?:dos\\|mac\\)$" coding-str) |
597 | (set-buffer-file-coding-system 'unix)))) | 684 | (set-buffer-file-coding-system 'unix)))) |
598 | 685 | ||
599 | I add it to the `find-file-hook` *and* `before-save-hook` because I | 686 | I add it to the `find-file-hook` *and* `before-save-hook` because I |
600 | don't want to ever work with anything other than UNIX line endings | 687 | don't want to ever work with anything other than UNIX line endings |
601 | ever again. I just don't care. Even Microsoft Notepad can handle | 688 | ever again. I just don't care. Even Microsoft Notepad can handle |
602 | UNIX line endings, so I don't want to hear it. | 689 | UNIX line endings, so I don't want to hear it. |
603 | 690 | ||
604 | (add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish) | 691 | (add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish) |
605 | (add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish) | 692 | (add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish) |
606 | 693 | ||
607 | 694 | ||
608 | ### Backups | 695 | ### Backups |
@@ -614,18 +701,18 @@ from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_ti | |||
614 | 701 | ||
615 | (with-eval-after-load 'no-littering | 702 | (with-eval-after-load 'no-littering |
616 | (let ((dir (no-littering-expand-var-file-name "backup"))) | 703 | (let ((dir (no-littering-expand-var-file-name "backup"))) |
617 | (make-directory dir 'parents) | 704 | (make-directory dir 'parents) |
618 | (cuss backup-directory-alist | 705 | (cuss backup-directory-alist |
619 | `((".*" . ,dir))))) | 706 | `((".*" . ,dir))))) |
620 | 707 | ||
621 | 708 | ||
622 | ### Auto-saves | 709 | ### Auto-saves |
623 | 710 | ||
624 | (with-eval-after-load 'no-littering | 711 | (with-eval-after-load 'no-littering |
625 | (let ((dir (no-littering-expand-var-file-name "autosaves"))) | 712 | (let ((dir (no-littering-expand-var-file-name "autosaves"))) |
626 | (make-directory dir 'parents) | 713 | (make-directory dir 'parents) |
627 | (cuss auto-save-file-name-transforms | 714 | (cuss auto-save-file-name-transforms |
628 | `((".*" ,dir t)))) | 715 | `((".*" ,dir t)))) |
629 | 716 | ||
630 | (auto-save-visited-mode +1)) | 717 | (auto-save-visited-mode +1)) |
631 | 718 | ||
@@ -663,41 +750,165 @@ from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_ti | |||
663 | 750 | ||
664 | 1. Replace selection when typing | 751 | 1. Replace selection when typing |
665 | 752 | ||
666 | (delete-selection-mode +1) | 753 | (delete-selection-mode +1) |
667 | 754 | ||
668 | 2. Work better with the system clipboard | 755 | 2. Work better with the system clipboard |
669 | 756 | ||
670 | (cuss save-interprogram-paste-before-kill t | 757 | (cuss save-interprogram-paste-before-kill t |
671 | "Save existing clipboard text into the kill ring before | 758 | "Save existing clipboard text into the kill ring before |
672 | replacing it.") | 759 | replacing it.") |
673 | 760 | ||
674 | (cuss yank-pop-change-selection t | 761 | (cuss yank-pop-change-selection t |
675 | "Update the X selection when rotating the kill ring.") | 762 | "Update the X selection when rotating the kill ring.") |
676 | 763 | ||
677 | 764 | ||
678 | ### Searching & Replacing | 765 | ### Searching & Replacing |
679 | 766 | ||
680 | 1. Replace with Anzu | 767 | 1. Replace with Anzu |
681 | 768 | ||
682 | (straight-use-package 'anzu) | 769 | (straight-use-package 'anzu) |
683 | (require 'anzu) | 770 | (require 'anzu) |
684 | 771 | ||
685 | ;; show search count in the modeline | 772 | ;; show search count in the modeline |
686 | (global-anzu-mode +1) | 773 | (global-anzu-mode +1) |
687 | 774 | ||
688 | (cuss anzu-replace-to-string-separator " → " | 775 | (cuss anzu-replace-to-string-separator " → " |
689 | "What to separate the search from the replacement.") | 776 | "What to separate the search from the replacement.") |
690 | 777 | ||
691 | (global-set-key [remap query-replace] #'anzu-query-replace) | 778 | (global-set-key [remap query-replace] #'anzu-query-replace) |
692 | (global-set-key [remap query-replace-regexp] #'anzu-query-replace-regexp) | 779 | (global-set-key [remap query-replace-regexp] #'anzu-query-replace-regexp) |
693 | 780 | ||
694 | (define-key isearch-mode-map [remap isearch-query-replace] #'anzu-isearch-query-replace) | 781 | (define-key isearch-mode-map [remap isearch-query-replace] #'anzu-isearch-query-replace) |
695 | (define-key isearch-mode-map [remap isearch-query-replace-regexp] #'anzu-isearch-query-replace-regexp) | 782 | (define-key isearch-mode-map [remap isearch-query-replace-regexp] #'anzu-isearch-query-replace-regexp) |
783 | |||
784 | |||
785 | ### Overwrite mode | ||
786 | |||
787 | (defun acdw/overwrite-mode-change-cursor () | ||
788 | (setq cursor-type (if overwrite-mode t 'bar))) | ||
789 | |||
790 | (add-hook 'overwrite-mode-hook #'acdw/overwrite-mode-change-cursor) | ||
791 | |||
792 | (rm/whitelist-add "Ovwrt") | ||
793 | |||
794 | |||
795 | ### The Mark | ||
796 | |||
797 | (cuss set-mark-repeat-command-pop t | ||
798 | "Repeat `set-mark-command' with a prefix argument, without | ||
799 | repeatedly entering the prefix argument.") | ||
800 | |||
801 | |||
802 | ### Whitespace | ||
803 | |||
804 | (cuss whitespace-style | ||
805 | '(empty ;; remove blank lines at the beginning and end of buffers | ||
806 | indentation ;; clean up indentation | ||
807 | space-before-tab ;; fix mixed spaces and tabs | ||
808 | space-after-tab)) | ||
809 | |||
810 | (add-hook 'before-save-hook #'whitespace-cleanup) | ||
696 | 811 | ||
697 | 812 | ||
698 | # Programming | 813 | # Programming |
699 | 814 | ||
700 | 815 | ||
816 | ## Prettify symbols | ||
817 | |||
818 | |||
819 | ### A bit from Rasmus | ||
820 | |||
821 | from [Rasmus Roulund](https://pank.eu/blog/pretty-babel-src-blocks.html#coderef-symbol), via [Musa Al-hassy](https://alhassy.github.io/emacs.d/index.html#Making-Block-Delimiters-Less-Intrusive). | ||
822 | |||
823 | (defvar-local rasmus/org-at-src-begin -1 | ||
824 | "Variable that holds whether last position was a ") | ||
825 | |||
826 | (defvar rasmus/ob-header-symbol ?☰ | ||
827 | "Symbol used for babel headers") | ||
828 | |||
829 | (defun rasmus/org-prettify-src--update () | ||
830 | (let ((case-fold-search t) | ||
831 | (re "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*") | ||
832 | found) | ||
833 | (save-excursion | ||
834 | (goto-char (point-min)) | ||
835 | (while (re-search-forward re nil t) | ||
836 | (goto-char (match-end 0)) | ||
837 | (let ((args (org-trim | ||
838 | (buffer-substring-no-properties (point) | ||
839 | (line-end-position))))) | ||
840 | (when (org-string-nw-p args) | ||
841 | (let ((new-cell (cons args rasmus/ob-header-symbol))) | ||
842 | (cl-pushnew new-cell prettify-symbols-alist :test #'equal) | ||
843 | (cl-pushnew new-cell found :test #'equal))))) | ||
844 | (setq prettify-symbols-alist | ||
845 | (cl-set-difference prettify-symbols-alist | ||
846 | (cl-set-difference | ||
847 | (cl-remove-if-not | ||
848 | (lambda (elm) | ||
849 | (eq (cdr elm) rasmus/ob-header-symbol)) | ||
850 | prettify-symbols-alist) | ||
851 | found :test #'equal))) | ||
852 | ;; Clean up old font-lock-keywords. | ||
853 | (font-lock-remove-keywords nil prettify-symbols--keywords) | ||
854 | (setq prettify-symbols--keywords (prettify-symbols--make-keywords)) | ||
855 | (font-lock-add-keywords nil prettify-symbols--keywords) | ||
856 | (while (re-search-forward re nil t) | ||
857 | (font-lock-flush (line-beginning-position) (line-end-position)))))) | ||
858 | |||
859 | (defun rasmus/org-prettify-src () | ||
860 | "Hide src options via `prettify-symbols-mode'. | ||
861 | |||
862 | `prettify-symbols-mode' is used because it has uncollpasing. It's | ||
863 | may not be efficient." | ||
864 | (let* ((case-fold-search t) | ||
865 | (at-src-block (save-excursion | ||
866 | (beginning-of-line) | ||
867 | (looking-at "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*")))) | ||
868 | ;; Test if we moved out of a block. | ||
869 | (when (or (and rasmus/org-at-src-begin | ||
870 | (not at-src-block)) | ||
871 | ;; File was just opened. | ||
872 | (eq rasmus/org-at-src-begin -1)) | ||
873 | (rasmus/org-prettify-src--update)) | ||
874 | ;; Remove composition if at line; doesn't work properly. | ||
875 | ;; (when at-src-block | ||
876 | ;; (with-silent-modifications | ||
877 | ;; (remove-text-properties (match-end 0) | ||
878 | ;; (1+ (line-end-position)) | ||
879 | ;; '(composition)))) | ||
880 | (setq rasmus/org-at-src-begin at-src-block))) | ||
881 | |||
882 | (defun rasmus/org-prettify-symbols () | ||
883 | (mapc (apply-partially 'add-to-list 'prettify-symbols-alist) | ||
884 | (cl-reduce 'append | ||
885 | (mapcar (lambda (x) (list x (cons (upcase (car x)) (cdr x)))) | ||
886 | `(("#+begin_src" . ?✎) ;; ➤ 🖝 ➟ ➤ ✎ | ||
887 | ("#+end_src" . ?⏹) ;; □ | ||
888 | ("#+header:" . ,rasmus/ob-header-symbol) | ||
889 | ("#+begin_quote" . ?») | ||
890 | ("#+end_quote" . ?«))))) | ||
891 | (turn-on-prettify-symbols-mode) | ||
892 | (add-hook 'post-command-hook 'rasmus/org-prettify-src t t)) | ||
893 | |||
894 | |||
895 | ### Regular prettify-symbols-mode | ||
896 | |||
897 | (cuss prettify-symbols-unprettify-at-point 'right-edge | ||
898 | "Unprettify a symbol when inside it or next to it.") | ||
899 | |||
900 | (defun acdw/org-mode-prettify () | ||
901 | "Prettify `org-mode'." | ||
902 | (append '(("[ ]" . ?□) ("[X]" . ?☑) ("[-]" . ?◐) | ||
903 | ("#begin_src" . ?🖬) ("#BEGIN_SRC" . ?🖬) | ||
904 | ("#end_src" . ?■) ("#END_SRC" . ?■)) | ||
905 | prettify-symbols-alist)) | ||
906 | |||
907 | (add-hook 'org-mode-hook #'acdw/org-mode-prettify) | ||
908 | |||
909 | (global-prettify-symbols-mode +1) | ||
910 | |||
911 | |||
701 | ## Parentheses | 912 | ## Parentheses |
702 | 913 | ||
703 | 914 | ||
@@ -747,46 +958,22 @@ from [u/TheFrenchPoulp](https://www.reddit.com/r/emacs/comments/km9by4/weekly_ti | |||
747 | 958 | ||
748 | This has to be done *before* loading the package. It's included in `visual-fill-column`, too, but for some reason isn't loaded there. | 959 | This has to be done *before* loading the package. It's included in `visual-fill-column`, too, but for some reason isn't loaded there. |
749 | 960 | ||
750 | (global-set-key [right-margin mouse-1] (global-key-binding [mouse-1])) ; #'mouse-set-point | 961 | (dolist (margin '(right-margin left-margin)) |
751 | (global-set-key [right-margin mouse-2] (global-key-binding [mouse-2])) ; #'mouse-yank-primary | 962 | (dolist (button '(mouse-1 mouse-2 mouse-3)) |
752 | (global-set-key [right-margin mouse-3] (global-key-binding [mouse-3])) ; #'mouse-save-then-kill | 963 | (global-set-key (vector margin button) |
753 | (global-set-key [right-margin drag-mouse-1] #'ignore) | 964 | (global-key-binding (vector button))))) |
754 | (global-set-key [right-margin drag-mouse-2] #'ignore) | ||
755 | (global-set-key [right-margin drag-mouse-3] #'ignore) | ||
756 | (global-set-key [right-margin double-mouse-1] #'ignore) | ||
757 | (global-set-key [right-margin double-mouse-2] #'ignore) | ||
758 | (global-set-key [right-margin double-mouse-3] #'ignore) | ||
759 | (global-set-key [right-margin triple-mouse-1] #'ignore) | ||
760 | (global-set-key [right-margin triple-mouse-2] #'ignore) | ||
761 | (global-set-key [right-margin triple-mouse-3] #'ignore) | ||
762 | (global-set-key [left-margin mouse-1] (global-key-binding [mouse-1])) ; #'mouse-set-point | ||
763 | (global-set-key [left-margin mouse-2] (global-key-binding [mouse-2])) ; #'mouse-yank-primary | ||
764 | (global-set-key [left-margin mouse-3] (global-key-binding [mouse-3])) ; #'mouse-save-then-kill | ||
765 | (global-set-key [left-margin drag-mouse-1] #'ignore) | ||
766 | (global-set-key [left-margin drag-mouse-2] #'ignore) | ||
767 | (global-set-key [left-margin drag-mouse-3] #'ignore) | ||
768 | (global-set-key [left-margin double-mouse-1] #'ignore) | ||
769 | (global-set-key [left-margin double-mouse-2] #'ignore) | ||
770 | (global-set-key [left-margin double-mouse-3] #'ignore) | ||
771 | (global-set-key [left-margin triple-mouse-1] #'ignore) | ||
772 | (global-set-key [left-margin triple-mouse-2] #'ignore) | ||
773 | (global-set-key [left-margin triple-mouse-3] #'ignore) | ||
774 | 965 | ||
775 | (mouse-wheel-mode +1) | 966 | (mouse-wheel-mode +1) |
776 | 967 | ||
777 | (when (bound-and-true-p mouse-wheel-mode) | 968 | (when (bound-and-true-p mouse-wheel-mode) |
778 | (global-set-key [right-margin mouse-wheel-down-event] #'mwheel-scroll) | 969 | (dolist (margin '(right-margin left-margin)) |
779 | (global-set-key [right-margin mouse-wheel-up-event] #'mwheel-scroll) | 970 | (dolist (event '(mouse-wheel-down-event |
780 | (global-set-key [right-margin wheel-down] #'mwheel-scroll) | 971 | mouse-wheel-up-event |
781 | (global-set-key [right-margin wheel-up] #'mwheel-scroll) | 972 | wheel-down |
782 | (global-set-key [left-margin mouse-wheel-down-event] #'mwheel-scroll) | 973 | wheel-up |
783 | (global-set-key [left-margin mouse-wheel-up-event] #'mwheel-scroll) | 974 | mouse-4 |
784 | (global-set-key [left-margin wheel-down] #'mwheel-scroll) | 975 | mouse-5)) |
785 | (global-set-key [left-margin wheel-up] #'mwheel-scroll) | 976 | (global-set-key (vector margin event) #'mwheel-scroll)))) |
786 | (global-set-key [right-margin mouse-4] #'mwheel-scroll) | ||
787 | (global-set-key [right-margin mouse-5] #'mwheel-scroll) | ||
788 | (global-set-key [left-margin mouse-4] #'mwheel-scroll) | ||
789 | (global-set-key [left-margin mouse-5] #'mwheel-scroll)) | ||
790 | 977 | ||
791 | 978 | ||
792 | ### Load the package | 979 | ### Load the package |
@@ -800,7 +987,7 @@ This has to be done *before* loading the package. It's included in `visual-fill | |||
800 | "Width of fill-column, and thus, visual-fill-column.") | 987 | "Width of fill-column, and thus, visual-fill-column.") |
801 | 988 | ||
802 | (advice-add 'text-scale-adjust | 989 | (advice-add 'text-scale-adjust |
803 | :after #'visual-fill-column-adjust) | 990 | :after #'visual-fill-column-adjust) |
804 | 991 | ||
805 | (global-visual-fill-column-mode +1) | 992 | (global-visual-fill-column-mode +1) |
806 | 993 | ||
@@ -818,11 +1005,43 @@ This has to be done *before* loading the package. It's included in `visual-fill | |||
818 | (straight-use-package 'typo) | 1005 | (straight-use-package 'typo) |
819 | 1006 | ||
820 | (add-hook 'text-mode-hook #'typo-mode) | 1007 | (add-hook 'text-mode-hook #'typo-mode) |
1008 | |||
1009 | ;; Disable `typo-mode' when inside an Org source block | ||
1010 | (with-eval-after-load 'typo | ||
1011 | (add-to-list 'typo-disable-electricity-functions | ||
1012 | #'org-in-src-block-p)) | ||
1013 | |||
1014 | |||
1015 | ## Word count | ||
1016 | |||
1017 | (straight-use-package 'wc-mode) | ||
1018 | |||
1019 | (add-hook 'text-mode-hook #'wc-mode) | ||
1020 | |||
1021 | (rm/whitelist-add "WC") | ||
821 | 1022 | ||
822 | 1023 | ||
823 | # Applications | 1024 | # Applications |
824 | 1025 | ||
825 | 1026 | ||
1027 | ## Dired | ||
1028 | |||
1029 | |||
1030 | ### Expand subtrees | ||
1031 | |||
1032 | (straight-use-package 'dired-subtree) | ||
1033 | |||
1034 | (with-eval-after-load 'dired | ||
1035 | (define-key dired-mode-map "i" #'dired-subtree-toggle)) | ||
1036 | |||
1037 | |||
1038 | ### Collapse singleton directories | ||
1039 | |||
1040 | (straight-use-package 'dired-collapse) | ||
1041 | |||
1042 | (add-hook 'dired-mode-hook #'dired-collapse-mode) | ||
1043 | |||
1044 | |||
826 | ## Org mode | 1045 | ## Org mode |
827 | 1046 | ||
828 | I’ve put org mode under Applications, as opposed to Writing, because it’s more generally-applicable than that. | 1047 | I’ve put org mode under Applications, as opposed to Writing, because it’s more generally-applicable than that. |
@@ -830,7 +1049,8 @@ I’ve put org mode under Applications, as opposed to Writing, because it’s m | |||
830 | 1049 | ||
831 | ### Basics | 1050 | ### Basics |
832 | 1051 | ||
833 | (straight-use-package 'org) | 1052 | (straight-use-package '(org |
1053 | :repo "https://code.orgmode.org/bzg/org-mode.git")) | ||
834 | 1054 | ||
835 | (with-eval-after-load 'org | 1055 | (with-eval-after-load 'org |
836 | (require 'org-tempo) | 1056 | (require 'org-tempo) |
@@ -849,194 +1069,205 @@ I’ve put org mode under Applications, as opposed to Writing, because it’s m | |||
849 | (cuss org-confirm-babel-evaluate nil) | 1069 | (cuss org-confirm-babel-evaluate nil) |
850 | (cuss org-directory "~/Org") | 1070 | (cuss org-directory "~/Org") |
851 | (cuss org-ellipsis "…") | 1071 | (cuss org-ellipsis "…") |
1072 | (cuss org-catch-invisible-edits 'show) | ||
852 | 1073 | ||
853 | 1. Tags | 1074 | 1. Tags |
854 | 1075 | ||
855 | (cuss org-tags-column 0 | 1076 | (cuss org-tags-column 0 |
856 | "Show tags directly after the headline. | 1077 | "Show tags directly after the headline. |
857 | This is the best-looking option with variable-pitch fonts.") | 1078 | This is the best-looking option with variable-pitch fonts.") |
858 | 1079 | ||
859 | (cussface | 1080 | (cussface |
860 | '(org-tag | 1081 | '(org-tag |
861 | ((t | 1082 | ((t |
862 | (:height 0.8 :weight normal :slant italic :foreground "grey40" :inherit | 1083 | (:height 0.8 :weight normal :slant italic :foreground "grey40" :inherit |
863 | (variable-pitch)))))) | 1084 | (variable-pitch)))))) |
864 | 1085 | ||
865 | 1086 | ||
866 | ### General | 1087 | ### General |
867 | 1088 | ||
868 | 1. [Org Return: DWIM](https://github.com/alphapapa/unpackaged.el#org-return-dwim) | 1089 | 1. [Org Return: DWIM](https://github.com/alphapapa/unpackaged.el#org-return-dwim) |
869 | 1090 | ||
870 | (defun unpackaged/org-element-descendant-of (type element) | 1091 | (defun unpackaged/org-element-descendant-of (type element) |
871 | "Return non-nil if ELEMENT is a descendant of TYPE. | 1092 | "Return non-nil if ELEMENT is a descendant of TYPE. |
872 | TYPE should be an element type, like `item' or `paragraph'. | 1093 | TYPE should be an element type, like `item' or `paragraph'. |
873 | ELEMENT should be a list like that returned by `org-element-context'." | 1094 | ELEMENT should be a list like that returned by `org-element-context'." |
874 | ;; MAYBE: Use `org-element-lineage'. | 1095 | ;; MAYBE: Use `org-element-lineage'. |
875 | (when-let* ((parent (org-element-property :parent element))) | 1096 | (when-let* ((parent (org-element-property :parent element))) |
876 | (or (eq type (car parent)) | 1097 | (or (eq type (car parent)) |
877 | (unpackaged/org-element-descendant-of type parent)))) | 1098 | (unpackaged/org-element-descendant-of type parent)))) |
878 | 1099 | ||
879 | ;;;###autoload | 1100 | ;;;###autoload |
880 | (defun unpackaged/org-return-dwim (&optional default) | 1101 | (defun unpackaged/org-return-dwim (&optional default) |
881 | "A helpful replacement for `org-return'. With prefix, call `org-return'. | 1102 | "A helpful replacement for `org-return'. With prefix, call `org-return'. |
882 | 1103 | ||
883 | On headings, move point to position after entry content. In | 1104 | On headings, move point to position after entry content. In |
884 | lists, insert a new item or end the list, with checkbox if | 1105 | lists, insert a new item or end the list, with checkbox if |
885 | appropriate. In tables, insert a new row or end the table." | 1106 | appropriate. In tables, insert a new row or end the table." |
886 | ;; Inspired by John Kitchin: http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/ | 1107 | ;; Inspired by John Kitchin: http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/ |
887 | (interactive "P") | 1108 | (interactive "P") |
888 | (if default | 1109 | (if default |
889 | (org-return) | 1110 | (org-return) |
890 | (cond | 1111 | (cond |
891 | ;; Act depending on context around point. | 1112 | ;; Act depending on context around point. |
892 | 1113 | ||
893 | ;; NOTE: I prefer RET to not follow links, but by uncommenting this block, links will be | 1114 | ;; NOTE: I prefer RET to not follow links, but by uncommenting this block, links will be |
894 | ;; followed. | 1115 | ;; followed. |
895 | 1116 | ||
896 | ;; ((eq 'link (car (org-element-context))) | 1117 | ;; ((eq 'link (car (org-element-context))) |
897 | ;; ;; Link: Open it. | 1118 | ;; ;; Link: Open it. |
898 | ;; (org-open-at-point-global)) | 1119 | ;; (org-open-at-point-global)) |
899 | 1120 | ||
900 | ((org-at-heading-p) | 1121 | ((org-at-heading-p) |
901 | ;; Heading: Move to position after entry content. | 1122 | ;; Heading: Move to position after entry content. |
902 | ;; NOTE: This is probably the most interesting feature of this function. | 1123 | ;; NOTE: This is probably the most interesting feature of this function. |
903 | (let ((heading-start (org-entry-beginning-position))) | 1124 | (let ((heading-start (org-entry-beginning-position))) |
904 | (goto-char (org-entry-end-position)) | 1125 | (goto-char (org-entry-end-position)) |
905 | (cond ((and (org-at-heading-p) | 1126 | (cond ((and (org-at-heading-p) |
906 | (= heading-start (org-entry-beginning-position))) | 1127 | (= heading-start (org-entry-beginning-position))) |
907 | ;; Entry ends on its heading; add newline after | 1128 | ;; Entry ends on its heading; add newline after |
908 | (end-of-line) | 1129 | (end-of-line) |
909 | (insert "\n\n")) | 1130 | (insert "\n\n")) |
910 | (t | 1131 | (t |
911 | ;; Entry ends after its heading; back up | 1132 | ;; Entry ends after its heading; back up |
912 | (forward-line -1) | 1133 | (forward-line -1) |
913 | (end-of-line) | 1134 | (end-of-line) |
914 | (when (org-at-heading-p) | 1135 | (when (org-at-heading-p) |
915 | ;; At the same heading | 1136 | ;; At the same heading |
916 | (forward-line) | 1137 | (forward-line) |
917 | (insert "\n") | 1138 | (insert "\n") |
918 | (forward-line -1)) | 1139 | (forward-line -1)) |
919 | ;; FIXME: looking-back is supposed to be called with more arguments. | 1140 | ;; FIXME: looking-back is supposed to be called with more arguments. |
920 | (while (not (looking-back (rx (repeat 3 (seq (optional blank) "\n"))) nil)) | 1141 | (while (not (looking-back (rx (repeat 3 (seq (optional blank) "\n"))) nil)) |
921 | (insert "\n")) | 1142 | (insert "\n")) |
922 | (forward-line -1))))) | 1143 | (forward-line -1))))) |
923 | 1144 | ||
924 | ((org-at-item-checkbox-p) | 1145 | ((org-at-item-checkbox-p) |
925 | ;; Checkbox: Insert new item with checkbox. | 1146 | ;; Checkbox: Insert new item with checkbox. |
926 | (org-insert-todo-heading nil)) | 1147 | (org-insert-todo-heading nil)) |
927 | 1148 | ||
928 | ((org-in-item-p) | 1149 | ((org-in-item-p) |
929 | ;; Plain list. Yes, this gets a little complicated... | 1150 | ;; Plain list. Yes, this gets a little complicated... |
930 | (let ((context (org-element-context))) | 1151 | (let ((context (org-element-context))) |
931 | (if (or (eq 'plain-list (car context)) ; First item in list | 1152 | (if (or (eq 'plain-list (car context)) ; First item in list |
932 | (and (eq 'item (car context)) | 1153 | (and (eq 'item (car context)) |
933 | (not (eq (org-element-property :contents-begin context) | 1154 | (not (eq (org-element-property :contents-begin context) |
934 | (org-element-property :contents-end context)))) | 1155 | (org-element-property :contents-end context)))) |
935 | (unpackaged/org-element-descendant-of 'item context)) ; Element in list item, e.g. a link | 1156 | (unpackaged/org-element-descendant-of 'item context)) ; Element in list item, e.g. a link |
936 | ;; Non-empty item: Add new item. | 1157 | ;; Non-empty item: Add new item. |
937 | (org-insert-item) | 1158 | (org-insert-item) |
938 | ;; Empty item: Close the list. | 1159 | ;; Empty item: Close the list. |
939 | ;; TODO: Do this with org functions rather than operating on the text. Can't seem to find the right function. | 1160 | ;; TODO: Do this with org functions rather than operating on the text. Can't seem to find the right function. |
940 | (delete-region (line-beginning-position) (line-end-position)) | 1161 | (delete-region (line-beginning-position) (line-end-position)) |
941 | (insert "\n")))) | 1162 | (insert "\n")))) |
942 | 1163 | ||
943 | ((when (fboundp 'org-inlinetask-in-task-p) | 1164 | ((when (fboundp 'org-inlinetask-in-task-p) |
944 | (org-inlinetask-in-task-p)) | 1165 | (org-inlinetask-in-task-p)) |
945 | ;; Inline task: Don't insert a new heading. | 1166 | ;; Inline task: Don't insert a new heading. |
946 | (org-return)) | 1167 | (org-return)) |
947 | 1168 | ||
948 | ((org-at-table-p) | 1169 | ((org-at-table-p) |
949 | (cond ((save-excursion | 1170 | (cond ((save-excursion |
950 | (beginning-of-line) | 1171 | (beginning-of-line) |
951 | ;; See `org-table-next-field'. | 1172 | ;; See `org-table-next-field'. |
952 | (cl-loop with end = (line-end-position) | 1173 | (cl-loop with end = (line-end-position) |
953 | for cell = (org-element-table-cell-parser) | 1174 | for cell = (org-element-table-cell-parser) |
954 | always (equal (org-element-property :contents-begin cell) | 1175 | always (equal (org-element-property :contents-begin cell) |
955 | (org-element-property :contents-end cell)) | 1176 | (org-element-property :contents-end cell)) |
956 | while (re-search-forward "|" end t))) | 1177 | while (re-search-forward "|" end t))) |
957 | ;; Empty row: end the table. | 1178 | ;; Empty row: end the table. |
958 | (delete-region (line-beginning-position) (line-end-position)) | 1179 | (delete-region (line-beginning-position) (line-end-position)) |
959 | (org-return)) | 1180 | (org-return)) |
960 | (t | 1181 | (t |
961 | ;; Non-empty row: call `org-return'. | 1182 | ;; Non-empty row: call `org-return'. |
962 | (org-return)))) | 1183 | (org-return)))) |
963 | (t | 1184 | (t |
964 | ;; All other cases: call `org-return'. | 1185 | ;; All other cases: call `org-return'. |
965 | (org-return))))) | 1186 | (org-return))))) |
966 | 1187 | ||
967 | (with-eval-after-load 'org | 1188 | (with-eval-after-load 'org |
968 | (define-key org-mode-map (kbd "RET") #'unpackaged/org-return-dwim)) | 1189 | (define-key org-mode-map (kbd "RET") #'unpackaged/org-return-dwim)) |
969 | 1190 | ||
970 | 2. Insert blank lines around headers | 1191 | 2. Insert blank lines around headers |
971 | 1192 | ||
972 | from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#ensure-blank-lines-between-headings-and-before-contents). | 1193 | from [unpackaged.el](https://github.com/alphapapa/unpackaged.el#ensure-blank-lines-between-headings-and-before-contents). |
973 | 1194 | ||
974 | ;;;###autoload | 1195 | ;;;###autoload |
975 | (defun unpackaged/org-fix-blank-lines (&optional prefix) | 1196 | (defun unpackaged/org-fix-blank-lines (&optional prefix) |
976 | "Ensure that blank lines exist between headings and between headings and their contents. | 1197 | "Ensure that blank lines exist between headings and between headings and their contents. |
977 | With prefix, operate on whole buffer. Ensures that blank lines | 1198 | With prefix, operate on whole buffer. Ensures that blank lines |
978 | exist after each headings's drawers." | 1199 | exist after each headings's drawers." |
979 | (interactive "P") | 1200 | (interactive "P") |
980 | (org-map-entries (lambda () | 1201 | (org-map-entries (lambda () |
981 | (org-with-wide-buffer | 1202 | (org-with-wide-buffer |
982 | ;; `org-map-entries' narrows the buffer, which prevents us | 1203 | ;; `org-map-entries' narrows the buffer, which prevents us |
983 | ;; from seeing newlines before the current heading, so we | 1204 | ;; from seeing newlines before the current heading, so we |
984 | ;; do this part widened. | 1205 | ;; do this part widened. |
985 | (while (not (looking-back "\n\n" nil)) | 1206 | (while (not (looking-back "\n\n" nil)) |
986 | ;; Insert blank lines before heading. | 1207 | ;; Insert blank lines before heading. |
987 | (insert "\n"))) | 1208 | (insert "\n"))) |
988 | (let ((end (org-entry-end-position))) | 1209 | (let ((end (org-entry-end-position))) |
989 | ;; Insert blank lines before entry content | 1210 | ;; Insert blank lines before entry content |
990 | (forward-line) | 1211 | (forward-line) |
991 | (while (and (org-at-planning-p) | 1212 | (while (and (org-at-planning-p) |
992 | (< (point) (point-max))) | 1213 | (< (point) (point-max))) |
993 | ;; Skip planning lines | 1214 | ;; Skip planning lines |
994 | (forward-line)) | 1215 | (forward-line)) |
995 | (while (re-search-forward org-drawer-regexp end t) | 1216 | (while (re-search-forward org-drawer-regexp end t) |
996 | ;; Skip drawers. You might think that `org-at-drawer-p' | 1217 | ;; Skip drawers. You might think that `org-at-drawer-p' |
997 | ;; would suffice, but for some reason it doesn't work | 1218 | ;; would suffice, but for some reason it doesn't work |
998 | ;; correctly when operating on hidden text. This | 1219 | ;; correctly when operating on hidden text. This |
999 | ;; works, taken from `org-agenda-get-some-entry-text'. | 1220 | ;; works, taken from `org-agenda-get-some-entry-text'. |
1000 | (re-search-forward "^[ \t]*:END:.*\n?" end t) | 1221 | (re-search-forward "^[ \t]*:END:.*\n?" end t) |
1001 | (goto-char (match-end 0))) | 1222 | (goto-char (match-end 0))) |
1002 | (unless (or (= (point) (point-max)) | 1223 | (unless (or (= (point) (point-max)) |
1003 | (org-at-heading-p) | 1224 | (org-at-heading-p) |
1004 | (looking-at-p "\n")) | 1225 | (looking-at-p "\n")) |
1005 | (insert "\n")))) | 1226 | (insert "\n")))) |
1006 | t (if prefix | 1227 | t (if prefix |
1007 | nil | 1228 | nil |
1008 | 'tree))) | 1229 | 'tree))) |
1009 | 1230 | ||
1010 | 1. Add a before-save-hook | 1231 | 1. Add a before-save-hook |
1011 | 1232 | ||
1012 | (defun cribbed/org-mode-fix-blank-lines () | 1233 | (defun cribbed/org-mode-fix-blank-lines () |
1013 | (when (eq major-mode 'org-mode) | 1234 | (when (eq major-mode 'org-mode) |
1014 | (let ((current-prefix-arg 4)) ; Emulate C-u | 1235 | (let ((current-prefix-arg 4)) ; Emulate C-u |
1015 | (call-interactively 'unpackaged/org-fix-blank-lines)))) | 1236 | (call-interactively 'unpackaged/org-fix-blank-lines)))) |
1016 | 1237 | ||
1017 | (add-hook 'before-save-hook #'cribbed/org-mode-fix-blank-lines) | 1238 | (add-hook 'before-save-hook #'cribbed/org-mode-fix-blank-lines) |
1018 | 1239 | ||
1019 | 1240 | ||
1020 | ### Org Agenda | 1241 | ### Org Agenda |
1021 | 1242 | ||
1022 | (cuss org-agenda-files | 1243 | (cuss org-agenda-files |
1023 | (let ((list)) | 1244 | (let ((list)) |
1024 | (dolist (file '(;; add more files to this list | 1245 | (dolist (file '(;; add more files to this list |
1025 | "home.org" | 1246 | "home.org" |
1026 | "work.org") | 1247 | "work.org") |
1027 | list) | 1248 | list) |
1028 | (push (expand-file-name file org-directory) list)))) | 1249 | (push (expand-file-name file org-directory) list)))) |
1029 | 1250 | ||
1030 | (define-key acdw/map (kbd "C-a") #'org-agenda) | 1251 | (define-key acdw/map (kbd "C-a") #'org-agenda) |
1031 | 1252 | ||
1032 | (cuss org-todo-keywords | 1253 | (cuss org-todo-keywords |
1033 | '((sequence "RECUR(r)" "TODO(t)" "|" "DONE(d)") | 1254 | '((sequence "RECUR(r)" "TODO(t)" "|" "DONE(d)") |
1034 | (sequence "|" "CANCELLED(c)"))) | 1255 | (sequence "|" "CANCELLED(c)"))) |
1035 | 1256 | ||
1036 | 1257 | ||
1037 | ### TODO Capture | 1258 | ### TODO Capture |
1038 | 1259 | ||
1039 | 1260 | ||
1261 | ### Include Org links in source code | ||
1262 | |||
1263 | (straight-use-package '(org-link-minor-mode | ||
1264 | :host github | ||
1265 | :repo "seanohalpin/org-link-minor-mode")) | ||
1266 | |||
1267 | ;; enable in elisp buffers | ||
1268 | (add-hook 'emacs-lisp-mode-hook #'org-link-minor-mode) | ||
1269 | |||
1270 | |||
1040 | ## Git | 1271 | ## Git |
1041 | 1272 | ||
1042 | (straight-use-package 'magit) | 1273 | (straight-use-package 'magit) |
@@ -1047,8 +1278,8 @@ I’ve put org mode under Applications, as opposed to Writing, because it’s m | |||
1047 | ## Beancount mode | 1278 | ## Beancount mode |
1048 | 1279 | ||
1049 | (straight-use-package '(beancount-mode | 1280 | (straight-use-package '(beancount-mode |
1050 | :host github | 1281 | :host github |
1051 | :repo "beancount/beancount-mode")) | 1282 | :repo "beancount/beancount-mode")) |
1052 | (require 'beancount) | 1283 | (require 'beancount) |
1053 | 1284 | ||
1054 | (add-to-list 'auto-mode-alist '("\\.beancount\\'" . beancount-mode)) | 1285 | (add-to-list 'auto-mode-alist '("\\.beancount\\'" . beancount-mode)) |
@@ -1072,24 +1303,33 @@ I’ve put org mode under Applications, as opposed to Writing, because it’s m | |||
1072 | 1303 | ||
1073 | ### init.el | 1304 | ### init.el |
1074 | 1305 | ||
1075 | I realized I didn’t need `early-init.el`, since it really only set `load-prefer-newer`. So I’ve set that here, and wrapped the actual loading of config in a `let*` form that speeds up init, and loads the newer of either `config.org` or `config.el`. | ||
1076 | |||
1077 | ;; init.el -*- lexical-binding: t -*- | 1306 | ;; init.el -*- lexical-binding: t -*- |
1078 | 1307 | ||
1079 | (setq load-prefer-newer t) | 1308 | (setq load-prefer-newer t) |
1080 | 1309 | ||
1081 | (let* (;; Speed up init | 1310 | (let* (;; Speed up init |
1082 | (gc-cons-threshold most-positive-fixnum) | 1311 | (gc-cons-threshold most-positive-fixnum) |
1083 | (file-name-handler-alist nil) | 1312 | (file-name-handler-alist nil) |
1084 | ;; Config file names | 1313 | ;; Config file names |
1085 | (conf (expand-file-name "config" | 1314 | (conf (expand-file-name "config" |
1086 | user-emacs-directory)) | 1315 | user-emacs-directory)) |
1087 | (conf-el (concat conf ".el")) | 1316 | (conf-el (concat conf ".el")) |
1088 | (conf-org (concat conf ".org"))) | 1317 | (conf-org (concat conf ".org"))) |
1089 | (unless (and (file-newer-than-file-p conf-el conf-org) | 1318 | (unless (and (file-newer-than-file-p conf-el conf-org) |
1090 | (load conf 'no-error)) | 1319 | (load conf 'no-error)) |
1091 | (require 'org) | 1320 | (require 'org) |
1092 | (org-babel-load-file conf-org))) | 1321 | (org-babel-load-file conf-org))) |
1322 | |||
1323 | |||
1324 | ### early-init.el | ||
1325 | |||
1326 | ;; early-init.el -*- no-byte-compile: t; -*- | ||
1327 | |||
1328 | ;; I use `straight.el' instead of `package.el'. | ||
1329 | (setq package-enable-at-startup nil) | ||
1330 | |||
1331 | ;; Don't resize the frame when loading fonts | ||
1332 | (setq frame-inhibit-implied-resize t) | ||
1093 | 1333 | ||
1094 | 1334 | ||
1095 | ## Ease tangling and loading of Emacs' init | 1335 | ## Ease tangling and loading of Emacs' init |
@@ -1099,29 +1339,29 @@ I realized I didn’t need `early-init.el`, since it really only set `load-prefe | |||
1099 | Then, load the byte-compilations unless passed with a prefix argument." | 1339 | Then, load the byte-compilations unless passed with a prefix argument." |
1100 | (interactive "P") | 1340 | (interactive "P") |
1101 | (let ((config (expand-file-name "config.org" user-emacs-directory))) | 1341 | (let ((config (expand-file-name "config.org" user-emacs-directory))) |
1102 | (save-mark-and-excursion | 1342 | (save-mark-and-excursion |
1103 | (with-current-buffer (find-file config) | 1343 | (with-current-buffer (find-file config) |
1104 | (let ((prog-mode-hook nil)) | 1344 | (let ((prog-mode-hook nil)) |
1105 | ;; generate the readme | 1345 | ;; generate the readme |
1106 | (when (file-newer-than-file-p config (expand-file-name | 1346 | (when (file-newer-than-file-p config (expand-file-name |
1107 | "README.md" | 1347 | "README.md" |
1108 | user-emacs-directory)) | 1348 | user-emacs-directory)) |
1109 | (message "%s" "Exporting README.md...") | 1349 | (message "%s" "Exporting README.md...") |
1110 | (require 'ox-md) | 1350 | (require 'ox-md) |
1111 | (with-demoted-errors "Problem exporting README.md: %S" | 1351 | (with-demoted-errors "Problem exporting README.md: %S" |
1112 | (org-md-export-to-markdown))) | 1352 | (org-md-export-to-markdown))) |
1113 | ;; tangle config.org | 1353 | ;; tangle config.org |
1114 | (when (file-newer-than-file-p config (expand-file-name | 1354 | (when (file-newer-than-file-p config (expand-file-name |
1115 | "config.el" | 1355 | "config.el" |
1116 | user-emacs-directory)) | 1356 | user-emacs-directory)) |
1117 | (message "%s" "Tangling config.org...") | 1357 | (message "%s" "Tangling config.org...") |
1118 | (require 'org) | 1358 | (require 'org) |
1119 | (let ((inits (org-babel-tangle))) | 1359 | (let ((inits (org-babel-tangle))) |
1120 | ;; byte-compile resulting files | 1360 | ;; byte-compile resulting files |
1121 | (message "%s" "Byte-compiling...") | 1361 | (message "%s" "Byte-compiling...") |
1122 | (dolist (f inits) | 1362 | (dolist (f inits) |
1123 | (when (string-match "\\.el\\'" f) | 1363 | (when (string-match "\\.el\\'" f) |
1124 | (byte-compile-file f (not disable-load))))))))))) | 1364 | (byte-compile-file f (not disable-load))))))))))) |
1125 | 1365 | ||
1126 | 1366 | ||
1127 | ## Ancillary scripts | 1367 | ## Ancillary scripts |
@@ -1129,32 +1369,35 @@ I realized I didn’t need `early-init.el`, since it really only set `load-prefe | |||
1129 | 1369 | ||
1130 | ### emacsdc | 1370 | ### emacsdc |
1131 | 1371 | ||
1372 | :header-args: :tangle bin/emacsdc :tangle-mode (identity #o755) | ||
1373 | |||
1132 | Here's a wrapper script that'll start `emacs --daemon` if there isn't | 1374 | Here's a wrapper script that'll start `emacs --daemon` if there isn't |
1133 | one, and then launch `emacsclient` with the arguments. I'd recommend | 1375 | one, and then launch `emacsclient` with the arguments. I'd recommend |
1134 | installing with either `ln -s bin/emacsdc $HOME/.local/bin/`, or | 1376 | installing with either `ln -s bin/emacsdc $HOME/.local/bin/`, or |
1135 | adding `$HOME/.local/bin` to your `$PATH`. | 1377 | adding `$HOME/.local/bin` to your `$PATH`. |
1136 | 1378 | ||
1137 | if ! emacsclient -nc "$@" 2>/dev/null; then | 1379 | if ! emacsclient -nc "$@" 2>/dev/null; then |
1138 | emacs --daemon | 1380 | emacs --daemon |
1139 | emacsclient -nc "$@" | 1381 | emacsclient -nc "$@" |
1140 | fi | 1382 | fi |
1141 | 1383 | ||
1142 | 1384 | ||
1143 | ### Emacs.cmd | 1385 | ### Emacs.cmd |
1144 | 1386 | ||
1145 | Here's a wrapper script that'll run Emacs on Windows, with a custom | 1387 | Here's a wrapper script that'll run Emacs on Windows, with a custom `$HOME`. I have |
1146 | `$HOME`. I have mine setup like this: Emacs is downloaded from [the | 1388 | mine setup like this: Emacs is downloaded from [the GNU mirror](https://mirrors.tripadvisor.com/gnu/emacs/windows/emacs-27/emacs-27.1-x86_64.zip) and unzipped to |
1147 | GNU mirror](https://mirrors.tripadvisor.com/gnu/emacs/windows/emacs-27/emacs-27.1-x86_64.zip) and unzipped to `~/Downloads/emacs/`. `Emacs.cmd` sets | 1389 | `~/Downloads/emacs/`. For some reason, Emacs by default sets `$HOME` to `%APPDATA%`, |
1148 | `$HOME` to `~/Downloads/emacshome/`, which is where `.emacs.d` is, and | 1390 | which doesn’t make a lot of sense to me. I change it to `%USERPROFILE%`, and then run |
1149 | whatever else I might want to throw in there. | 1391 | Emacs with the supplied arguments. |
1150 | 1392 | ||
1151 | set HOME=%~dp0..\..\emacshome | 1393 | set HOME=%USERPROFILE% |
1394 | set EMACS="%USERPROFILE%\Downloads\emacs\bin\runemacs.exe" | ||
1152 | 1395 | ||
1153 | REM Run "Quick Mode" | 1396 | REM Run "Quick Mode" |
1154 | REM "%~dp0runemacs.exe" -Q %* | 1397 | REM "%EMACS%" -Q %* |
1155 | 1398 | ||
1156 | REM Regular | 1399 | REM Regular |
1157 | "%~dp0runemacs.exe" %* | 1400 | "%EMACS%" %* |
1158 | 1401 | ||
1159 | 1402 | ||
1160 | ## License | 1403 | ## License |
@@ -1188,4 +1431,3 @@ It's highly likely that the WTFPL is completely incompatible with the | |||
1188 | GPL, for what should be fairly obvious reasons. To that, I say: | 1431 | GPL, for what should be fairly obvious reasons. To that, I say: |
1189 | 1432 | ||
1190 | **SUE ME, RMS!** | 1433 | **SUE ME, RMS!** |
1191 | |||