summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--config.org984
-rw-r--r--early-init.el79
-rw-r--r--init.el47
3 files changed, 864 insertions, 246 deletions
diff --git a/config.org b/config.org index b27fb35..ea8c78c 100644 --- a/config.org +++ b/config.org
@@ -5,7 +5,15 @@
5 5
6#+begin_src emacs-lisp :noweb-ref settings 6#+begin_src emacs-lisp :noweb-ref settings
7 (setq user-full-name "Case Duckworth" 7 (setq user-full-name "Case Duckworth"
8 user-mail-address "acdw@acdw.net") 8 user-mail-address "acdw@acdw.net")
9#+end_src
10
11** Where I am
12
13#+begin_src emacs-lisp :noweb-ref settings
14 (setq calendar-location-name "Baton Rouge, LA"
15 calendar-latitude 30.4
16 calendar-longitude -91.1)
9#+end_src 17#+end_src
10 18
11* Look and feel 19* Look and feel
@@ -14,7 +22,7 @@
14 22
15*** Initial frame setup 23*** Initial frame setup
16:PROPERTIES: 24:PROPERTIES:
17:header-args: :noweb-ref initial-frame-setup 25:header-args: :noweb-ref early-init-frame
18:END: 26:END:
19 27
20I tangle this section to =early-init.el=, since that's evaluated 28I tangle this section to =early-init.el=, since that's evaluated
@@ -25,7 +33,7 @@ of unstyled content" thing.
25 33
26#+begin_src emacs-lisp 34#+begin_src emacs-lisp
27 (add-to-list 'default-frame-alist 35 (add-to-list 'default-frame-alist
28 '(tool-bar-lines . 0)) 36 '(tool-bar-lines . 0))
29 37
30 (tool-bar-mode -1) 38 (tool-bar-mode -1)
31#+end_src 39#+end_src
@@ -34,7 +42,7 @@ of unstyled content" thing.
34 42
35#+begin_src emacs-lisp 43#+begin_src emacs-lisp
36 (add-to-list 'default-frame-alist 44 (add-to-list 'default-frame-alist
37 '(menu-bar-lines . 0)) 45 '(menu-bar-lines . 0))
38 46
39 (menu-bar-mode -1) 47 (menu-bar-mode -1)
40#+end_src 48#+end_src
@@ -43,19 +51,29 @@ of unstyled content" thing.
43 51
44#+begin_src emacs-lisp 52#+begin_src emacs-lisp
45 (add-to-list 'default-frame-alist 53 (add-to-list 'default-frame-alist
46 '(vertical-scroll-bars . nil) 54 '(vertical-scroll-bars . nil)
47 '(horizontal-scroll-bars . nil)) 55 '(horizontal-scroll-bars . nil))
48 56
49 (scroll-bar-mode -1) 57 (scroll-bar-mode -1)
50 (horizontal-scroll-bar-mode -1) 58 (horizontal-scroll-bar-mode -1)
51#+end_src 59#+end_src
52 60
61**** Resizing
62
63I don't want the frame to resize when I change fonts and stuff, and I
64want it to resize by pixels -- we /are/ using a GUI, after all.
65
66#+begin_src emacs-lisp
67 (setq-default frame-inhibit-implied-resize t
68 frame-resize-pixelwise t)
69#+end_src
70
53*** Frame titles 71*** Frame titles
54 72
55#+begin_src emacs-lisp :noweb-ref settings 73#+begin_src emacs-lisp :noweb-ref settings
56 (setq-default frame-title-format 74 (setq-default frame-title-format
57 (concat invocation-name "@" (system-name) 75 (concat invocation-name "@" (system-name)
58 ": %b %+%+ %f")) 76 ": %b %+%+ %f"))
59#+end_src 77#+end_src
60 78
61*** Fringes 79*** Fringes
@@ -131,7 +149,7 @@ to switch to the other buffer if there's only one window in the frame.
131 "Switch to other window, or the previous buffer." 149 "Switch to other window, or the previous buffer."
132 (interactive) 150 (interactive)
133 (if (eq (count-windows) 1) 151 (if (eq (count-windows) 1)
134 (switch-to-buffer nil) 152 (switch-to-buffer nil)
135 (other-window 1))) 153 (other-window 1)))
136#+end_src 154#+end_src
137 155
@@ -164,12 +182,12 @@ also want it to show a cute little message to myself.
164 182
165#+begin_src emacs-lisp :noweb-ref settings 183#+begin_src emacs-lisp :noweb-ref settings
166 (setq-default inhibit-startup-screen t ; Don't show that splash screen thing. 184 (setq-default inhibit-startup-screen t ; Don't show that splash screen thing.
167 initial-buffer-choice t ; Start on *scratch* 185 initial-buffer-choice t ; Start on *scratch*
168 initial-scratch-message 186 initial-scratch-message
169 (concat ";; Howdy, " 187 (concat ";; Howdy, "
170 (nth 0 (split-string user-full-name)) "!\n" 188 (nth 0 (split-string user-full-name)) "!\n"
171 ";; Welcome to Emacs." 189 ";; Welcome to Emacs."
172 "\n\n")) 190 "\n\n"))
173#+end_src 191#+end_src
174 192
175*** Immortal =*scratch*= buffer 193*** Immortal =*scratch*= buffer
@@ -181,7 +199,7 @@ function to the =kill-buffer-query-functions= hook that will return
181#+begin_src emacs-lisp :noweb-ref functions 199#+begin_src emacs-lisp :noweb-ref functions
182 (defun immortal-scratch () 200 (defun immortal-scratch ()
183 (if (not (eq (current-buffer) (get-buffer "*scratch*"))) 201 (if (not (eq (current-buffer) (get-buffer "*scratch*")))
184 t 202 t
185 (bury-buffer) 203 (bury-buffer)
186 nil)) 204 nil))
187#+end_src 205#+end_src
@@ -203,12 +221,12 @@ function to the =kill-buffer-query-functions= hook that will return
203 (interactive "P") 221 (interactive "P")
204 (pcase (or (car prefix) 0) 222 (pcase (or (car prefix) 0)
205 (0 (kill-current-buffer) 223 (0 (kill-current-buffer)
206 (unless (one-window-p) (delete-window))) 224 (unless (one-window-p) (delete-window)))
207 (4 (other-window 1) 225 (4 (other-window 1)
208 (kill-current-buffer) 226 (kill-current-buffer)
209 (unless (one-window-p) (delete-window))) 227 (unless (one-window-p) (delete-window)))
210 (16 (mapc #'kill-buffer (delq (current-buffer) (buffer-list))) 228 (16 (mapc #'kill-buffer (delq (current-buffer) (buffer-list)))
211 (delete-other-windows)))) 229 (delete-other-windows))))
212#+end_src 230#+end_src
213 231
214#+begin_src emacs-lisp :noweb-ref bindings 232#+begin_src emacs-lisp :noweb-ref bindings
@@ -223,7 +241,7 @@ I like a vertical bar, but only in the selected window.
223 241
224#+begin_src emacs-lisp :noweb-ref settings 242#+begin_src emacs-lisp :noweb-ref settings
225 (setq-default cursor-type 'bar 243 (setq-default cursor-type 'bar
226 cursor-in-non-selected-windows nil) 244 cursor-in-non-selected-windows nil)
227#+end_src 245#+end_src
228 246
229*** Don't blink the cursor 247*** Don't blink the cursor
@@ -238,7 +256,7 @@ I like a vertical bar, but only in the selected window.
238 256
239#+begin_src emacs-lisp :noweb-ref settings 257#+begin_src emacs-lisp :noweb-ref settings
240 (setq-default tab-bar-tab-name-function 258 (setq-default tab-bar-tab-name-function
241 #'tab-bar-tab-name-current-with-count) 259 #'tab-bar-tab-name-current-with-count)
242#+end_src 260#+end_src
243 261
244*** When to show the tab bar 262*** When to show the tab bar
@@ -255,13 +273,13 @@ Only when there's more than one tab.
255 273
256#+begin_src emacs-lisp :noweb-ref functions 274#+begin_src emacs-lisp :noweb-ref functions
257 (defun set-face-from-alternatives (face frame &rest fontspecs) 275 (defun set-face-from-alternatives (face frame &rest fontspecs)
258 "Set FACE on FRAME from first available spec from FONTSPECS. 276 "Set FACE on FRAME from first available spec from FONTSPECS.
259 FACE and FRAME work the same as with `set-face-attribute.'" 277 FACE and FRAME work the same as with `set-face-attribute.'"
260 (catch :return 278 (catch :return
261 (dolist (spec fontspecs) 279 (dolist (spec fontspecs)
262 (when-let ((found (find-font (apply #'font-spec spec)))) 280 (when-let ((found (find-font (apply #'font-spec spec))))
263 (set-face-attribute face frame :font found) 281 (set-face-attribute face frame :font found)
264 (throw :return found))))) 282 (throw :return found)))))
265#+end_src 283#+end_src
266 284
267*** Setup fonts on first window focus 285*** Setup fonts on first window focus
@@ -276,24 +294,28 @@ At the end of this function, it removes itself from
276 removes itself from that hook." 294 removes itself from that hook."
277 (interactive) 295 (interactive)
278 (set-face-from-alternatives 'default nil 296 (set-face-from-alternatives 'default nil
279 '(:family "Input Mono" 297 '(:family "Iosevka Acdw"
280 :slant normal 298 :slant normal
281 :weight normal 299 :weight normal
282 :height 110) 300 :height 105)
283 '(:family "Consolas" 301 '(:family "Iosevka Extended"
284 :slant normal 302 :slant normal
285 :weight normal 303 :weight normal
286 :height 100)) 304 :height 105)
305 '(:family "Consolas"
306 :slant normal
307 :weight normal
308 :height 100))
287 ;; `fixed-pitch' inherits from `default' 309 ;; `fixed-pitch' inherits from `default'
288 (set-face-attribute 'fixed-pitch nil :inherit 'default) 310 (set-face-attribute 'fixed-pitch nil :inherit 'default)
289 ;; variable-pitch is different 311 ;; variable-pitch is different
290 (set-face-from-alternatives 'variable-pitch nil 312 (set-face-from-alternatives 'variable-pitch nil
291 '(:family "Input Sans" 313 '(:family "DejaVu Sans"
292 :slant normal 314 :slant normal
293 :weight normal) 315 :weight normal)
294 '(:family "Georgia" 316 '(:family "Georgia"
295 :slant normal 317 :slant normal
296 :weight normal)) 318 :weight normal))
297 ;; remove self from hook 319 ;; remove self from hook
298 (remove-function after-focus-change-function #'acdw/setup-fonts)) 320 (remove-function after-focus-change-function #'acdw/setup-fonts))
299#+end_src 321#+end_src
@@ -304,7 +326,7 @@ using the graphical Emacs.
304#+begin_src emacs-lisp :noweb-ref hooks 326#+begin_src emacs-lisp :noweb-ref hooks
305 (when (display-graphic-p) 327 (when (display-graphic-p)
306 (add-function :before after-focus-change-function 328 (add-function :before after-focus-change-function
307 #'acdw/setup-fonts)) 329 #'acdw/setup-fonts))
308#+end_src 330#+end_src
309 331
310*** Underlines 332*** Underlines
@@ -317,6 +339,53 @@ underline below all the text.
317 (setq-default x-underline-at-descent-line t) 339 (setq-default x-underline-at-descent-line t)
318#+end_src 340#+end_src
319 341
342** Theming
343
344*** Modus themes
345
346#+begin_src emacs-lisp :noweb-ref packages
347 (straight-use-package 'modus-themes)
348#+end_src
349
350#+begin_src emacs-lisp :noweb-ref settings
351 (setq-default modus-themes-slanted-constructs t
352 modus-themes-bold-constructs t
353 modus-themes-region 'bg-only
354 modus-themes-org-blocks 'grayscale
355 modus-themes-headings '((1 . line)
356 (t . t))
357 modus-themes-scale-headings nil)
358#+end_src
359
360*** Change themes based on time of day
361
362#+begin_src emacs-lisp :noweb-ref functions
363 (defun acdw/run-with-sun (sunrise-command sunset-command)
364 "Run commands at sunrise and sunset."
365 (let* ((times-regex (rx (* nonl)
366 (: (any ?s ?S) "unrise") " "
367 (group (repeat 1 2 digit) ":"
368 (repeat 1 2 digit)
369 (: (any ?a ?A ?p ?P) (any ?m ?M)))
370 (* nonl)
371 (: (any ?s ?S) "unset") " "
372 (group (repeat 1 2 digit) ":"
373 (repeat 1 2 digit)
374 (: (any ?a ?A ?p ?P) (any ?m ?M)))
375 (* nonl)))
376 (ss (sunrise-sunset))
377 (_m (string-match times-regex ss))
378 (sunrise-time (match-string 1 ss))
379 (sunset-time (match-string 2 ss)))
380 (run-at-time sunrise-time (* 60 60 24) sunrise-command)
381 (run-at-time sunset-time (* 60 60 24) sunset-command)))
382#+end_src
383
384#+begin_src emacs-lisp :noweb-ref hooks
385 (acdw/run-with-sun #'modus-themes-load-operandi
386 #'modus-themes-load-vivendi)
387#+end_src
388
320* Interactivity 389* Interactivity
321 390
322** Dialogs and alerts 391** Dialogs and alerts
@@ -346,7 +415,7 @@ systems.
346 415
347#+begin_src emacs-lisp :noweb-ref settings 416#+begin_src emacs-lisp :noweb-ref settings
348 (setq-default visible-bell nil 417 (setq-default visible-bell nil
349 ring-bell-function #'flash-mode-line) 418 ring-bell-function #'flash-mode-line)
350#+end_src 419#+end_src
351 420
352**** Flash the mode-line 421**** Flash the mode-line
@@ -363,9 +432,9 @@ systems.
363 432
364#+begin_src emacs-lisp :noweb-ref settings 433#+begin_src emacs-lisp :noweb-ref settings
365 (setq-default minibuffer-prompt-properties 434 (setq-default minibuffer-prompt-properties
366 '(read-only t 435 '(read-only t
367 cursor-intangible t 436 cursor-intangible t
368 face minibuffer-prompt)) 437 face minibuffer-prompt))
369#+end_src 438#+end_src
370 439
371*** Enable a recursive minibuffer 440*** Enable a recursive minibuffer
@@ -401,8 +470,8 @@ to /hide/ those contents.
401 470
402#+begin_src emacs-lisp :noweb-ref 471#+begin_src emacs-lisp :noweb-ref
403 (setq-default completion-ignore-case t 472 (setq-default completion-ignore-case t
404 read-buffer-completion-ignore-case t 473 read-buffer-completion-ignore-case t
405 read-file-name-completion-ignore-case t) 474 read-file-name-completion-ignore-case t)
406#+end_src 475#+end_src
407 476
408* Persistence 477* Persistence
@@ -419,11 +488,11 @@ I keep all of it.
419 488
420#+begin_src emacs-lisp :noweb-ref modes 489#+begin_src emacs-lisp :noweb-ref modes
421 (setq-default savehist-additional-variables 490 (setq-default savehist-additional-variables
422 '(kill-ring 491 '(kill-ring
423 search-ring 492 search-ring
424 regexp-search-ring) 493 regexp-search-ring)
425 history-length t ; Don't truncate 494 history-length t ; Don't truncate
426 history-delete-duplicates t) 495 history-delete-duplicates t)
427#+end_src 496#+end_src
428 497
429#+begin_src emacs-lisp :noweb-ref modes 498#+begin_src emacs-lisp :noweb-ref modes
@@ -461,13 +530,21 @@ with that.
461 530
462#+begin_src emacs-lisp :noweb-ref settings 531#+begin_src emacs-lisp :noweb-ref settings
463 (setq-default recentf-max-menu-items 100 532 (setq-default recentf-max-menu-items 100
464 recentf-max-saved-items nil) 533 recentf-max-saved-items nil)
465#+end_src 534#+end_src
466 535
467#+begin_src emacs-lisp :noweb-ref modes 536#+begin_src emacs-lisp :noweb-ref modes
468 (recentf-mode +1) 537 (recentf-mode +1)
469#+end_src 538#+end_src
470 539
540I also want to ignore the =no-littering-var-directory= and
541=no-littering-etc-directory=, since those aren't useful.
542
543#+begin_src emacs-lisp :noweb-ref no-littering
544 (add-to-list 'recentf-exclude no-littering-var-directory)
545 (add-to-list 'recentf-exclude no-littering-etc-directory)
546#+end_src
547
471*** Save the recentf list periodically 548*** Save the recentf list periodically
472 549
473#+begin_src emacs-lisp :noweb-ref functions 550#+begin_src emacs-lisp :noweb-ref functions
@@ -477,14 +554,14 @@ with that.
477 "When we last saved the `recentf-save-list'.") 554 "When we last saved the `recentf-save-list'.")
478 555
479 (when (> (time-convert (time-since recentf--last-save) 'integer) 556 (when (> (time-convert (time-since recentf--last-save) 'integer)
480 (* 60 5)) 557 (* 60 5))
481 (setq-default recentf--last-save (time-convert nil 'integer)) 558 (setq-default recentf--last-save (time-convert nil 'integer))
482 (when-unfocused #'recentf-save-list))) 559 (when-unfocused #'recentf-save-list)))
483#+end_src 560#+end_src
484 561
485#+begin_src emacs-lisp :noweb-ref hooks 562#+begin_src emacs-lisp :noweb-ref hooks
486 (add-function :after after-focus-change-function 563 (add-function :after after-focus-change-function
487 #'maybe-save-recentf) 564 #'maybe-save-recentf)
488#+end_src 565#+end_src
489 566
490* Responsiveness 567* Responsiveness
@@ -500,6 +577,7 @@ the user is looking at something else.
500#+begin_src emacs-lisp :noweb-ref functions 577#+begin_src emacs-lisp :noweb-ref functions
501 (defun when-unfocused (func &rest args) 578 (defun when-unfocused (func &rest args)
502 "Run FUNC, with ARGS, iff all frames are out of focus." 579 "Run FUNC, with ARGS, iff all frames are out of focus."
580 (require 'seq)
503 (when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list))) 581 (when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list)))
504 (apply func args))) 582 (apply func args)))
505#+end_src 583#+end_src
@@ -519,7 +597,7 @@ It's 2020. Let's encode files like it is.
519 (set-keyboard-coding-system 'utf-8) 597 (set-keyboard-coding-system 'utf-8)
520 598
521 (setq-default buffer-file-coding-system 'utf-8 599 (setq-default buffer-file-coding-system 'utf-8
522 x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)) 600 x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
523#+end_src 601#+end_src
524 602
525*** UNIX-style line endings 603*** UNIX-style line endings
@@ -531,7 +609,7 @@ This function is from the [[https://www.emacswiki.org/emacs/EndOfLineTips][Emacs
531 "Convert line endings to UNIX, dammit." 609 "Convert line endings to UNIX, dammit."
532 (let ((coding-str (symbol-name buffer-file-coding-system))) 610 (let ((coding-str (symbol-name buffer-file-coding-system)))
533 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str) 611 (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
534 (set-buffer-file-coding-system 'unix)))) 612 (set-buffer-file-coding-system 'unix))))
535#+end_src 613#+end_src
536 614
537I add it to both =file-find-hook= /and/ =before-save-hook= because I'm 615I add it to both =file-find-hook= /and/ =before-save-hook= because I'm
@@ -546,16 +624,559 @@ Notepad can handle UNIX line endings, so I don't want to hear it.
546 624
547** Keep =~/.emacs.d= clean :package: 625** Keep =~/.emacs.d= clean :package:
548 626
627#+begin_src emacs-lisp :noweb-ref packages :noweb yes
628 (straight-use-package 'no-littering)
629 (require 'no-littering)
630 (with-eval-after-load 'no-littering
631 <<no-littering>>
632 ) ; end of no-littering
633#+end_src
634
635** Backups
636
637#+begin_src emacs-lisp :noweb-ref settings
638 (setq-default backup-by-copying t
639 ;; Don't delete old versions
640 delete-old-versions -1
641 ;; Make numeric backups unconditionally
642 version-control t
643 ;; Also backup files covered by version control
644 vc-make-backup-files t)
645#+end_src
646
647#+begin_src emacs-lisp :noweb-ref no-littering
648 (let ((dir (no-littering-expand-var-file-name "backup")))
649 (make-directory dir :parents)
650 (setq-default backup-directory-alist
651 `((".*" . ,dir))))
652#+end_src
653
654** Autosaves :package:
655
656I don't use the =auto-save= system, preferring instead to use
657Bozhidar Batsov's [[https://github.com/bbatsov/super-save][super-save]] package.
658
659#+begin_src emacs-lisp :noweb-ref settings
660 (setq-default auto-save-default nil)
661
662 (setq-default super-save-remote-files nil
663 super-save-exclude '(".gpg")
664 super-save-auto-save-when-idle t)
665#+end_src
666
667#+begin_src emacs-lisp :noweb-ref packages
668 (straight-use-package 'super-save)
669#+end_src
670
671#+begin_src emacs-lisp :noweb-ref modes
672 (super-save-mode +1)
673#+end_src
674
675** Auto-revert files
676
677I like to keep the buffers Emacs has in-memory in sync with the actual
678contents of the files the represent on-disk. Thus, we have
679=auto-revert-mode=.
680
681#+begin_src emacs-lisp :noweb-ref settings
682 (setq-default auto-revert-verbose nil)
683#+end_src
684
685#+begin_src emacs-lisp :noweb-ref modes
686 (global-auto-revert-mode +1)
687#+end_src
688
689
690* Editing
691
692** Lines
693
694*** Auto-fill vs. Visual-line
695
696I've mostly been using visual-line mode, and it's been pretty good.
697There are some times, however, when lines are just ... really long,
698and they wrap weird or whatever. Not to mention, in Org mode,
699=visual-line-mode= screws up the bindings for line movement. So
700here's what I'm going to do.
701
7021. Enable =visual-line-mode= with =text-mode=, but /not/ with
703 =org-mode=.
704
705 #+begin_src emacs-lisp :noweb-ref hooks
706 (defun hook--visual-line-mode ()
707 (unless (eq major-mode 'org-mode)
708 (visual-line-mode +1)))
709
710 (add-hook 'text-mode-hook #'hook--visual-line-mode)
711 #+end_src
712
7132. Enable =auto-fill-mode= with =org-mode=.
714
715 #+begin_src emacs-lisp :noweb-ref hooks
716 (add-hook 'org-mode-hook #'auto-fill-mode)
717 #+end_src
718
7193. /Just/ in case ... let's "fix" =visual-line-mode= if we're in =org-mode=.
720
721 #+begin_src emacs-lisp :noweb-ref hooks
722 (defun hook--visual-line-fix-org-keys ()
723 (when (derived-mode-p 'org-mode)
724 (local-set-key (kbd "C-a") #'org-beginning-of-line)
725 (local-set-key (kbd "C-e") #'org-end-of-line)
726 (local-set-key (kbd "C-k") #'org-kill-line)))
727
728 (add-hook 'visual-line-mode-hook #'hook--visual-line-fix-org-keys)
729
730 #+end_src
731
732I think that'll work -- I only care about line aesthetics with text.
733Programming modes should be /allowed/ to have long lines, regardless
734of how /terrible/ it is to have them.
735
736*** Stay snappy with long-lined files
737
738#+begin_src emacs-lisp :noweb-ref modes
739 (when (fboundp 'global-so-long-mode)
740 (global-so-long-mode +1))
741#+end_src
742
743** Whitespace
744
745*** Whitespace style
746
747The =whitespace-style= defines what kinds of whitespace to clean up on
748=whitespace-cleanup=, as well as what to highlight (if that option is
749enabled).
750
751#+begin_src emacs-lisp :noweb-ref settings
752 (setq-default whitespace-style '(empty ; remove blank lines at buffer edges
753 indentation ; clean up indentation
754 ;; fix mixed spaces and tabs
755 space-before-tab
756 space-after-tab))
757#+end_src
758
759*** Clean up whitespace on save
760
761#+begin_src emacs-lisp :noweb-ref hooks
762 (add-hook 'before-save-hook #'whitespace-cleanup)
763#+end_src
764
765*** Don't use TABs
766
767I was team TAB for a while, but I find them easier to avoid in Emacs.
768It manages my whitespace for me, anyway.
769
770#+begin_src emacs-lisp :noweb-ref settings
771 (setq-default indent-tabs-mode nil)
772#+end_src
773
774** Killing & Yanking
775
776*** Replace the selection when typing
777
778#+begin_src emacs-lisp :noweb-ref modes
779 (delete-selection-mode +1)
780#+end_src
781
782*** Work better with the system clipboard
783
784#+begin_src emacs-lisp :noweb-ref settings
785 (setq-default
786 ;; Save existing clipboard text to the kill ring before replacing it.
787 save-interprogram-paste-before-kill t
788 ;; Update the X selection when rotating the kill ring.
789 yank-pop-change-selection t
790 ;; Enable clipboards
791 x-select-enable-clipboard t
792 x-select-enable-primary t
793 ;; Copy a region when it's selected with the mouse
794 mouse-drag-copy-region t)
795#+end_src
796
797*** Don't append the same thing twice to the kill ring
798
799#+begin_src emacs-lisp :noweb-ref settings
800 (setq-default kill-do-not-save-duplicates t)
801#+end_src
802
803** Overwrite mode
804
805*** Change the cursor
806
807#+begin_src emacs-lisp :noweb-ref hooks
808 (defun hook--overwrite-mode-change-cursor ()
809 (setq cursor-type (if overwrite-mode t 'bar)))
810
811 (add-hook 'overwrite-mode-hook #'hook--overwrite-mode-change-cursor)
812#+end_src
813
814** The Mark
815
816*** Repeat popping the mark without repeating the prefix argument
817
818#+begin_src emacs-lisp :noweb-ref settings
819 (setq-default set-mark-repeat-command-pop t)
820#+end_src
821
822* Writing
823
824** Word count :package:
825
826#+begin_src emacs-lisp :noweb-ref packages
827 (straight-use-package 'wc-mode)
828#+end_src
829
830#+begin_src emacs-lisp :noweb-ref hooks
831 (add-hook 'text-mode-hook #'wc-mode)
832#+end_src
833
834* Programming
835
836** Comments
837
838*** Auto fill comments in programming modes
839
840Okay, so I lied in the [[*Auto-fill vs. Visual-line][Auto-fill vs. Visual-line]] section. I /do/ want
841to auto-fill in programming modes, but /only/ the comments.
842
843#+begin_src emacs-lisp :noweb-ref hooks
844 (defun hook--comment-auto-fill ()
845 (setq-local comment-auto-fill-only-comments t)
846 (auto-fill-mode +1))
847
848 (add-hook 'prog-mode-hook #'hook--comment-auto-fill)
849#+end_src
850
851** Parentheses
852
853*** Show parentheses
854
855#+begin_src emacs-lisp :noweb-ref modes
856 (show-paren-mode +1)
857#+end_src
858
859#+begin_src emacs-lisp :noweb-ref settings
860 (setq-default show-paren-delay 0
861 ;; Show the matching paren if visible, else the whole expression
862 show-paren-style 'mixed)
863#+end_src
864
865** Executable scripts
866
867This poorly-named function will make a file executable if it looks
868like a script (looking at the function definition, it looks like it
869checks for a shebang).
870
871#+begin_src emacs-lisp :noweb-ref hooks
872 (add-hook 'after-save-hook
873 #'executable-make-buffer-file-executable-if-script-p)
874#+end_src
875
876** Language-specific
877
878*** Emacs Lisp
879
880**** Don't limit the length of evaluated expressions
881
882#+begin_src emacs-lisp :noweb-ref settings
883 (setq-default eval-expression-print-length nil
884 eval-expression-print-level nil)
885#+end_src
886
887**** Indent Elisp like Common Lisp
888
889#+begin_src emacs-lisp :noweb-ref requires
890 (require 'cl-lib)
891#+end_src
892
893#+begin_src emacs-lisp :noweb-ref settings
894 (setq-default lisp-indent-function #'common-lisp-indent-function)
895#+end_src
896
897
898* Applications
899
900Emacs is well-known for its ability to subsume one's entire computing
901life. There are a few /killer apps/ that make Emacs really shine.
902Here, I configure them and a few others.
903
904My rubric for what makes a package an application, versus just a
905package, is mostly based on the way I feel about it. Don't expect to
906agree with all of my choices.
907
908** Web browsing
909
910*** Browse-url
911
912I like using Firefox.
913
914#+begin_src emacs-lisp :noweb-ref settings
915 (setq-default browse-url-browser-function 'browse-url-firefox
916 browse-url-new-window-flag t
917 browse-url-firefox-new-window-is-tab t)
918#+end_src
919
920At work, I need to tell Emacs where Firefox is.
921
922#+begin_src emacs-lisp :noweb-ref windows-specific
923 (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")
924#+end_src
925
926** Dired
927
928#+begin_src emacs-lisp :noweb-ref hooks
929 (defun hook--dired-mode ()
930 (hl-line-mode +1)
931 (dired-hide-details-mode +1))
932
933 (add-hook 'dired-mode-hook #'hook--dired-mode)
934#+end_src
935
936A note on =dired-listing-switches=: when I'm able to figure out how to
937move up a directory with a keybinding, I'll change =-a= to =-A=.
938
939#+begin_src emacs-lisp :noweb-ref settings
940 (setq-default dired-recursive-copies 'always
941 dired-recursive-deletes 'always
942 delete-by-moving-to-trash t
943 dired-listing-switches "-alh")
944#+end_src
945
946*** Expand subtrees :package:
947
948Instead of opening each folder in its own buffer, =dired-subtree=
949enables me to open them in the same buffer, fancily indented.
950
951#+begin_src emacs-lisp :noweb-ref packages
952 (straight-use-package 'dired-subtree)
953#+end_src
954
955#+begin_src emacs-lisp :noweb-ref bindings
956 (with-eval-after-load 'dired
957 (define-key dired-mode-map "i" #'dired-subtree-toggle))
958#+end_src
959
960*** Collapse singleton directories
961
962If a directory only has one item in it, =dired-collapse= shows what
963that one item is.
964
965#+begin_src emacs-lisp :noweb-ref packages
966 (straight-use-package 'dired-subtree)
967#+end_src
968
969#+begin_src emacs-lisp :noweb-ref hooks
970 (add-hook 'dired-mode-hook #'dired-collapse-mode)
971#+end_src
972
973** Org mode
974
975#+begin_src emacs-lisp :noweb-ref packages
976 (straight-use-package 'org)
977
978 (with-eval-after-load 'org
979 (require 'org-tempo)
980 (require 'ox-md))
981#+end_src
982
983#+begin_src emacs-lisp :noweb-ref settings
984 (setq-default
985 ;; Where to look for Org files
986 org-directory "~/org" ; this is the default
987 ;; Fontify stuff
988 org-hide-emphasis-markers t
989 org-fontify-whole-heading-line t
990 org-fontify-done-headline t
991 org-fontify-quote-and-verse-blocks t
992 org-src-fontify-natively t
993 org-ellipsis "…"
994 org-pretty-entities t
995 ;; Source blocks
996 org-src-tab-acts-natively t
997 org-src-window-setup 'current-window ; could change this
998 org-confirm-babel-evaluate nil
999 ;; Behavior
1000 org-adapt-indentation nil ; don't indent things
1001 org-catch-invisible-edits 'smart ; let's try this
1002 org-special-ctrl-a/e t
1003 org-special-ctrl-k t
1004 ;; Exporting
1005 org-export-headline-levels 8)
1006#+end_src
1007
1008*** Org templates
1009
1010#+begin_src emacs-lisp :noweb-ref settings
1011 (with-eval-after-load 'org-tempo
1012 (dolist (cell '(("el" . "src emacs-lisp")
1013 ("cr" . "src emacs-lisp :noweb-ref requires")
1014 ("cf" . "src emacs-lisp :noweb-ref functions")
1015 ("cs" . "src emacs-lisp :noweb-ref settings")
1016 ("cm" . "src emacs-lisp :noweb-ref modes")
1017 ("cl" . "src emacs-lisp :noweb-ref linux-specific")
1018 ("cw" . "src emacs-lisp :noweb-ref windows-specific")
1019 ("cp" . "src emacs-lisp :noweb-ref packages")
1020 ("ch" . "src emacs-lisp :noweb-ref hooks")
1021 ("cb" . "src emacs-lisp :noweb-ref bindings")
1022 ("cnl" . "src emacs-lisp :noweb-ref no-littering")))
1023 (add-to-list 'org-structure-template-alist cell)))
1024#+end_src
1025
1026*** Org Return: DWIM :unpackaged:
1027
1028#+begin_src emacs-lisp :noweb-ref functions
1029 (defun unpackaged/org-element-descendant-of (type element)
1030 "Return non-nil if ELEMENT is a descendant of TYPE.
1031 TYPE should be an element type, like `item' or `paragraph'.
1032 ELEMENT should be a list like that returned by `org-element-context'."
1033 ;; MAYBE: Use `org-element-lineage'.
1034 (when-let* ((parent (org-element-property :parent element)))
1035 (or (eq type (car parent))
1036 (unpackaged/org-element-descendant-of type parent))))
1037
1038 (defun unpackaged/org-return-dwim (&optional default)
1039 "A helpful replacement for `org-return'. With prefix, call `org-return'.
1040
1041 On headings, move point to position after entry content. In
1042 lists, insert a new item or end the list, with checkbox if
1043 appropriate. In tables, insert a new row or end the table."
1044 ;; Inspired by John Kitchin: http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/
1045 (interactive "P")
1046 (if default
1047 (org-return)
1048 (cond
1049 ;; Act depending on context around point.
1050
1051 ;; NOTE: I prefer RET to not follow links, but by uncommenting this block, links will be
1052 ;; followed.
1053
1054 ;; ((eq 'link (car (org-element-context)))
1055 ;; ;; Link: Open it.
1056 ;; (org-open-at-point-global))
1057
1058 ((org-at-heading-p)
1059 ;; Heading: Move to position after entry content.
1060 ;; NOTE: This is probably the most interesting feature of this function.
1061 (let ((heading-start (org-entry-beginning-position)))
1062 (goto-char (org-entry-end-position))
1063 (cond ((and (org-at-heading-p)
1064 (= heading-start (org-entry-beginning-position)))
1065 ;; Entry ends on its heading; add newline after
1066 (end-of-line)
1067 (insert "\n\n"))
1068 (t
1069 ;; Entry ends after its heading; back up
1070 (forward-line -1)
1071 (end-of-line)
1072 (when (org-at-heading-p)
1073 ;; At the same heading
1074 (forward-line)
1075 (insert "\n")
1076 (forward-line -1))
1077 ;; FIXME: looking-back is supposed to be called with more arguments.
1078 (while (not (looking-back (rx (repeat 3 (seq (optional blank) "\n"))) nil))
1079 (insert "\n"))
1080 (forward-line -1)))))
1081
1082 ((org-at-item-checkbox-p)
1083 ;; Checkbox: Insert new item with checkbox.
1084 (org-insert-todo-heading nil))
1085
1086 ((org-in-item-p)
1087 ;; Plain list. Yes, this gets a little complicated...
1088 (let ((context (org-element-context)))
1089 (if (or (eq 'plain-list (car context)) ; First item in list
1090 (and (eq 'item (car context))
1091 (not (eq (org-element-property :contents-begin context)
1092 (org-element-property :contents-end context))))
1093 (unpackaged/org-element-descendant-of 'item context)) ; Element in list item, e.g. a link
1094 ;; Non-empty item: Add new item.
1095 (org-insert-item)
1096 ;; Empty item: Close the list.
1097 ;; TODO: Do this with org functions rather than operating on the text. Can't seem to find the right function.
1098 (delete-region (line-beginning-position) (line-end-position))
1099 (insert "\n"))))
1100
1101 ((when (fboundp 'org-inlinetask-in-task-p)
1102 (org-inlinetask-in-task-p))
1103 ;; Inline task: Don't insert a new heading.
1104 (org-return))
1105
1106 ((org-at-table-p)
1107 (cond ((save-excursion
1108 (beginning-of-line)
1109 ;; See `org-table-next-field'.
1110 (cl-loop with end = (line-end-position)
1111 for cell = (org-element-table-cell-parser)
1112 always (equal (org-element-property :contents-begin cell)
1113 (org-element-property :contents-end cell))
1114 while (re-search-forward "|" end t)))
1115 ;; Empty row: end the table.
1116 (delete-region (line-beginning-position) (line-end-position))
1117 (org-return))
1118 (t
1119 ;; Non-empty row: call `org-return'.
1120 (org-return))))
1121 (t
1122 ;; All other cases: call `org-return'.
1123 (org-return)))))
1124#+end_src
1125
1126#+begin_src emacs-lisp :noweb-ref bindings
1127 (with-eval-after-load 'org
1128 (define-key org-mode-map (kbd "RET") #'unpackaged/org-return-dwim))
1129#+end_src
1130
1131
549* Package management :package: 1132* Package management :package:
550:PROPERTIES: 1133:PROPERTIES:
551:header-args: :noweb-ref package-bootstrap 1134:header-args: :noweb-ref early-init-package
552:END: 1135:END:
553 1136
554Emacs is the /extensible/ editor, and that means I want to use 1137Emacs is the /extensible/ editor, and that means I want to use
555third-party packages. Of course, first I have to /manage/ those 1138third-party packages. Of course, first I have to /manage/ those
556packages. I use the excellent =straight.el=. 1139packages. I use the excellent =straight.el=.
557 1140
558** TODO Update the PATH 1141** Update the PATH
1142
1143PATH handling on Emacs is a little complicated. There's the regular
1144environment variable =$PATH=, which we all know and love, and then
1145Emacs has its own special =exec-path= on /top/ of that. From my
1146research, it looks like Emacs uses =exec-path= for itself, and =$PATH=
1147for any shells or other processes it spawns. They don't /have/ to be
1148the same, but luckily for us, Emacs sets =exec-path= from =$PATH= on
1149initialization, so when I add stuff to =exec-path= to, say, run git, I
1150can just change =$PATH= right back to the expanded =exec-path= without
1151any data loss. Here's what all that looks like.
1152
1153#+begin_src emacs-lisp
1154 (let ((win-app-dir "~/Applications"))
1155 (dolist (path (list
1156 ;; Windows
1157 (expand-file-name "Git/bin" win-app-dir)
1158 (expand-file-name "Git/usr/bin" win-app-dir)
1159 (expand-file-name "Git/mingw64/bin" win-app-dir)
1160 ;; Linux
1161 (expand-file-name "bin"
1162 user-emacs-directory)
1163 (expand-file-name "~/bin")
1164 (expand-file-name "~/.local/bin")
1165 (expand-file-name "~/Scripts")
1166 ))
1167 (when (file-exists-p path)
1168 (add-to-list 'exec-path path :append))))
1169
1170 ;; Set $PATH
1171 (setenv "PATH" (mapconcat #'identity exec-path path-separator))
1172#+end_src
1173
1174*** References
1175
1176- [[https://emacs.stackexchange.com/questions/550/exec-path-and-path][exec-path and $PATH (StackExchange)]]
1177- [[https://utoi.tistory.com/entry/Difference-Between-Emacss-%E2%80%9Cgetenv-PATH%E2%80%9D-and-%E2%80%9Cexec-path%E2%80%9D][Difference between Emacs's "(getenv PATH)" and "exec-path" (U&I)]]
1178- [[https://emacs.stackexchange.com/questions/27326/gui-emacs-sets-the-exec-path-only-from-windows-environment-variable-but-not-from][GUI Emacs sets the exec-path only from Windows environment variable
1179 but not from .emacs file (StackExchange)]]
559 1180
560** Disable =package.el= 1181** Disable =package.el=
561 1182
@@ -573,19 +1194,19 @@ function so I can call it in another wrapper.
573 "Bootstrap straight.el." 1194 "Bootstrap straight.el."
574 (defvar bootstrap-version) 1195 (defvar bootstrap-version)
575 (let ((bootstrap-file 1196 (let ((bootstrap-file
576 (expand-file-name 1197 (expand-file-name
577 "straight/repos/straight.el/bootstrap.el" 1198 "straight/repos/straight.el/bootstrap.el"
578 user-emacs-directory)) 1199 user-emacs-directory))
579 (bootstrap-version 5)) 1200 (bootstrap-version 5))
580 (unless (file-exists-p bootstrap-file) 1201 (unless (file-exists-p bootstrap-file)
581 (with-current-buffer 1202 (with-current-buffer
582 (url-retrieve-synchronously 1203 (url-retrieve-synchronously
583 (concat 1204 (concat
584 "https://raw.githubusercontent.com/" 1205 "https://raw.githubusercontent.com/"
585 "raxod502/straight.el/develop/install.el") 1206 "raxod502/straight.el/develop/install.el")
586 'silent 'inhibit-cookies) 1207 'silent 'inhibit-cookies)
587 (goto-char (point-max)) 1208 (goto-char (point-max))
588 (eval-print-last-sexp))) 1209 (eval-print-last-sexp)))
589 (load bootstrap-file nil 'nomessage))) 1210 (load bootstrap-file nil 'nomessage)))
590#+end_src 1211#+end_src
591 1212
@@ -594,17 +1215,18 @@ directly. If it errors (it tends to on Windows), I'll directly clone
594the repo using git, /then/ run the bootstrap code. 1215the repo using git, /then/ run the bootstrap code.
595 1216
596#+begin_src emacs-lisp 1217#+begin_src emacs-lisp
597 (unless (ignore-errors (acdw/bootstrap-straight)) 1218 (when (executable-find "git")
598 (let ((msg "Straight.el didn't bootstrap correctly. Cloning directly")) 1219 (unless (ignore-errors (acdw/bootstrap-straight))
599 (message "%s..." msg) 1220 (let ((msg "Straight.el didn't bootstrap correctly. Cloning directly"))
600 (call-process "git" nil 1221 (message "%s..." msg)
601 (get-buffer-create "*bootstrap-straight-messages*") nil 1222 (call-process "git" nil
602 "clone" 1223 (get-buffer-create "*bootstrap-straight-messages*") nil
603 "https://github.com/raxod502/straight.el" 1224 "clone"
604 (expand-file-name "straight/repos/straight.el" 1225 "https://github.com/raxod502/straight.el"
605 user-emacs-directory)) 1226 (expand-file-name "straight/repos/straight.el"
606 (message "%s...Done." msg) 1227 user-emacs-directory))
607 (acdw/bootstrap-straight))) 1228 (message "%s...Done." msg)
1229 (acdw/bootstrap-straight))))
608#+end_src 1230#+end_src
609 1231
610* System-specific 1232* System-specific
@@ -615,9 +1237,13 @@ settings and written some ancillary scripts.
615 1237
616** Determine where I am 1238** Determine where I am
617:PROPERTIES: 1239:PROPERTIES:
618:header-args: :noweb-ref functions 1240:header-args: :noweb-ref when-at
619:END: 1241:END:
620 1242
1243This macro needs to go into =init.el=, /before/ loading =config.el= --
1244because I've used the =when-at= form in the =:tangle= directive for
1245the scripts in this section.
1246
621#+begin_src emacs-lisp 1247#+begin_src emacs-lisp
622 (defmacro when-at (conditions &rest commands) 1248 (defmacro when-at (conditions &rest commands)
623 "Run COMMANDS, or let the user know, when at a specific place. 1249 "Run COMMANDS, or let the user know, when at a specific place.
@@ -629,20 +1255,20 @@ settings and written some ancillary scripts.
629 If COMMANDS is empty or nil, simply return the result of CONDITIONS." 1255 If COMMANDS is empty or nil, simply return the result of CONDITIONS."
630 (declare (indent 1)) 1256 (declare (indent 1))
631 (let ((at-work '(memq system-type '(ms-dos windows-nt))) 1257 (let ((at-work '(memq system-type '(ms-dos windows-nt)))
632 (at-home '(memq system-type '(gnu gnu/linux gnu/kfreebsd)))) 1258 (at-home '(memq system-type '(gnu gnu/linux gnu/kfreebsd))))
633 (pcase conditions 1259 (pcase conditions
634 (:work (if commands `(when ,at-work ,@commands) at-work)) 1260 (:work (if commands `(when ,at-work ,@commands) at-work))
635 (:home (if commands `(when ,at-home ,@commands) at-home)) 1261 (:home (if commands `(when ,at-home ,@commands) at-home))
636 ((guard (eq (car conditions) :work)) 1262 ((guard (eq (car conditions) :work))
637 (if commands 1263 (if commands
638 `(when (and ,at-work ,@(cdr conditions)) 1264 `(when (and ,at-work ,@(cdr conditions))
639 ,@commands) 1265 ,@commands)
640 `(and ,at-work ,@(cdr conditions)))) 1266 `(and ,at-work ,@(cdr conditions))))
641 ((guard (eq (car conditions) :home)) 1267 ((guard (eq (car conditions) :home))
642 (if commands 1268 (if commands
643 `(when (and ,at-home ,@(cdr conditions)) 1269 `(when (and ,at-home ,@(cdr conditions))
644 ,@commands) 1270 ,@commands)
645 `(and ,at-work ,@(cdr conditions))))))) 1271 `(and ,at-work ,@(cdr conditions)))))))
646#+end_src 1272#+end_src
647 1273
648** Linux (home) 1274** Linux (home)
@@ -663,7 +1289,7 @@ Here's a wrapper script that'll start =emacs --daemon= if there isn't
663one, and then launch =emacsclient= with the arguments. Install it to 1289one, and then launch =emacsclient= with the arguments. Install it to
664your =$PATH= somewhere. 1290your =$PATH= somewhere.
665 1291
666#+begin_src sh :shebang "#!/bin/sh" :tangle (when-at :home "~/bin/em") 1292#+begin_src sh :shebang "#!/bin/sh" :tangle (if (eq system-type 'gnu/linux) "~/bin/em" "")
667 if ! emacsclient -nc "$@"; then 1293 if ! emacsclient -nc "$@"; then
668 emacs --daemon 1294 emacs --daemon
669 emacsclient -nc "$@" 1295 emacsclient -nc "$@"
@@ -678,7 +1304,7 @@ your =$PATH= somewhere.
678I haven't really tested this yet, but it should allow me to open other 1304I haven't really tested this yet, but it should allow me to open other
679files and things in Emacs. From [[https://www.taingram.org/blog/emacs-client.html][taingram]]. 1305files and things in Emacs. From [[https://www.taingram.org/blog/emacs-client.html][taingram]].
680 1306
681#+begin_src conf-desktop :tangle (when-at :home "~/.local/share/applications/emacsclient.desktop") 1307#+begin_src conf-desktop :tangle (if (eq system-type 'gnu/linux) "~/.local/share/applications/emacsclient.desktop" "")
682 [Desktop Entry] 1308 [Desktop Entry]
683 Name=Emacs Client 1309 Name=Emacs Client
684 GenericName=Text Editor 1310 GenericName=Text Editor
@@ -713,10 +1339,10 @@ section come from [[https://github.com/termitereform/JunkPile/blob/master/emacs-
713 1339
714**** Common variables 1340**** Common variables
715 1341
716#+NAME: w32-bat-common 1342#+begin_src bat :noweb-ref w32-bat-common
717#+begin_src bat
718set HOME=%~dp0..\.. 1343set HOME=%~dp0..\..
719set EMACS=%HOME%\Applications\Emacs\bin\runemacs.exe 1344set EMACS=%HOME%\Applications\Emacs\bin\runemacs.exe
1345chdir %HOME%
720#+end_src 1346#+end_src
721 1347
722**** Emacs Daemon 1348**** Emacs Daemon
@@ -725,7 +1351,7 @@ Either run this once at startup, or put a shortcut of it in the
725Startup folder: 1351Startup folder:
726=%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup=. 1352=%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup=.
727 1353
728#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Daemon.cmd") 1354#+begin_src bat :tangle (if (eq system-type 'windows-nt) "~/Applications/cmd/Emacs Daemon.cmd" "")
729<<w32-bat-common>> 1355<<w32-bat-common>>
730%EMACS% --daemon 1356%EMACS% --daemon
731#+end_src 1357#+end_src
@@ -737,7 +1363,7 @@ run =runemacs.exe=.
737 1363
738*This is the main shortcut for running Emacs.* 1364*This is the main shortcut for running Emacs.*
739 1365
740#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs.cmd") 1366#+begin_src bat :tangle (if (eq system-type 'windows-nt) "~/Applications/cmd/Emacs.cmd" "")
741<<w32-bat-common>> 1367<<w32-bat-common>>
742set EMACSC=%HOME%\Applications\Emacs\bin\emacsclientw.exe 1368set EMACSC=%HOME%\Applications\Emacs\bin\emacsclientw.exe
743"%EMACSC%" -n -c -a "%EMACS%" %* 1369"%EMACSC%" -n -c -a "%EMACS%" %*
@@ -747,7 +1373,7 @@ set EMACSC=%HOME%\Applications\Emacs\bin\emacsclientw.exe
747 1373
748This runs Emacs with the factory settings. 1374This runs Emacs with the factory settings.
749 1375
750#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Safe Start.cmd") 1376#+begin_src bat :tangle (if (eq system-type 'windows-nt) "~/Applications/cmd/Emacs Safe Start.cmd" "")
751<<w32-bat-common>> 1377<<w32-bat-common>>
752"%EMACS%" -Q %* 1378"%EMACS%" -Q %*
753#+end_src 1379#+end_src
@@ -756,7 +1382,7 @@ This runs Emacs with the factory settings.
756 1382
757This runs Emacs with the =--debug-init= option enabled. 1383This runs Emacs with the =--debug-init= option enabled.
758 1384
759#+begin_src bat :tangle (when-at :work "~/Applications/cmd/Emacs Debug.cmd") 1385#+begin_src bat :tangle (if (eq system-type 'windows-nt) "~/Applications/cmd/Emacs Debug.cmd" "")
760<<w32-bat-common>> 1386<<w32-bat-common>>
761"%EMACS%" --debug-init %* 1387"%EMACS%" --debug-init %*
762#+end_src 1388#+end_src
@@ -794,20 +1420,25 @@ my config here /logically/, while keeping the generated file organized
794 ;;; REQUIRES 1420 ;;; REQUIRES
795 <<requires>> 1421 <<requires>>
796 ;;; PACKAGES 1422 ;;; PACKAGES
797 <<packages>> 1423 ;; straight.el depends on git, which /should be/ find-able by the PATH
1424 ;; manipulation in early-init.el. Just in case, though, we'll check
1425 ;; that we can find git.
1426 (when (executable-find "git")
1427 <<packages>>
1428 )
798 ;;; FUNCTIONS 1429 ;;; FUNCTIONS
799 <<functions>> 1430 <<functions>>
800 ;;; SETTINGS 1431 ;;; SETTINGS
801 <<settings>> 1432 <<settings>>
802 ;;; MODES
803 <<modes>>
804 ;;; SYSTEM-DEPENDENT SETTINGS 1433 ;;; SYSTEM-DEPENDENT SETTINGS
805 (when-at :home 1434 (when-at :home
806 <<linux-specific>> 1435 <<linux-specific>>
807 ) 1436 ) ; end when-at :home
808 (when-at :work 1437 (when-at :work
809 <<windows-specific>> 1438 <<windows-specific>>
810 ) 1439 ) ; end when-at :work
1440 ;;; MODES
1441 <<modes>>
811 ;;; HOOKS 1442 ;;; HOOKS
812 <<hooks>> 1443 <<hooks>>
813 ;;; BINDINGS 1444 ;;; BINDINGS
@@ -836,6 +1467,14 @@ The classic Emacs initiation file.
836 (setq-default load-prefer-newer t) 1467 (setq-default load-prefer-newer t)
837#+end_src 1468#+end_src
838 1469
1470**** =when-at=
1471
1472See [[*Determine where I am][the definition above]] for rationale as to why this is here.
1473
1474#+begin_src emacs-lisp
1475 <<when-at>>
1476#+end_src
1477
839**** Load the config 1478**** Load the config
840 1479
841I keep most of my config in =config.el=, which is tangled directly 1480I keep most of my config in =config.el=, which is tangled directly
@@ -844,28 +1483,28 @@ directly from Org if it's newer.
844 1483
845#+begin_src emacs-lisp 1484#+begin_src emacs-lisp
846 (let* (;; Speed up init 1485 (let* (;; Speed up init
847 (gc-cons-threshold most-positive-fixnum) 1486 (gc-cons-threshold most-positive-fixnum)
848 (file-name-handler-alist nil) 1487 (file-name-handler-alist nil)
849 ;; Config file names 1488 ;; Config file names
850 (config (expand-file-name "config" 1489 (config (expand-file-name "config"
851 user-emacs-directory)) 1490 user-emacs-directory))
852 (config.el (concat config ".el")) 1491 (config.el (concat config ".el"))
853 (config.org (concat config ".org")) 1492 (config.org (concat config ".org"))
854 (straight-org-dir (expand-file-name "straight/build/org" 1493 (straight-org-dir (expand-file-name "straight/build/org"
855 user-emacs-directory))) 1494 user-emacs-directory)))
856 ;; Unless config.org is /newer/ than config.el, *or* the config 1495 ;; Unless config.org is /newer/ than config.el, *or* the config
857 ;; is able to be loaded without errors, load the config from 1496 ;; is able to be loaded without errors, load the config from
858 ;; config.org. 1497 ;; config.org.
859 (unless (or (file-newer-than-file-p config.org config.el) 1498 (unless (or (file-newer-than-file-p config.org config.el)
860 (load config 'no-error)) 1499 (load config 'no-error))
861 ;; A plain require here just loads the older `org' 1500 ;; A plain require here just loads the older `org'
862 ;; in Emacs' install dir. We need to add the newer 1501 ;; in Emacs' install dir. We need to add the newer
863 ;; one to the `load-path', hopefully that's all. 1502 ;; one to the `load-path', hopefully that's all.
864 (when (file-exists-p straight-org-dir) 1503 (when (file-exists-p straight-org-dir)
865 (add-to-list 'load-path straight-org-dir)) 1504 (add-to-list 'load-path straight-org-dir))
866 ;; Load config.org 1505 ;; Load config.org
867 (require 'org) 1506 (require 'org)
868 (org-babel-load-file config.org))) 1507 (org-babel-load-file config.org)))
869#+end_src 1508#+end_src
870 1509
871*** early-init.el 1510*** early-init.el
@@ -877,46 +1516,13 @@ Beginning with 27.1, Emacs also loads an =early-init.el= file, before
877the package manager or the UI code. The Info says we should put as 1516the package manager or the UI code. The Info says we should put as
878little as possible in this file, so I only have what I need. 1517little as possible in this file, so I only have what I need.
879 1518
880**** Don't byte-compile this file
881
882#+begin_src emacs-lisp 1519#+begin_src emacs-lisp
883 ;; early-init.el -*- no-byte-compile: t; -*- 1520 ;; early-init.el -*- no-byte-compile: t; -*-
884 <<disclaimer>> 1521 <<disclaimer>>
885#+end_src 1522 ;; BOOTSTRAP PACKAGE MANAGEMENT
886 1523 <<early-init-package>>
887**** Package management 1524 ;; SETUP FRAME
888 1525 <<early-init-frame>>
889Since =early-init.el= loads before the built-in package manager
890initializes, I disable it and bootstrap my package manager of choice,
891=straight.el=.
892
893#+begin_src emacs-lisp
894 <<package-bootstrap>>
895#+end_src
896
897**** Don't resize the frame when loading fonts
898
899#+begin_src emacs-lisp
900 (setq-default frame-inhibit-implied-resize t)
901#+end_src
902
903**** Resize frame by pixels
904
905#+begin_src emacs-lisp
906 (setq-default frame-resize-pixelwise t)
907#+end_src
908
909**** Shoe-horned from elsewhere in =config.org=
910
911A fundamental tension of literal programming is logical versus
912programmatic ordering. I understand that's a problem it's meant to
913solve but hey, maybe I'm not quite there yet. I feel that having this
914weird shoe-horning of other bits of my config here, in a backwater
915heading in an appendix, isn't quite the future I wanted. But it's
916what I have for now.
917
918#+begin_src emacs-lisp
919 <<initial-frame-setup>>
920#+end_src 1526#+end_src
921 1527
922** License 1528** License
@@ -924,7 +1530,7 @@ what I have for now.
924:header-args: :tangle LICENSE 1530:header-args: :tangle LICENSE
925:END: 1531:END:
926 1532
927Copyright © 2020 Case Duckworth <acdw@acdw.net> 1533Copyright © 2020 Case Duckworth <acdw@acdw.net>
928 1534
929This work is free. You can redistribute it and/or modify it under the 1535This work is free. You can redistribute it and/or modify it under the
930terms of the Do What the Fuck You Want To Public License, Version 2, 1536terms of the Do What the Fuck You Want To Public License, Version 2,
@@ -954,33 +1560,3 @@ It's highly likely that the WTFPL is completely incompatible with the
954GPL, for what should be fairly obvious reasons. To that, I say: 1560GPL, for what should be fairly obvious reasons. To that, I say:
955 1561
956*SUE ME, RMS!* 1562*SUE ME, RMS!*
957
958** Make it easier to edit =config.org= :noexport:
959
960Because I use a lot of =:noweb-ref= directives in this file, editing
961it can be annoying -- I need some nice templates. Run this code block
962with =C-c C-c=.
963
964#+begin_src emacs-lisp :results output silent
965 (require 'org-tempo)
966
967 (dolist (cell '(("el" . "src emacs-lisp")
968 ("cr" . "src emacs-lisp :noweb-ref requires")
969 ("cf" . "src emacs-lisp :noweb-ref functions")
970 ("cs" . "src emacs-lisp :noweb-ref settings")
971 ("cm" . "src emacs-lisp :noweb-ref modes")
972 ("cl" . "src emacs-lisp :noweb-ref linux-specific")
973 ("cw" . "src emacs-lisp :noweb-ref windows-specific")
974 ("cp" . "src emacs-lisp :noweb-ref packages")
975 ("ch" . "src emacs-lisp :noweb-ref hooks")
976 ("cb" . "src emacs-lisp :noweb-ref bindings")))
977 (add-to-list 'org-structure-template-alist cell))
978#+end_src
979
980** Local variables :noexport:
981
982# Local variables:
983# org-adapt-indentation: nil
984# lisp-indent-function: 'common-lisp-indent-function
985# eval: (auto-fill-mode +1)
986# End:
diff --git a/early-init.el b/early-init.el index 103e0b4..5ebc544 100644 --- a/early-init.el +++ b/early-init.el
@@ -1,53 +1,70 @@
1;; early-init.el -*- no-byte-compile: t; -*- 1;; early-init.el -*- no-byte-compile: t; -*-
2;; This file is automatically tangled from config.org. 2;; This file is automatically tangled from config.org.
3;; Hand edits will be overwritten! 3;; Hand edits will be overwritten!
4;; BOOTSTRAP PACKAGE MANAGEMENT
5(let ((win-app-dir "~/Applications"))
6 (dolist (path (list
7 ;; Windows
8 (expand-file-name "Git/bin" win-app-dir)
9 (expand-file-name "Git/usr/bin" win-app-dir)
10 (expand-file-name "Git/mingw64/bin" win-app-dir)
11 ;; Linux
12 (expand-file-name "bin"
13 user-emacs-directory)
14 (expand-file-name "~/bin")
15 (expand-file-name "~/.local/bin")
16 (expand-file-name "~/Scripts")
17 ))
18 (when (file-exists-p path)
19 (add-to-list 'exec-path path :append))))
4 20
21;; Set $PATH
22(setenv "PATH" (mapconcat #'identity exec-path path-separator))
5(setq package-enable-at-startup nil) 23(setq package-enable-at-startup nil)
6(defun acdw/bootstrap-straight () 24(defun acdw/bootstrap-straight ()
7 "Bootstrap straight.el." 25 "Bootstrap straight.el."
8 (defvar bootstrap-version) 26 (defvar bootstrap-version)
9 (let ((bootstrap-file 27 (let ((bootstrap-file
10 (expand-file-name 28 (expand-file-name
11 "straight/repos/straight.el/bootstrap.el" 29 "straight/repos/straight.el/bootstrap.el"
12 user-emacs-directory)) 30 user-emacs-directory))
13 (bootstrap-version 5)) 31 (bootstrap-version 5))
14 (unless (file-exists-p bootstrap-file) 32 (unless (file-exists-p bootstrap-file)
15 (with-current-buffer 33 (with-current-buffer
16 (url-retrieve-synchronously 34 (url-retrieve-synchronously
17 (concat 35 (concat
18 "https://raw.githubusercontent.com/" 36 "https://raw.githubusercontent.com/"
19 "raxod502/straight.el/develop/install.el") 37 "raxod502/straight.el/develop/install.el")
20 'silent 'inhibit-cookies) 38 'silent 'inhibit-cookies)
21 (goto-char (point-max)) 39 (goto-char (point-max))
22 (eval-print-last-sexp))) 40 (eval-print-last-sexp)))
23 (load bootstrap-file nil 'nomessage))) 41 (load bootstrap-file nil 'nomessage)))
24(unless (ignore-errors (acdw/bootstrap-straight)) 42(when (executable-find "git")
25 (let ((msg "Straight.el didn't bootstrap correctly. Cloning directly")) 43 (unless (ignore-errors (acdw/bootstrap-straight))
26 (message "%s..." msg) 44 (let ((msg "Straight.el didn't bootstrap correctly. Cloning directly"))
27 (call-process "git" nil 45 (message "%s..." msg)
28 (get-buffer-create "*bootstrap-straight-messages*") nil 46 (call-process "git" nil
29 "clone" 47 (get-buffer-create "*bootstrap-straight-messages*") nil
30 "https://github.com/raxod502/straight.el" 48 "clone"
31 (expand-file-name "straight/repos/straight.el" 49 "https://github.com/raxod502/straight.el"
32 user-emacs-directory)) 50 (expand-file-name "straight/repos/straight.el"
33 (message "%s...Done." msg) 51 user-emacs-directory))
34 (acdw/bootstrap-straight))) 52 (message "%s...Done." msg)
35 53 (acdw/bootstrap-straight))))
36(setq-default frame-inhibit-implied-resize t) 54;; SETUP FRAME
37
38(setq-default frame-resize-pixelwise t)
39
40(add-to-list 'default-frame-alist 55(add-to-list 'default-frame-alist
41 '(tool-bar-lines . 0)) 56 '(tool-bar-lines . 0))
42 57
43(tool-bar-mode -1) 58(tool-bar-mode -1)
44(add-to-list 'default-frame-alist 59(add-to-list 'default-frame-alist
45 '(menu-bar-lines . 0)) 60 '(menu-bar-lines . 0))
46 61
47(menu-bar-mode -1) 62(menu-bar-mode -1)
48(add-to-list 'default-frame-alist 63(add-to-list 'default-frame-alist
49 '(vertical-scroll-bars . nil) 64 '(vertical-scroll-bars . nil)
50 '(horizontal-scroll-bars . nil)) 65 '(horizontal-scroll-bars . nil))
51 66
52(scroll-bar-mode -1) 67(scroll-bar-mode -1)
53(horizontal-scroll-bar-mode -1) 68(horizontal-scroll-bar-mode -1)
69(setq-default frame-inhibit-implied-resize t
70 frame-resize-pixelwise t)
diff --git a/init.el b/init.el index e8a67fd..221956c 100644 --- a/init.el +++ b/init.el
@@ -4,26 +4,51 @@
4 4
5(setq-default load-prefer-newer t) 5(setq-default load-prefer-newer t)
6 6
7(defmacro when-at (conditions &rest commands)
8 "Run COMMANDS, or let the user know, when at a specific place.
9
10CONDITIONS are one of `:work', `:home', or a list beginning with
11those and other conditions to check. COMMANDS are only run if
12all CONDITIONS are met.
13
14If COMMANDS is empty or nil, simply return the result of CONDITIONS."
15 (declare (indent 1))
16 (let ((at-work '(memq system-type '(ms-dos windows-nt)))
17 (at-home '(memq system-type '(gnu gnu/linux gnu/kfreebsd))))
18 (pcase conditions
19 (:work (if commands `(when ,at-work ,@commands) at-work))
20 (:home (if commands `(when ,at-home ,@commands) at-home))
21 ((guard (eq (car conditions) :work))
22 (if commands
23 `(when (and ,at-work ,@(cdr conditions))
24 ,@commands)
25 `(and ,at-work ,@(cdr conditions))))
26 ((guard (eq (car conditions) :home))
27 (if commands
28 `(when (and ,at-home ,@(cdr conditions))
29 ,@commands)
30 `(and ,at-work ,@(cdr conditions)))))))
31
7(let* (;; Speed up init 32(let* (;; Speed up init
8 (gc-cons-threshold most-positive-fixnum) 33 (gc-cons-threshold most-positive-fixnum)
9 (file-name-handler-alist nil) 34 (file-name-handler-alist nil)
10 ;; Config file names 35 ;; Config file names
11 (config (expand-file-name "config" 36 (config (expand-file-name "config"
12 user-emacs-directory)) 37 user-emacs-directory))
13 (config.el (concat config ".el")) 38 (config.el (concat config ".el"))
14 (config.org (concat config ".org")) 39 (config.org (concat config ".org"))
15 (straight-org-dir (expand-file-name "straight/build/org" 40 (straight-org-dir (expand-file-name "straight/build/org"
16 user-emacs-directory))) 41 user-emacs-directory)))
17 ;; Unless config.org is /newer/ than config.el, *or* the config 42 ;; Unless config.org is /newer/ than config.el, *or* the config
18 ;; is able to be loaded without errors, load the config from 43 ;; is able to be loaded without errors, load the config from
19 ;; config.org. 44 ;; config.org.
20 (unless (or (file-newer-than-file-p config.org config.el) 45 (unless (or (file-newer-than-file-p config.org config.el)
21 (load config 'no-error)) 46 (load config 'no-error))
22 ;; A plain require here just loads the older `org' 47 ;; A plain require here just loads the older `org'
23 ;; in Emacs' install dir. We need to add the newer 48 ;; in Emacs' install dir. We need to add the newer
24 ;; one to the `load-path', hopefully that's all. 49 ;; one to the `load-path', hopefully that's all.
25 (when (file-exists-p straight-org-dir) 50 (when (file-exists-p straight-org-dir)
26 (add-to-list 'load-path straight-org-dir)) 51 (add-to-list 'load-path straight-org-dir))
27 ;; Load config.org 52 ;; Load config.org
28 (require 'org) 53 (require 'org)
29 (org-babel-load-file config.org))) 54 (org-babel-load-file config.org)))