summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--early-init.el111
-rw-r--r--init.el961
-rw-r--r--lisp/acdw.el412
3 files changed, 753 insertions, 731 deletions
diff --git a/early-init.el b/early-init.el index 4037ef8..adc876a 100644 --- a/early-init.el +++ b/early-init.el
@@ -27,64 +27,53 @@
27;;; Speed up init 27;;; Speed up init
28;; see doom-emacs, et al. 28;; see doom-emacs, et al.
29 29
30(defconst gc-cons-threshold-basis (* 800 1000)
31 "The basis value for `gc-cons-threshold' to return to after a jump.
32800 KB is Emacs's default `gc-cons-threshold'.")
33
34(defconst gc-cons-percentage-basis 0.1
35 "The basis value for `gc-cons-percentage' to return to after init.
360.1 is Emacs's default `gc-cons-percentage'.")
37
38(defvar orig-file-name-handler-alist file-name-handler-alist 30(defvar orig-file-name-handler-alist file-name-handler-alist
39 "The original value of `file-name-handler-alist' will be restored 31 "The original value of `file-name-handler-alist' will be restored
40 after init.") 32 after init.")
41 33
42(setq gc-cons-threshold most-positive-fixnum 34(setq file-name-handler-alist nil)
43 gc-cons-percentage 0.6 35(acdw/gc-disable)
44 file-name-handler-alist nil)
45 36
46(defun hook--post-init-reset () 37(add-hook 'after-init-hook
47 "Reset `gc-cons-threshold', `gc-cons-percentage', and 38 (defun hook--post-init-reset ()
39 "Reset `gc-cons-threshold', `gc-cons-percentage', and
48 `file-name-handler-alist' to their defaults after init." 40 `file-name-handler-alist' to their defaults after init."
49 (setq gc-cons-threshold gc-cons-threshold-basis 41 (acdw/gc-enable)
50 gc-cons-percentage gc-cons-percentage-basis) 42 (dolist (handler file-name-handler-alist)
51 (dolist (handler file-name-handler-alist) 43 (add-to-list 'orig-file-name-handler-alist handler))
52 (add-to-list 'orig-file-name-handler-alist handler)) 44 (setq file-name-handler-alist orig-file-name-handler-alist)))
53 (setq file-name-handler-alist orig-file-name-handler-alist))
54
55(add-hook 'after-init-hook #'hook--post-init-reset)
56 45
57;;; Frame settings 46;;; Frame settings
58 47
59(setq default-frame-alist ; Remove most UI 48(setq default-frame-alist ; Remove most UI
60 `((tool-bar-lines . 0) ; No tool bar 49 `((tool-bar-lines . 0) ; No tool bar
61 (menu-bar-lines . 0) ; No menu bar 50 (menu-bar-lines . 0) ; No menu bar
62 (vertical-scroll-bars) ; No scroll bars 51 (vertical-scroll-bars) ; No scroll bars
63 (horizontal-scroll-bars) ; ... at all 52 (horizontal-scroll-bars) ; ... at all
64 (width . 84) ; A /little/ wider than 53 (width . 84) ; A /little/ wider than
65 ; `fill-column' (set later) 54 ; `fill-column' (set later)
66 (height . 30) 55 (height . 30)
67 (left-fringe . 8) ; Width of fringes 56 (left-fringe . 8) ; Width of fringes
68 (right-fringe . 8) ; (8 is default) 57 (right-fringe . 8) ; (8 is default)
69 (font . ,(pcase acdw/system 58 (font . ,(pcase acdw/system
70 (:home "DejaVu Sans Mono 10") 59 (:home "DejaVu Sans Mono 10")
71 (:work "Consolas 10")))) 60 (:work "Consolas 10"))))
72 frame-inhibit-implied-resize t ; Don't resize randomly 61 frame-inhibit-implied-resize t ; Don't resize randomly
73 frame-resize-pixelwise t ; Resize by pixels, not chars 62 frame-resize-pixelwise t ; Resize by pixels, not chars
74 ) 63 )
75 64
76(defun hook--disable-ui-modes () 65(defun hook--disable-ui-modes ()
77 "Disable frame UI using modes, for toggling later." 66 "Disable frame UI using modes, for toggling later."
78 (dolist (mode ;; each mode is of the form (MODE . FRAME-ALIST-VAR) 67 (dolist (mode ;; each mode is of the form (MODE . FRAME-ALIST-VAR)
79 '((tool-bar-mode . tool-bar-lines) 68 '((tool-bar-mode . tool-bar-lines)
80 (menu-bar-mode . menu-bar-lines) 69 (menu-bar-mode . menu-bar-lines)
81 (scroll-bar-mode . vertical-scroll-bars) 70 (scroll-bar-mode . vertical-scroll-bars)
82 (horizontal-scroll-bar-mode . horizontal-scroll-bars) 71 (horizontal-scroll-bar-mode . horizontal-scroll-bars)
83 )) 72 ))
84 (let ((setting (alist-get (cdr mode) default-frame-alist))) 73 (let ((setting (alist-get (cdr mode) default-frame-alist)))
85 (when (or (not setting) 74 (when (or (not setting)
86 (= 0 setting)) 75 (= 0 setting))
87 (funcall (car mode) -1))))) 76 (funcall (car mode) -1)))))
88 77
89(add-hook 'after-init-hook #'hook--disable-ui-modes) 78(add-hook 'after-init-hook #'hook--disable-ui-modes)
90 79
@@ -92,11 +81,11 @@
92 81
93;; 1. Update `exec-path'. 82;; 1. Update `exec-path'.
94(dolist (path (list (expand-file-name "bin" user-emacs-directory) 83(dolist (path (list (expand-file-name "bin" user-emacs-directory)
95 (expand-file-name "~/bin") 84 (expand-file-name "~/bin")
96 (expand-file-name "~/.local/bin") 85 (expand-file-name "~/.local/bin")
97 (expand-file-name "~/usr/bin") 86 (expand-file-name "~/usr/bin")
98 (expand-file-name "~/cmd") 87 (expand-file-name "~/cmd")
99 (expand-file-name "~/mingw64/bin"))) 88 (expand-file-name "~/mingw64/bin")))
100 (when (file-exists-p path) 89 (when (file-exists-p path)
101 (add-to-list 'exec-path path :append))) 90 (add-to-list 'exec-path path :append)))
102 91
@@ -104,27 +93,25 @@
104(setenv "PATH" (mapconcat #'identity exec-path path-separator)) 93(setenv "PATH" (mapconcat #'identity exec-path path-separator))
105 94
106;; 2. Set `package' and `straight' variables. 95;; 2. Set `package' and `straight' variables.
107(setq package-enable-at-startup nil ; not sure if strictly 96(setq package-enable-at-startup nil
108 ; necessary 97 package-quickstart nil
109 package-quickstart nil ; ditto
110 straight-host-usernames '((github . "duckwork") 98 straight-host-usernames '((github . "duckwork")
111 (gitlab . "acdw")) 99 (gitlab . "acdw"))
112 straight-base-dir acdw/dir ; don't clutter ~/.emacs.d 100 straight-base-dir acdw/dir)
113 )
114 101
115;; 3. Bootstrap `straight'. 102;; 3. Bootstrap `straight'.
116(defvar bootstrap-version) 103(defvar bootstrap-version)
117(let ((bootstrap-file 104(let ((bootstrap-file
118 (expand-file-name 105 (expand-file-name
119 "straight/repos/straight.el/bootstrap.el" 106 "straight/repos/straight.el/bootstrap.el"
120 straight-base-dir)) 107 straight-base-dir))
121 (bootstrap-version 5)) 108 (bootstrap-version 5))
122 (unless (file-exists-p bootstrap-file) 109 (unless (file-exists-p bootstrap-file)
123 (with-current-buffer 110 (with-current-buffer
124 (url-retrieve-synchronously 111 (url-retrieve-synchronously
125 (concat "https://raw.githubusercontent.com/" 112 (concat "https://raw.githubusercontent.com/"
126 "raxod502/straight.el/develop/install.el") 113 "raxod502/straight.el/develop/install.el")
127 'silent 'inhibit-cookies) 114 'silent 'inhibit-cookies)
128 (goto-char (point-max)) 115 (goto-char (point-max))
129 (eval-print-last-sexp))) 116 (eval-print-last-sexp)))
130 (load bootstrap-file nil 'nomessage)) 117 (load bootstrap-file nil 'nomessage))
@@ -134,10 +121,10 @@
134(defun hook--message-startup-time () 121(defun hook--message-startup-time ()
135 "Show Emacs's startup time in the message buffer. For profiling." 122 "Show Emacs's startup time in the message buffer. For profiling."
136 (message "Emacs ready in %s with %d garbage collections." 123 (message "Emacs ready in %s with %d garbage collections."
137 (format "%.2f seconds" 124 (format "%.2f seconds"
138 (float-time (time-subtract after-init-time 125 (float-time (time-subtract after-init-time
139 before-init-time))) 126 before-init-time)))
140 gcs-done)) 127 gcs-done))
141 128
142(add-hook 'emacs-startup-hook #'hook--message-startup-time) 129(add-hook 'emacs-startup-hook #'hook--message-startup-time)
143 130
diff --git a/init.el b/init.el index 8f2bc12..cec8777 100644 --- a/init.el +++ b/init.el
@@ -3,7 +3,7 @@
3;; Created: Sometime during Covid-19, 2020 3;; Created: Sometime during Covid-19, 2020
4;; Keywords: configuration 4;; Keywords: configuration
5;; URL: https://tildegit.org/acdw/emacs 5;; URL: https://tildegit.org/acdw/emacs
6;; Bankruptcy: 5d 6;; Bankruptcy: 6
7 7
8;; This file is NOT part of GNU Emacs. 8;; This file is NOT part of GNU Emacs.
9 9
@@ -16,54 +16,113 @@
16 16
17;;; Code: 17;;; Code:
18 18
19;;; `setup' -- configuration macro
20(straight-use-package '(setup :host nil
21 :repo "https://git.sr.ht/~zge/setup"))
22(require 'setup)
23
24;; shorthand for `customize-set-variable' (via setup)
25(defmacro setc (&rest args)
26 "Customize user options using ARGS like `setq'."
27 (declare (debug setq))
28 `(setup (:option ,@args)))
29
30;; Install packages with `straight-use-package'
31(setup-define :straight
32 (lambda (recipe)
33 `(straight-use-package ',recipe))
34 :documentation "Install RECIPE with `straight-use-package'."
35 :repeatable t
36 :shorthand (lambda (sexp)
37 (let ((recipe (cadr sexp)))
38 (if (consp recipe)
39 (car recipe)
40 recipe))))
41
42;; Bind keys to `acdw/map'
43(setup-define :acdw/map
44 (lambda (key command)
45 `(define-key acdw/map
46 ,(if (stringp key) (kbd key) key)
47 #',command))
48 :documentation "Bind KEY to COMMAND in `acdw/map'."
49 :debug '(form sexp)
50 :repeatable t)
51
52;; Bind keys to `acdw/leader'
53(setup-define :acdw/leader
54 (lambda (key command)
55 `(define-key acdw/leader
56 ,(if (stringp key) (kbd key) key)
57 #',command))
58 :documentation "Bind KEY to COMMAND in `acdw/leader' map."
59 :debug '(form sexp)
60 :repeatable t)
61
62;; Bind keys, and autoload the functions they're bound to.
63(setup-define :bind-autoload
64 (lambda (key command)
65 `(progn
66 (autoload #',command (symbol-name setup-name))
67 (define-key (symbol-value setup-map)
68 ,(if (stringp key) (kbd key) key)
69 #',command)))
70 :documentation "Bind KEY to COMMAND, and autload COMMAND from FEATURE."
71 :debug '(form sexp)
72 :repeatable t)
73
19;;; About me 74;;; About me
20(acdw/set 75(setc user-full-name "Case Duckworth"
21 '((user-full-name "Case Duckworth") 76 user-mail-address "acdw@acdw.net"
22 (user-mail-address "acdw@acdw.net") 77 calendar-location-name "Baton Rouge, LA"
23 (calendar-location-name "Baton Rouge, LA") 78 calendar-latitude 30.4
24 (calendar-latitude 30.4) 79 calendar-longitude -91.1)
25 (calendar-longitude -91.1)
26 (calendar-date-style iso)))
27 80
28;;; Good defaults 81;;; Good defaults
29 82
30;; Lines 83;; Lines
31(acdw/set '((fill-column 80))) 84(setc fill-column 80
32(global-display-fill-column-indicator-mode +1) 85 word-wrap t
86 truncate-lines nil)
33(add-hook 'text-mode-hook #'turn-on-auto-fill) 87(add-hook 'text-mode-hook #'turn-on-auto-fill)
34(add-hook 'prog-mode-hook #'turn-on-auto-fill) 88(add-hook 'prog-mode-hook #'turn-on-auto-fill)
89(global-display-fill-column-indicator-mode +1)
35(global-so-long-mode +1) 90(global-so-long-mode +1)
36 91
37;; I don't want `visual-line-mode', because I really only want to wrap and
38;; truncate lines. Believe me, I know what I'm doing.
39(acdw/set '((word-wrap t)
40 (truncate-lines nil)))
41
42;; Whitespace 92;; Whitespace
43(acdw/set '((whitespace-style 93(setc whitespace-style
44 (empty indentation space-before-tab space-after-tab)) 94 '(empty indentation space-before-tab space-after-tab)
45 (indent-tabs-mode nil "We've lost this battle...") 95 indent-tabs-mode nil
46 (tab-width 4))) 96 tab-width 4
97 smie-indent-basic tab-width)
47(add-hook 'before-save-hook #'whitespace-cleanup) 98(add-hook 'before-save-hook #'whitespace-cleanup)
48 99
49;; Pairs 100;; Pairs
50(add-hook 'prog-mode-hook #'electric-pair-local-mode) 101(setc show-paren-delay 0
51(acdw/set '((show-paren-delay 0) 102 show-paren-style 'mixed
52 (show-paren-style mixed) 103 show-paren-when-point-inside-paren t
53 (show-paren-when-point-inside-paren t) 104 show-paren-when-point-in-periphery t)
54 (show-paren-when-point-in-periphery t)))
55(show-paren-mode +1) 105(show-paren-mode +1)
106(add-hook 'prog-mode-hook #'electric-pair-local-mode)
56 107
57;; Killing & Yanking 108;; Killing and yanking
109(setc save-interprogram-paste-before-kill t
110 yank-pop-change-selection t
111 x-select-enable-clipboard t
112 x-select-enable-primary t
113 mouse-drag-copy-region t
114 kill-do-not-save-duplicates t)
58(delete-selection-mode +1) 115(delete-selection-mode +1)
59(acdw/set '((save-interprogram-paste-before-kill t)
60 (yank-pop-change-selection t)
61 (x-select-enable-clipboard t)
62 (x-select-enable-primary t)
63 (mouse-drag-copy-region t)
64 (kill-do-not-save-duplicates t)))
65 116
66;; Encoding 117;; Encoding
118(setc local-coding-system 'utf-8-unix
119 coding-system-for-read 'utf-8-unix
120 coding-system-for-write 'utf-8-unix
121 buffer-file-coding-system 'utf-8-unix
122 org-export-coding-system 'utf-8-unix
123 org-html-coding-system 'utf-8-unix
124 default-process-coding-system '(utf-8-unix . utf-8-unix)
125 x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
67(set-charset-priority 'unicode) 126(set-charset-priority 'unicode)
68(set-language-environment "UTF-8") 127(set-language-environment "UTF-8")
69(prefer-coding-system 'utf-8-unix) 128(prefer-coding-system 'utf-8-unix)
@@ -71,453 +130,387 @@
71(set-terminal-coding-system 'utf-8-unix) 130(set-terminal-coding-system 'utf-8-unix)
72(set-keyboard-coding-system 'utf-8-unix) 131(set-keyboard-coding-system 'utf-8-unix)
73(set-selection-coding-system 'utf-8-unix) 132(set-selection-coding-system 'utf-8-unix)
74(acdw/set '((locale-coding-system utf-8-unix) 133
75 (coding-system-for-read utf-8-unix) 134;; Uniquify
76 (coding-system-for-write utf-8-unix) 135(setup (:require uniquify)
77 (buffer-file-coding-system utf-8-unix) 136 (:option uniquify-buffer-name-style 'forward
78 (org-export-coding-system utf-8-unix) 137 uniquify-separator path-separator
79 (org-html-coding-system utf-8-unix) 138 uniquify-after-kill-buffer-p t
80 (default-process-coding-system (utf-8-unix . utf-8-unix)) 139 uniquify-ignore-buffers-re "^\\*"))
81 (x-select-request-type (UTF8_STRING COMPOUND_TEXT TEXT STRING)))) 140
82 141;; Files
83;; Unique buffer names 142(setc backup-directory-alist `((".*" . ,(acdw/in-dir "backup/" t)))
84(when (require 'uniquify) 143 tramp-backup-directory-alist backup-directory-alist
85 (acdw/set '((uniquify-buffer-name-style forward) 144 auto-save-file-name-transforms `((".*" ,(acdw/in-dir "auto-save/" t) t))
86 (uniquify-separator "/") 145 auto-save-list-file-prefix (acdw/in-dir "auto-save-list/.saves-" t)
87 (uniquify-after-kill-buffer-p t) 146 backup-by-copying t
88 (uniquify-ignore-buffers-re "^\\*")))) 147 delete-old-versions t
89 148 version-control t
90;; Backups 149 vc-make-backup-files t)
91(acdw/set `((backup-by-copying t)
92 (delete-old-versions -1)
93 (version-control t)
94 (vc-make-backup-files t)
95 (backup-directory-alist ((".*" . ,(acdw/in-dir "backup/" t))))))
96;; Autosaves
97(acdw/set `((auto-save-file-name-transforms
98 ((".*" ,(acdw/in-dir "auto-save/" t) t)))
99 (auto-save-list-file-prefix
100 ,(acdw/in-dir "auto-save-list/.saves-" t))))
101(auto-save-visited-mode +1) 150(auto-save-visited-mode +1)
102 151
103(defun hook--auto-save-when-unfocused ()
104 "Save all buffers when out of focus."
105 (acdw/when-unfocused #'save-some-buffers t))
106(add-function :after after-focus-change-function 152(add-function :after after-focus-change-function
107 #'hook--auto-save-when-unfocused) 153 (defun hook--auto-save-when-unfocused ()
108 154 "Save all buffers when out of focus."
109;; Auto-revert 155 (acdw/when-unfocused #'save-some-buffers t)))
110(when (require 'autorevert) 156
111 (global-auto-revert-mode +1)) 157(setup (:require autorevert)
112;; Save place 158 (global-auto-revert-mode +1))
113(when (require 'saveplace) 159
114 (acdw/set 160(setup (:require saveplace)
115 `((save-place-file ,(acdw/in-dir "places.el")) 161 (:option save-place-file (acdw/in-dir "places.el")
116 (save-place-forget-unreadable-files ,(eq acdw/system :home)))) 162 save-place-forget-unreadable-files (eq acdw/system :home))
117 (save-place-mode +1)) 163 (save-place-mode +1))
118;; Recent files 164
119(when (require 'recentf) 165(setup (:require recentf)
120 (acdw/set 166 (:option recentf-save-file (acdw/in-dir "recentf.el")
121 `((recentf-save-file ,(acdw/in-dir "recentf.el")) 167 recentf-max-menu-items 100
122 (recentf-max-menu-items 100) 168 recentf-max-saved-items nil
123 (recentf-max-saved-items nil) 169 recentf-auto-cleanup 60
124 (recentf-auto-cleanup 60 "Cleanup the recentf list when idle for 60s."))) 170 (append recentf-exclude) acdw/dir)
125 (add-to-list 'recentf-exclude acdw/dir)
126 (recentf-mode +1)) 171 (recentf-mode +1))
127 172
128;; Move the custom file 173;; Minibuffer
129(acdw/set `((custom-file ,(acdw/in-dir "custom.el")))) 174(setc minibuffer-prompt-properties
175 '(read-only t
176 cursor-intangible t
177 face minibuffer-prompt)
178 enable-recursive-minibuffers t
179 file-name-shadow-properties '(invisible t intangible t)
180 read-answer-short t)
181(minibuffer-depth-indicate-mode +1)
182(file-name-shadow-mode +1)
183(fset 'yes-or-no-p #'y-or-n-p)
184
185(setup (:require savehist)
186 (:option (append savehist-additional-variables) 'kill-ring
187 (append savehist-additional-variables) 'search-ring
188 (append savehist-additional-variables) 'regexp-search-ring
189 history-length t
190 history-delete-duplicates t
191 savehist-autosave-interval 6
192 savehist-file (acdw/in-dir "savehist.el"))
193 (savehist-mode +1))
130 194
131;; Cursor 195(setup (:require icomplete)
132(acdw/set '((cursor-type bar) 196 (:option completion-ignore-case t
133 (cursor-in-non-selected-windows hollow))) 197 read-buffer-completion-ignore-case t
198 icomplete-delay-completions-threshold 0
199 icomplete-max-delay-chars 0
200 icomplete-compute-delay 0
201 icomplete-show-matches-on-no-input t
202 icomplete-with-buffer-completion-tables t
203 icomplete-in-buffer t
204 completion-styles '(partial-completion substring flex))
205 (fido-mode -1)
206 (icomplete-mode +1))
207
208(setup imenu
209 (:option imenu-auto-rescan t))
134 210
135;; (defun hook--overwrite-mode-change-cursor () 211;; Cursor
136;; (setq cursor-type (if overwrite-mode 'hbar 'bar))) 212(setc cursor-type 'bar
137;; (add-hook 'overwrite-mode-hook #'hook--overwrite-mode-change-cursor) 213 cursor-in-non-selected-windows 'hollow)
138 214
139;; Scrolling 215;; Scrolling
140(acdw/set '((auto-window-vscroll nil) 216(setc auto-window-vscroll nil
141 (fast-but-imprecise-scrolling t) 217 fast-but-imprecise-scrolling t
142 (scroll-margin 0) 218 scroll-margin 0
143 (scroll-conservatively 101) 219 scroll-conservatively 101
144 (scroll-preserve-screen-position 1))) 220 scroll-preserve-screen-position 1)
145 221
146;; Bindings 222;; MS Windows
147(acdw/binds (("C-h" ehelp-command :after ("ehelp" nil nil 'keymap)) 223(setc w32-allow-system-shell t
148 ([remap just-one-space] cycle-spacing) 224 w32-pass-lwindow-to-system nil
149 ("M-/" hippie-expand) 225 w32-lwindow-modifier 'super
150 ("M-=" count-words) 226 w32-pass-rwindow-to-system nil
151 ("C-x C-b" ibuffer))) 227 w32-rwindow-modifier 'super
152 228 w32-pass-apps-to-system nil
153;;; Startup 229 w32-apps-modifier 'hyper)
154(acdw/set `((inhibit-startup-screen t) 230
155 (initial-buffer-choice t) 231;; Dired
156 (initial-scratch-message 232(setup dired
157 ,(concat ";; Howdy, " 233 (:option dired-recursive-copies 'always
158 (nth 0 (split-string user-full-name)) "!" 234 dired-recursive-deletes 'always
159 " Welcome to GNU Emacs.\n\n")))) 235 delete-by-moving-to-trash t
160 236 dired-listing-switches "-Al"
161;;; Windows settings 237 ls-lisp-dirs-first t
162(when (eq acdw/system :work) 238 dired-ls-F-marks-symlinks t
163 (acdw/set `((w32-allow-system-shell t) 239 dired-no-confirm '(byte-compile
164 (w32-pass-lwindow-to-system nil) 240 chgrp chmod chown copy
165 (w32-lwindow-modifier 'super) 241 hardlink load move
166 (w32-pass-rwindow-to-system nil) 242 shell touch symlink)
167 (w32-rwindow-modifier 'super) 243 dired-dwim-target t)
168 (w32-pass-apps-to-system nil) 244 (:also-load dired-x)
169 (w32-apps-modifier 'hyper)))) 245 (:hook dired-hide-details-mode
246 hl-line-mode)
247 (:acdw/map "C-x C-j" dired-jump))
248
249;; Eshell
250(setup eshell
251 (:option eshell-directory-name (acdw/in-dir "eshell/" t)
252 eshell-aliases-file (acdw/in-dir "eshell/aliases" t)))
170 253
171(acdw/set '((default-directory (expand-file-name "~/")))) 254;; Garbage collection
255(add-hook 'minibuffer-setup-hook #'acdw/gc-disable)
256(add-hook 'minibuffer-exit-hook #'acdw/gc-enable)
257(add-function :after after-focus-change-function
258 (defun hook--gc-when-unfocused ()
259 (acdw/when-unfocused #'garbage-collect)))
260
261;; Etc. good defaults
262(setc custom-file (acdw/in-dir "custom.el")
263 inhibit-startup-screen t
264 initial-buffer-choice t
265 initial-scratch-message (concat ";; Howdy, " (nth 0 (split-string
266 user-full-name))
267 "! Welcome to GNU Emacs.\n\n")
268 default-directory (expand-file-name "~/")
269 disabled-command-function nil
270 load-prefer-newer t
271 comp-async-report-warnings-errors nil
272 frame-title-format "%b %+%* GNU Emacs")
273
274;; Etc. bindings
275(autoload 'ehelp-command "ehelp" nil nil 'keymap)
276(define-key acdw/map (kbd "C-h") 'ehelp-command)
277(define-key acdw/map [remap just-one-space] #'cycle-spacing)
278(define-key acdw/map (kbd "M-/") #'hippie-expand)
279(define-key acdw/map (kbd "M-=") #'count-words)
280(define-key acdw/map (kbd "C-x C-b") #'ibuffer)
281
282;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
283;;; Here ends the package-less configuration. Everything following requires a
284;;; package to be downloaded. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
285;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
286
287;;; Interactivity
288
289
290;;;; Begin-end
291(setup (:straight beginend)
292 (beginend-global-mode +1))
293
294;;;; Expand-region
295(setup (:straight expand-region)
296 (:acdw/map "C-=" er/expand-region))
297
298;;;; CRUX
299(setup (:straight crux)
300 (:with-map acdw/map
301 (:bind "M-o" crux-other-window-or-switch-buffer)
302 (:bind "C-a" crux-move-beginning-of-line)
303 (:bind "C-k" crux-kill-and-join-forward))
304 (crux-reopen-as-root-mode +1))
305
306;;; Functionality
307
308;;;; Undo-fu
309(setup (:straight undo-fu)
310 (:with-map acdw/map
311 (:bind "C-/" undo-fu-only-undo
312 "C-?" undo-fu-only-redo)))
313
314(setup (:straight undo-fu-session)
315 (:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'"
316 "/git-rebase-todo\\'")
317 undo-fu-session-directory (acdw/in-dir "undo/" t))
318 (global-undo-fu-session-mode +1))
172 319
173;;; Minibuffer 320;;; Minibuffer
174 321
175(acdw/set '((minibuffer-prompt-properties (read-only t 322;;;; Icomplete-vertical
176 cursor-intangible t 323(setup (:straight icomplete-vertical)
177 face minibuffer-prompt)) 324 (let ((map icomplete-minibuffer-map))
178 (enable-recursive-minibuffers t) 325 (let ((command #'icomplete-forward-completions))
179 (file-name-shadow-properties (invisible t)))) 326 (define-key map (kbd "<down>") command)
180(minibuffer-depth-indicate-mode +1) 327 (define-key map (kbd "C-n") command))
181(file-name-shadow-mode +1) 328 (let ((command #'icomplete-backward-completions))
182 329 (define-key map (kbd "<up>") command)
183(acdw/pkg recursion-indicator 330 (define-key map (kbd "C-p") command))
184 :set '((recursion-indicator-general "%") 331 (define-key map (kbd "RET") #'icomplete-force-complete-and-exit)
185 (recursion-indicator-minibuffer "@")) 332 (define-key map (kbd "C-RET") #'minibuffer-complete-and-exit))
186 :now ((recursion-indicator-mode +1))) 333 (icomplete-vertical-mode +1))
187 334
188;; Save history 335;;;; Orderless
189(when (require 'savehist) 336(setup (:straight orderless)
190 (acdw/set `((savehist-additional-variables 337 (:option (prepend completion-styles) 'orderless))
191 (kill-ring search-ring regexp-search-ring)) 338
192 (history-length t) 339;;;; Consult
193 (history-delete-duplicates t) 340(setup (:straight consult)
194 (savehist-autosave-interval 6) 341 (:with-map acdw/map
195 (savehist-file ,(acdw/in-dir "savehist.el")))) 342 (:bind-autoload
196 (savehist-mode +1)) 343 ;; C-c bindings (`mode-specific-map')
197 344 "C-c h" consult-history
198;; God mode 345 "C-c m" consult-mode-command
199(acdw/pkg god-mode 346 ;; C-x bindings (`ctl-x-map')
200 :binds (("<escape>" god-local-mode) 347 "C-x M-:" consult-complex-command
201 ("i" god-local-mode :map god-local-mode-map) 348 "C-x b" consult-buffer
202 ("." repeat :map god-local-mode-map) 349 "C-x 4 b" consult-buffer-other-window
203 ("C-x C-1" delete-other-windows) 350 "C-x 5 b" consult-buffer-other-frame
204 ("C-x C-2" split-window-below) 351 "C-x r x" consult-register
205 ("C-x C-3" split-window-right) 352 "C-x r b" consult-bookmark
206 ("C-x C-0" delete-window)) 353 ;; M-g bindings (`goto-map')
207 :now ((defun acdw/god-mode-update-cursor () 354 "M-g o" consult-outline
208 (setq cursor-type (if (or god-local-mode buffer-read-only) 355 "M-g m" consult-mark
209 'box 356 "M-g k" consult-global-mark
210 'bar))) 357 "M-g i" consult-imenu
211 (defun acdw/god-mode-toggle-on-overwrite () 358 "M-g e" consult-error
212 (if (bound-and-true-p overwrite-mode) 359 ;; M-s bindings (`search-map')
213 (progn 360 "M-s g" consult-grep ; alts: consult-git-grep, consult-ripgrep
214 (setq cursor-type 'hbar) 361 "M-s f" consult-find ; alts: consult-locate
215 (god-local-mode-pause)) 362 "M-s l" consult-line
216 (god-local-mode-resume) 363 "M-s m" consult-multi-occur
217 (acdw/god-mode-update-cursor))) 364 "M-s k" consult-keep-lines
218 (require 'god-mode) 365 "M-s u" consult-focus-lines
219 (god-mode)) 366 ;; Other bindings
220 :hooks (((god-mode-enabled-hook god-mode-disabled-hook) 367 "M-y" consult-yank-pop
221 acdw/god-mode-update-cursor) 368 "<f1> a" consult-apropos
222 (overwrite-mode-hook acdw/god-mode-toggle-on-overwrite))) 369 "C-h a" consult-apropos))
223 370 (autoload 'consult-register-preview "consult")
224;; Icomplete (-vertical) 371 (:option register-preview-delay 0
225(when (require 'icomplete) 372 register-preview-function #'consult-register-preview))
226 (acdw/set '((completion-ignore-case t) 373
227 (read-buffer-completion-ignore-case t) 374;;;; Marginalia
228 (icomplete-delay-completions-threshold 0) 375(setup (:straight marginalia)
229 (icomplete-max-delay-chars 0) 376 (:option marginalia-annotators '(marginalia-annotators-heavy
230 (icomplete-compute-delay 0) 377 marginalia-annotators-light))
231 (icomplete-show-matches-on-no-input t) 378 (marginalia-mode +1))
232 (icomplete-with-buffer-completion-tables t) 379
233 (icomplete-in-buffer t))) 380;;; UI
234 (acdw/pkg orderless 381
235 :set '((completion-styles (orderless)))) 382;;;; Modus themes
236 (acdw/pkg icomplete-vertical 383(setup (:straight (modus-themes
237 :binds (("<down>" icomplete-forward-completions 384 :host gitlab
238 :map icomplete-minibuffer-map) 385 :repo "protesilaos/modus-themes"))
239 ("C-n" icomplete-forward-completions 386 (:option modus-themes-slanted-constructs t
240 :map icomplete-minibuffer-map) 387 modus-themes-bold-constructs t
241 ("<up>" icomplete-backward-completions 388 modus-themes-region 'bg-only
242 :map icomplete-minibuffer-map) 389 modus-themes-org-blocks 'grayscale
243 ("C-p" icomplete-backward-completions 390 modus-themes-headings '((1 . section)
244 :map icomplete-minibuffer-map) 391 (t . no-color))
245 ("C-v" icomplete-vertical-toggle 392 modus-themes-mode-line nil)
246 :map icomplete-minibuffer-map) 393 (acdw/sunrise-sunset #'modus-themes-load-operandi
247 ("RET" icomplete-force-complete-and-exit 394 #'modus-themes-load-vivendi))
248 :map icomplete-minibuffer-map) 395
249 ("C-j" minibuffer-complete-and-exit 396;;;; Mode line
250 :map icomplete-minibuffer-map)) 397(setup (:straight simple-modeline)
251 :now ((fido-mode -1) 398 (setup (:straight minions))
252 (icomplete-mode +1) 399 (:option simple-modeline-segments
253 (icomplete-vertical-mode +1)))) 400 '((acdw-modeline/modified
254 401 acdw-modeline/buffer-name
255;; Consult 402 acdw-modeline/vc-branch
256(acdw/pkg consult 403 simple-modeline-segment-position
257 :binds (;; C-c bindings (`mode-specific-map') 404 simple-modeline-segment-word-count)
258 ("C-c h" consult-history) 405 (simple-modeline-segment-misc-info
259 ("C-c m" consult-mode-command) 406 simple-modeline-segment-process
260 ;; C-x bindings (`ctl-x-map') 407 acdw-modeline/god-mode-indicator
261 ("C-x M-:" consult-complex-command) 408 acdw-modeline/minions
262 ("C-x b" consult-buffer) 409 simple-modeline-segment-major-mode)))
263 ("C-x 4 b" consult-buffer-other-window) 410 (require 'acdw-modeline)
264 ("C-x 5 b" consult-buffer-other-frame) 411 (simple-modeline-mode +1))
265 ("C-x r x" consult-register) 412
266 ("C-x r b" consult-bookmark) 413;;; Utilities
267 ;; M-g bindings (`goto-map') 414
268 ("M-g o" consult-outline) 415;;;; 0x0 -- upload files to a nullpointer
269 ("M-g m" consult-mark) 416(setup (:straight (0x0 :host nil
270 ("M-g k" consult-global-mark) 417 :repo "https://git.sr.ht/~zge/nullpointer-emacs"))
271 ("M-g i" consult-imenu) 418 (:option 0x0-default-host 'ttm))
272 ("M-g e" consult-error) 419
273 ;; M-s bindings (`search-map') 420;;; Applications
274 ("M-s g" consult-grep) ; alts: 421
275 ; consult-git-grep, 422;;;; Magit
276 ; consult-ripgrep 423(setup (:straight magit)
277 ("M-s f" consult-find) ; alts: 424 (:acdw/leader "g" magit-status)
278 ; consult-locate 425 (:option magit-display-buffer-function
279 ("M-s l" consult-line) 426 (defun magit-display-buffer-same-window (buffer)
280 ("M-s m" consult-multi-occur)
281 ("M-s k" consult-keep-lines)
282 ("M-s u" consult-focus-lines)
283 ;; Other bindings
284 ("M-y" consult-yank-pop)
285 ("<f1> a" consult-apropos)
286 ("C-h a" consult-apropos))
287 :now ((autoload 'consult-register-preview "consult"))
288 :set '((register-preview-delay 0)
289 (register-preview-function #'consult-register-preview)))
290
291;; begin-end
292(acdw/pkg beginend
293 :now ((beginend-global-mode)))
294
295;; Marginalia
296(acdw/pkg marginalia
297 :set '((marginalia-annotators (marginalia-annotators-heavy
298 marginalia-annotators-light)))
299 :now ((marginalia-mode +1)))
300
301;; Imenu
302(when (require 'imenu)
303 (acdw/set '((imenu-auto-rescan t))))
304
305;; Fonts
306(acdw/set-faces ((fixed-pitch . ((t (:inherit default))))))
307
308;;; Packages
309
310;; Undo-fu
311(acdw/pkg undo-fu
312 :binds (("C-/" undo-fu-only-undo)
313 ("C-?" undo-fu-only-redo)))
314(acdw/pkg undo-fu-session
315 :set `((undo-fu-session-incompatible-files ("/COMMIT_EDITMSG\\'"
316 "/git-rebase-todo\\'"))
317 (undo-fu-session-directory ,(acdw/in-dir "undo/" t)))
318 :then ((global-undo-fu-session-mode +1)))
319
320;; Modus themes
321(acdw/pkg (modus-themes
322 :host gitlab
323 :repo "protesilaos/modus-themes")
324 :set `((modus-themes-slanted-constructs t)
325 (modus-themes-bold-constructs t)
326 (modus-themes-region 'bg-only)
327 (modus-themes-org-blocks 'grayscale)
328 (modus-themes-headings ((1 . section)
329 (t . no-color)))
330 (modus-themes-scale-headings nil)
331 (modus-themes-mode-line nil))
332 :now ((acdw/sunrise-sunset #'modus-themes-load-operandi
333 #'modus-themes-load-vivendi)))
334
335;; Expand-region
336(acdw/pkg expand-region
337 :binds (("C-=" er/expand-region)))
338
339;; CRUX
340(acdw/pkg crux
341 :binds (("M-o" crux-other-window-or-switch-buffer)
342 ([remap move-beginning-of-line] crux-move-beginning-of-line)
343 ([remap kill-line] crux-kill-and-join-forward)))
344;;; Frame title
345
346(acdw/set `((frame-title-format
347 "%b %+%* GNU Emacs")))
348
349;;; Mode line
350
351;; Minions
352(acdw/pkg minions)
353
354;; Simple mode line
355(acdw/pkg simple-modeline
356 :set '((simple-modeline-segments
357 ((;; left
358 acdw-modeline/modified
359 acdw-modeline/buffer-name
360 acdw-modeline/vc-branch
361 simple-modeline-segment-position
362 simple-modeline-segment-word-count)
363 (;; right
364 simple-modeline-segment-misc-info
365 simple-modeline-segment-process
366 acdw-modeline/god-mode-indicator
367 acdw-modeline/minions
368 simple-modeline-segment-major-mode))))
369 :now ((require 'acdw-modeline)
370 (simple-modeline-mode +1)))
371
372;;; Magit
373
374(acdw/pkg magit
375 :binds (("g" magit-status :map acdw/leader))
376 :set `((magit-display-buffer-function
377 ,(defun magit-display-buffer-same-window (buffer)
378 "Display BUFFER in the selected window like God intended." 427 "Display BUFFER in the selected window like God intended."
379 (display-buffer buffer 428 (display-buffer buffer '(display-buffer-same-window)))
380 '(display-buffer-same-window)))) 429 magit-popup-display-buffer-action '((display-buffer-same-window))))
381 (magit-popup-display-buffer-action
382 ((display-buffer-same-window)))))
383 430
384;;; Web browsing 431;;;; File browsing
432(setup (:straight dired-subtree)
433 (define-key dired-mode-map "i" #'dired-subtree-toggle))
385 434
386(acdw/set '((browse-url-browser-function browse-url-firefox) 435(setup (:straight dired-collapse)
387 (browse-url-new-window-flag t) 436 (:hook-into dired-mode))
388 (browse-url-firefox-new-window-is-tab t)
389 (shr-max-width fill-column)
390 (shr-width fill-column)))
391 437
438;;;; Web browsing
392(when (eq acdw/system :work) 439(when (eq acdw/system :work)
393 (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")) 440 (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox"))
394 441
395(acdw/hooks ((text-mode-hook goto-address-mode) 442(setc browse-url-browser-function 'browse-url-firefox
396 (prog-mode-hook goto-address-prog-mode))) 443 browse-url-new-window-flag t
397 444 browse-url-firefox-new-window-is-tab t
398;;; Gemini/gopher browsing 445 shr-max-width fill-column
399 446 shr-width fill-column)
400(acdw/pkg (elpher 447
401 :repo "git://thelambdalab.xyz/elpher.git") 448(add-hook 'text-mode-hook #'goto-address-mode)
402 :set '((elpher-ipv4-always t) 449(add-hook 'prog-mode-hook #'goto-address-prog-mode)
403 (elpher-certificate-directory 450
404 (acdw/in-var "elpher/"))) 451;;;; Gemini/gopher browsing
405 :now ((acdw/bind-after-map "elpher" elpher-mode-map 452(setup (:straight (elpher :host nil
406 (("n" elpher-next-link :map-after "elpher") 453 :repo "git://thelambdalab.xyz/elpher.git"))
407 ("p" elpher-prev-link :map-after "elpher") 454 (:option elpher-ipv4-always t
408 ("o" elpher-follow-current-link :map-after "elpher") 455 elpher-certificate-directory (acdw/in-dir "elpher/"))
409 ("G" elpher-go-current :map-after "elpher"))) 456 (:bind "n" elpher-next-link
410 (when (boundp 'god-exempt-major-modes) 457 "p" elpher-prev-link
411 (add-to-list 'god-exempt-major-modes 'elpher-mode)))) 458 "o" elpher-follow-current-link
412 459 "G" elpher-go-current)
413(acdw/pkg (gemini-mode 460 (:hook acdw/reading-mode)
414 :repo "https://git.carcosa.net/jmcbray/gemini.el.git") 461 (when (boundp 'god-exempt-major-modes)
415 :now ((add-to-list 'auto-mode-alist 462 (:option (append god-exempt-major-modes) 'elpher-mode)))
416 '("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode)))) 463
417 464(setup (:straight (gemini-mode
418;;; Dired 465 :host nil
419(acdw/pkg dired 466 :repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
420 :local t 467 (:option (append auto-mode-alist)
421 :set `((dired-recursive-copies always) 468 '("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode)))
422 (dired-recursive-deletes always) 469
423 (delete-by-moving-to-trash t) 470;;;; Read e-books (nov.el)
424 (dired-listing-switches "-Al") 471(setup (:straight nov)
425 (ls-lisp-dirs-first t) 472 (:option nov-text-width fill-column
426 (dired-dwim-target t)) 473 (append auto-mode-alist) '("\\.epub\\'" . nov-mode)))
427 :now ((autoload 'dired-mode-map "dired" nil nil 'keymap) 474
428 (acdw/pkg dired-subtree) 475;;;; Org mode
429 (acdw/pkg dired-x 476(setup (:straight (org :host nil
430 :local t 477 :repo "https://code.orgmode.org/bzg/org-mode.git"))
431 :binds (("C-x C-j" dired-jump))) 478 (require 'acdw-org)
432 (acdw/pkg dired-collapse 479 (:option org-directory "~/org"
433 :hooks ((dired-mode-hook dired-collapse-mode))) 480 org-hide-emphasis-markers t
434 (defun hook--dired-mode () 481 org-fontify-whole-heading-line t
435 (hl-line-mode +1) 482 org-fontify-done-headline t
436 (dired-hide-details-mode +1))) 483 org-fontify-quote-and-verse-blocks t
437 :hooks ((dired-mode-hook hook--dired-mode)) 484 org-src-fontify-natively t
438 :binds (("i" dired-subtree-toggle :map dired-mode-map))) 485 org-pretty-entities t
439 486 org-tags-column (- 0 fill-column -3)
440;;; Eshell 487 org-src-tab-acts-natively t
441 488 org-src-window-setup 'current-window
442(acdw/set `((eshell-directory-name ,(acdw/in-dir "eshell/" t)) 489 org-confirm-babel-evaluate nil
443 (eshell-aliases-file ,(acdw/in-dir "eshell/aliases" t)))) 490 org-adapt-indentation nil
444 491 org-catch-invisible-edits 'smart
445;;; Org-mode 492 org-special-ctrl-a/e t
446(acdw/pkg (org 493 org-special-ctrl-k t
447 :repo "https://code.orgmode.org/bzg/org-mode.git") 494 org-imenu-depth 3
448 :now ((require 'acdw-org)) 495 org-export-headline-levels 8
449 :set `((org-directory "~/org") 496 org-export-with-smart-quotes t
450 (org-hide-emphasis-markers t) 497 org-export-with-sub-superscripts t)
451 (org-fontify-whole-heading-line t) 498 (:bind "RET" unpackaged/org-return-dwim)
452 (org-fontify-done-headline t) 499 (add-hook 'before-save-hook #'acdw/hook--org-mode-fix-blank-lines))
453 (org-fontify-quote-and-verse-blocks t)
454 (org-src-fontify-natively t)
455 (org-pretty-entities t)
456 (org-tags-column ,(- 0 fill-column -3))
457 (org-src-tab-acts-natively t)
458 (org-src-window-setup current-window)
459 (org-confirm-babel-evaluate nil)
460 (org-adapt-indentation nil)
461 (org-catch-invisible-edits smart)
462 (org-special-ctrl-a/e t)
463 (org-special-ctrl-k t)
464 (org-imenu-depth 3)
465 (org-export-headline-levels 8)
466 (org-export-with-smart-quotes t)
467 (org-export-with-sub-superscripts t))
468 :hooks ((before-save-hook acdw/hook--org-mode-fix-blank-lines))
469 :binds (("RET" unpackaged/org-return-dwim
470 :map org-mode-map :map-after 'org)))
471
472;;; Nov.el -- ebook reader
473(acdw/pkg nov
474 :now ((autoload #'nov-mode "nov")
475 (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)))
476 :set `((nov-text-width ,fill-column)))
477
478;;; 0x0 -- upload files
479(acdw/pkg (0x0 :repo "https://git.sr.ht/~zge/nullpointer-emacs")
480 :set '((0x0-default-host ttm)))
481 500
482;;; Programming languages 501;;; Programming languages
483 502
484;; General 503;;;; Formatting
485 504(setup (:straight (apheleia :host github
486(acdw/set `((smie-indent-basic ,tab-width))) 505 :repo "raxod502/apheleia"))
487 506 (apheleia-global-mode +1))
488;; Formatting 507
489 508;;;; Emacs lisp
490(acdw/pkg (apheleia 509(setup emacs-lisp
491 :host github 510 (require 'cl-lib)
492 :repo "raxod502/apheleia") 511 (:option eval-expression-print-length nil
493 :now ((apheleia-global-mode +1)) 512 eval-expression-print-level nil
494 :then ((add-to-list 'apheleia-formatters 513 lisp-indent-function #'common-lisp-indent-function)
495 '(shfmt . ("shfmt")))
496 (add-to-list 'apheleia-mode-alist
497 '(sh-mode . shfmt))))
498
499;; Shell(s)
500(when (executable-find "shellcheck")
501 (acdw/pkg flymake-shellcheck
502 :hooks ((sh-mode-hook (flymake-mode
503 flymake-shellcheck-load)))))
504
505(acdw/set `((sh-basic-offset ,tab-width)
506 (sh-indent-after-case 0)
507 (sh-indent-for-case-alt +)
508 (sh-indent-for-case-label 0)))
509
510(defun hook--sh-mode-indent-like-shfmt ()
511 "Try to mirror `shfmt' formatting in shell scripts."
512 (setq indent-tabs-mode t))
513(add-hook 'sh-mode-hook #'hook--sh-mode-indent-like-shfmt)
514
515;; Emacs lisp
516(acdw/set '((eval-expression-print-length nil)
517 (eval-expression-print-level nil)))
518
519(when (require 'cl-lib)
520 (setq-default lisp-indent-function #'common-lisp-indent-function)
521 (put 'cl-flet 'common-lisp-indent-function 514 (put 'cl-flet 'common-lisp-indent-function
522 (get 'flet 'common-lisp-indent-function)) 515 (get 'flet 'common-lisp-indent-function))
523 (put 'cl-labels 'common-lisp-indent-function 516 (put 'cl-labels 'common-lisp-indent-function
@@ -526,34 +519,36 @@
526 (put 'dotimes-protect 'common-lisp-indent-function 519 (put 'dotimes-protect 'common-lisp-indent-function
527 (get 'when 'common-lisp-indent-function))) 520 (get 'when 'common-lisp-indent-function)))
528 521
529;; Racket 522;;;; Shell scripts
530(acdw/pkg racket-mode) 523(setup sh
531 524 (:option sh-basic-offset tab-width
532;; Web stuff 525 sh-indent-after-case 0
533(acdw/set '((css-indent-offset 2) 526 sh-indent-for-case-alt '+
534 (js-indent-level 2) 527 sh-indent-for-case-label 0)
535 (sgml-indent-offset 2))) 528 (:local-set indent-tabs-mode t)
536 529
537;;; Miscellaneous 530 (when (executable-find "shfmt")
538 531 (:option (append apheleia-formatters) '(shfmt . ("shfmt"))
539(acdw/set '((disabled-command-function nil) 532 (append apheleia-mode-alist) '(sh-mode . shfmt)))
540 (load-prefer-newer t) 533
541 (comp-async-report-warnings-errors nil))) 534 (when (executable-find "shellcheck")
542 535 (straight-use-package 'flymake-shellcheck)
543(fset 'yes-or-no-p #'y-or-n-p) 536 (:hook flymake-mode
544 537 flymake-shellcheck-load)))
545;; Garbage collection 538
546(defun hook--gc-cons-maximize () 539;;;; Web languages
547 (setq gc-cons-threshold most-positive-fixnum)) 540(setup (:straight web-mode)
548(add-hook 'minibuffer-setup-hook #'hook--gc-cons-maximize) 541 (:option css-level-offset 2
549 542 js-indent-level 2
550(defun hook--gc-cons-baseline () 543 sgml-indent-offset 2)
551 (setq gc-cons-threshold gc-cons-threshold-basis)) 544 (dolist (extension '("\\(p\\|dj\\)?html"
552(add-hook 'minibuffer-exit-hook #'hook--gc-cons-baseline) 545 "html?"
553 546 "\\(tpl\\.\\)?php"
554(defun hook--gc-when-unfocused () 547 "[agj]sp"
555 (acdw/when-unfocused #'garbage-collect)) 548 "as[cp]x"
556(add-function :after after-focus-change-function 549 "erb"
557 #'hook--gc-when-unfocused) 550 "mustache"))
551 (add-to-list 'auto-mode-alist
552 `(,(concat "\\." extension "\\'") . web-mode))))
558 553
559;;; init.el ends here 554;;; init.el ends here
diff --git a/lisp/acdw.el b/lisp/acdw.el index 62778e3..9aa0821 100644 --- a/lisp/acdw.el +++ b/lisp/acdw.el
@@ -22,9 +22,9 @@
22;;; Utilities 22;;; Utilities
23 23
24(defconst acdw/system (pcase system-type 24(defconst acdw/system (pcase system-type
25 ('gnu/linux :home) 25 ('gnu/linux :home)
26 ((or 'msdos 'windows-nt) :work) 26 ((or 'msdos 'windows-nt) :work)
27 (_ :other)) 27 (_ :other))
28 "Which system is currently being used.") 28 "Which system is currently being used.")
29 29
30(defun acdw/when-unfocused (func &rest args) 30(defun acdw/when-unfocused (func &rest args)
@@ -37,220 +37,260 @@ Ready for use with `after-focus-change-function'."
37(defun acdw/sunrise-sunset (sunrise-command sunset-command) 37(defun acdw/sunrise-sunset (sunrise-command sunset-command)
38 "Run commands at sunrise and sunset." 38 "Run commands at sunrise and sunset."
39 (let* ((times-regex (rx (* nonl) 39 (let* ((times-regex (rx (* nonl)
40 (: (any ?s ?S) "unrise") " " 40 (: (any ?s ?S) "unrise") " "
41 (group (repeat 1 2 digit) ":" 41 (group (repeat 1 2 digit) ":"
42 (repeat 1 2 digit) 42 (repeat 1 2 digit)
43 (: (any ?a ?A ?p ?P) (any ?m ?M))) 43 (: (any ?a ?A ?p ?P) (any ?m ?M)))
44 (* nonl) 44 (* nonl)
45 (: (any ?s ?S) "unset") " " 45 (: (any ?s ?S) "unset") " "
46 (group (repeat 1 2 digit) ":" 46 (group (repeat 1 2 digit) ":"
47 (repeat 1 2 digit) 47 (repeat 1 2 digit)
48 (: (any ?a ?A ?p ?P) (any ?m ?M))) 48 (: (any ?a ?A ?p ?P) (any ?m ?M)))
49 (* nonl))) 49 (* nonl)))
50 (ss (sunrise-sunset)) 50 (ss (sunrise-sunset))
51 (_m (string-match times-regex ss)) 51 (_m (string-match times-regex ss))
52 (sunrise-time (match-string 1 ss)) 52 (sunrise-time (match-string 1 ss))
53 (sunset-time (match-string 2 ss))) 53 (sunset-time (match-string 2 ss)))
54 (run-at-time sunrise-time (* 60 60 24) sunrise-command) 54 (run-at-time sunrise-time (* 60 60 24) sunrise-command)
55 (run-at-time sunset-time (* 60 60 24) sunset-command) 55 (run-at-time sunset-time (* 60 60 24) sunset-command)
56 (run-at-time "12:00am" (* 60 60 24) sunset-command))) 56 (run-at-time "12:00am" (* 60 60 24) sunset-command)))
57 57
58;;; Garbage collection hacks
59
60(defconst acdw/gc-cons-threshold-basis (* 800 1024 1024)
61 "Basis value for `gc-cons-threshold' to return to after jumping.
62800 KB is Emacs's default.")
63
64(defconst acdw/gc-cons-percentage-basis 0.1
65 "Basis value for `gc-cons-percentage' to return to after jumping.
660.1 is Emacs's default.")
67
68(defun acdw/gc-disable ()
69 "Disable garbage collection by setting relevant variables to their maxima."
70 (setq gc-cons-threshold most-positive-fixnum
71 gc-cons-percentage 0.8))
72
73(defun acdw/gc-enable ()
74 "Re-enable garbage collection by setting relevant variables back to bases."
75 (setq gc-cons-threshold acdw/gc-cons-threshold-basis
76 gc-cons-percentage acdw/gc-cons-percentage-basis))
77
58;;; Directories (think `no-littering') 78;;; Directories (think `no-littering')
59 79
60(defvar acdw/dir (expand-file-name 80(defvar acdw/dir (expand-file-name
61 (convert-standard-filename "var/") 81 (convert-standard-filename "var/")
62 user-emacs-directory) 82 user-emacs-directory)
63 "A directory to hold extra configuration and emacs data.") 83 "A directory to hold extra configuration and emacs data.")
64 84
65(defun acdw/in-dir (file &optional make-directory) 85(defun acdw/in-dir (file &optional make-directory)
66 "Expand FILE relative to `acdw/dir', optionally creating its 86 "Expand FILE relative to `acdw/dir', optionally creating its
67directory." 87directory."
68 (let ((f (expand-file-name (convert-standard-filename file) 88 (let ((f (expand-file-name (convert-standard-filename file)
69 acdw/dir))) 89 acdw/dir)))
70 (when make-directory 90 (when make-directory
71 (make-directory (file-name-directory f) 'parents)) 91 (make-directory (file-name-directory f) 'parents))
72 f)) 92 f))
73 93
74;;; Settings 94;;; Settings
75 95
76(defun acdw/set (assignments) 96;; (defun acdw/set (assignments)
77 "Perform `customize-set-variable' on each of ASSIGNMENTS. 97;; "Perform `customize-set-variable' on each of ASSIGNMENTS.
78 98
79ASSIGNMENTS is a list where each element is of the form 99;; ASSIGNMENTS is a list where each element is of the form
80(VARIABLE VALUE [COMMENT])." 100;; (VARIABLE VALUE [COMMENT])."
81 (let (setting) ; for return value 101;; (let (setting) ; for return value
82 (dolist (assignment assignments setting) 102;; (dolist (assignment assignments setting)
83 (customize-set-variable (car assignment) 103;; (customize-set-variable (car assignment)
84 (cadr assignment) 104;; (cadr assignment)
85 (if (and (caddr assignment) 105;; (if (and (caddr assignment)
86 (stringp (caddr assignment))) 106;; (stringp (caddr assignment)))
87 (caddr assignment) 107;; (caddr assignment)
88 "Customized by `acdw/set'.")) 108;; "Customized by `acdw/set'."))
89 (setq setting (car assignment))))) 109;; (setq setting (car assignment)))))
90 110
91;;; Faces 111;;; Faces
92 112
93(defun acdw/set-face (face spec) 113;; (defun acdw/set-face (face spec)
94 "Customize FACE according to SPEC, and register it with `customize'. 114;; "Customize FACE according to SPEC, and register it with `customize'.
95SPEC is as for `defface'." 115;; SPEC is as for `defface'."
96 (put face 'customized-face spec) 116;; (put face 'customized-face spec)
97 (face-spec-set face spec)) 117;; (face-spec-set face spec))
98 118
99(defmacro acdw/set-faces (face-specs) 119;; (defmacro acdw/set-faces (face-specs)
100 "Run `acdw/set-face' over each face in FACE-SPECS." 120;; "Run `acdw/set-face' over each face in FACE-SPECS."
101 (let (face-list) 121;; (let (face-list)
102 (dolist (face face-specs) 122;; (dolist (face face-specs)
103 (push `(acdw/set-face ',(car face) ',(cdr face)) face-list)) 123;; (push `(acdw/set-face ',(car face) ',(cdr face)) face-list))
104 `(progn 124;; `(progn
105 ,@face-list))) 125;; ,@face-list)))
106 126
107;;; Hooks 127;;; Hooks
108(defmacro acdw/hooks (hook-specs &rest args) 128;; (defmacro acdw/hooks (hook-specs &rest args)
109 "Add functions to hooks, according to HOOK-SPECS. 129;; "Add functions to hooks, according to HOOK-SPECS.
110 130
111Each HOOK-SPEC is of the following format: (HOOKS FUNCS [DEPTH] [LOCAL]). 131;; Each HOOK-SPEC is of the following format: (HOOKS FUNCS [DEPTH] [LOCAL]).
112Either HOOKS or FUNCS can also be a list, in which case `add-hook' is called 132;; Either HOOKS or FUNCS can also be a list, in which case `add-hook' is called
113over the Cartesian product of HOOKS and FUNCS. In each HOOK-SPEC, DEPTH and 133;; over the Cartesian product of HOOKS and FUNCS. In each HOOK-SPEC, DEPTH and
114LOCAL apply to all hooks defined; if finer control is needed, either pass the 134;; LOCAL apply to all hooks defined; if finer control is needed, either pass the
115same hooks and functions in different HOOK-SPECs, or just use `add-hook'. 135;; same hooks and functions in different HOOK-SPECs, or just use `add-hook'.
116 136
117ARGS accept the following keywords: 137;; ARGS accept the following keywords:
118 138
119:after FEATURE .. `autoload' all functions after FEATURE." 139;; :after FEATURE .. `autoload' all functions after FEATURE."
120 (let ((after (plist-get args :after)) 140;; (let ((after (plist-get args :after))
121 (command-list)) 141;; (command-list))
122 (dolist (spec hook-specs) 142;; (dolist (spec hook-specs)
123 (let* ((hooks (car spec)) 143;; (let* ((hooks (car spec))
124 (funcs (cadr spec)) 144;; (funcs (cadr spec))
125 (depth (or (caddr spec) 0)) 145;; (depth (or (caddr spec) 0))
126 (local (cadddr spec))) 146;; (local (cadddr spec)))
127 (when (not (listp hooks)) (setq hooks (list hooks))) 147;; (when (not (listp hooks)) (setq hooks (list hooks)))
128 (when (not (listp funcs)) (setq funcs (list funcs))) 148;; (when (not (listp funcs)) (setq funcs (list funcs)))
129 (dolist (hook hooks) 149;; (dolist (hook hooks)
130 (dolist (func funcs) 150;; (dolist (func funcs)
131 (push `(add-hook ',hook #',func ,depth ,local) command-list) 151;; (push `(add-hook ',hook #',func ,depth ,local) command-list)
132 (when after 152;; (when after
133 (push `(autoload #',func ,after) command-list)))))) 153;; (push `(autoload #',func ,after) command-list))))))
134 `(progn 154;; `(progn
135 ,@command-list))) 155;; ,@command-list)))
136 156
137;;; Keybindings 157;;; Keybindings
138 158
139(defvar acdw/bind-default-map 'acdw/map 159;; (defvar acdw/bind-default-map 'acdw/map
140 "The default keymap to use with `acdw/bind'.") 160;; "The default keymap to use with `acdw/bind'.")
141 161
142(defmacro acdw/bind (key command &rest args) 162;; (defmacro acdw/bind (key command &rest args)
143 "A simple key-binding macro to take care of the repetitive stuff 163;; "A simple key-binding macro to take care of the repetitive stuff
144automatically. 164;; automatically.
145 165
146If KEY is a vector, it's passed directly to `define-key', 166;; If KEY is a vector, it's passed directly to `define-key',
147otherwise it's wrapped in `kbd'. 167;; otherwise it's wrapped in `kbd'.
148 168
149The following keywords are recognized: 169;; The following keywords are recognized:
150 170
151:after ARGS .. call `autoload' on COMMAND using ARGS before 171;; :after ARGS .. call `autoload' on COMMAND using ARGS before
152 binding the key. ARGS can be just the filename to 172;; binding the key. ARGS can be just the filename to
153 load; in that case it's wrapped in a list. 173;; load; in that case it's wrapped in a list.
154 174
155:map KEYMAP .. define KEY in KEYMAP instead of the 175;; :map KEYMAP .. define KEY in KEYMAP instead of the
156 default `acdw/bind-default-map'. If `:after' is also supplied, 176;; default `acdw/bind-default-map'. If `:after' is also supplied,
157 run `autoload' on KEYMAP (except when using `:map-after', see). 177;; run `autoload' on KEYMAP (except when using `:map-after', see).
158 178
159:map-after FILE .. run the underlying `define-key' command in an 179;; :map-after FILE .. run the underlying `define-key' command in an
160 `with-eval-after-load'. For the rare occasion when the keymap is 180;; `with-eval-after-load'. For the rare occasion when the keymap is
161 defined in a different file than the command it binds (looking 181;; defined in a different file than the command it binds (looking
162 at you, `org-mode')." 182;; at you, `org-mode')."
163 (let ((after (when-let (sym (plist-get args :after)) 183;; (let ((after (when-let (sym (plist-get args :after))
164 (if (not (listp sym)) 184;; (if (not (listp sym))
165 (list sym) 185;; (list sym)
166 sym))) 186;; sym)))
167 (map-after (plist-get args :map-after)) 187;; (map-after (plist-get args :map-after))
168 (keymap (or (plist-get args :map) acdw/bind-default-map)) 188;; (keymap (or (plist-get args :map) acdw/bind-default-map))
169 (keycode (if (vectorp key) key (kbd key))) 189;; (keycode (if (vectorp key) key (kbd key)))
170 (command-list)) 190;; (command-list))
171 (let ((define-key-command `(define-key ,keymap ,keycode ',command))) 191;; (let ((define-key-command `(define-key ,keymap ,keycode ',command)))
172 (if map-after 192;; (if map-after
173 (push `(with-eval-after-load ,map-after 193;; (push `(with-eval-after-load ,map-after
174 ,define-key-command) 194;; ,define-key-command)
175 command-list) 195;; command-list)
176 (push define-key-command command-list))) 196;; (push define-key-command command-list)))
177 (when after 197;; (when after
178 (unless (fboundp command) 198;; (unless (fboundp command)
179 (push `(autoload ',command ,@after) command-list)) 199;; (push `(autoload ',command ,@after) command-list))
180 (unless (or map-after 200;; (unless (or map-after
181 (eq keymap acdw/bind-default-map)) 201;; (eq keymap acdw/bind-default-map))
182 (push `(autoload ',keymap ,(car after) nil nil 'keymap) command-list))) 202;; (push `(autoload ',keymap ,(car after) nil nil 'keymap) command-list)))
183 `(progn 203;; `(progn
184 ,@command-list))) 204;; ,@command-list)))
185 205
186(defmacro acdw/binds (bindings) 206;; (defmacro acdw/binds (bindings)
187 "Bind multiple keys at once." 207;; "Bind multiple keys at once."
188 (let (bind-list) 208;; (let (bind-list)
189 (dolist (bind bindings) 209;; (dolist (bind bindings)
190 (push `(acdw/bind ,@bind) bind-list)) 210;; (push `(acdw/bind ,@bind) bind-list))
191 `(progn 211;; `(progn
192 ,@bind-list))) 212;; ,@bind-list)))
193 213
194;; convenience 214;; convenience
195(defmacro acdw/bind-after-map (file keymap bindings) 215;; (defmacro acdw/bind-after-map (file keymap bindings)
196 "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP. 216;; "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP.
197KEYMAP can be nil." 217;; KEYMAP can be nil."
198 (declare (indent 2)) 218;; (declare (indent 2))
199 (let ((bind-list) 219;; (let ((bind-list)
200 (extra-args (if keymap 220;; (extra-args (if keymap
201 `(:after ,file :map ,keymap) 221;; `(:after ,file :map ,keymap)
202 `(:after ,file)))) 222;; `(:after ,file))))
203 (dolist (binding bindings) 223;; (dolist (binding bindings)
204 (push `(acdw/bind ,@binding ,@extra-args) bind-list)) 224;; (push `(acdw/bind ,@binding ,@extra-args) bind-list))
205 `(progn 225;; `(progn
206 ,@bind-list))) 226;; ,@bind-list)))
207 227
208;;; Packages 228;;; Packages
209 229
210(defmacro acdw/pkg (package &rest args) 230;; (defmacro acdw/pkg (package &rest args)
211 "Set up a package using `straight.el'. 231;; "Set up a package using `straight.el'.
212 232
213ARGS can include the following keywords: 233;; ARGS can include the following keywords:
214 234
215:local BOOL .. if BOOL is non-nil, don't run `straight-use-package' on 235;; :local BOOL .. if BOOL is non-nil, don't run `straight-use-package' on
216 PACKAGE. Good for using `acdw/pkg' on local features. 236;; PACKAGE. Good for using `acdw/pkg' on local features.
217:require BOOL .. if BOOL is non-nil, run `require' on PACKAGE before anything. 237;; :require BOOL .. if BOOL is non-nil, run `require' on PACKAGE before anything.
218:now FORMS .. run FORMS immediately. 238;; :now FORMS .. run FORMS immediately.
219:then FORMS .. run FORMS after loading PACKAGE, using `with-eval-after-load'. 239;; :then FORMS .. run FORMS after loading PACKAGE, using `with-eval-after-load'.
220:set SETTINGS .. pass SETTINGS to `acdw/set', right after `:now' forms. 240;; :set SETTINGS .. pass SETTINGS to `acdw/set', right after `:now' forms.
221 SETTINGS should be properly quoted, just like they'd be passed 241;; SETTINGS should be properly quoted, just like they'd be passed
222 to the function. 242;; to the function.
223:binds BINDS .. run `acdw/bind-after-map' on BINDS. 243;; :binds BINDS .. run `acdw/bind-after-map' on BINDS.
224:hooks HOOKS .. run `acdw/hooks' on HOOKS." 244;; :hooks HOOKS .. run `acdw/hooks' on HOOKS."
225 (declare (indent 1)) 245;; (declare (indent 1))
226 (let ((local-pkg (plist-get args :local)) 246;; (let ((local-pkg (plist-get args :local))
227 (require-pkg (plist-get args :require)) 247;; (require-pkg (plist-get args :require))
228 (now-forms (plist-get args :now)) 248;; (now-forms (plist-get args :now))
229 (settings (plist-get args :set)) 249;; (settings (plist-get args :set))
230 (binds (plist-get args :binds)) 250;; (binds (plist-get args :binds))
231 (hooks (plist-get args :hooks)) 251;; (hooks (plist-get args :hooks))
232 (then-forms (plist-get args :then)) 252;; (then-forms (plist-get args :then))
233 (requirement (if (listp package) 253;; (requirement (if (listp package)
234 (car package) 254;; (car package)
235 package)) 255;; package))
236 (final-form)) 256;; (final-form))
237 (when then-forms 257;; (when then-forms
238 (push `(with-eval-after-load ',requirement ,@then-forms) final-form)) 258;; (push `(with-eval-after-load ',requirement ,@then-forms) final-form))
239 (when hooks 259;; (when hooks
240 (push `(acdw/hooks ,hooks :after ,(symbol-name requirement)) final-form)) 260;; (push `(acdw/hooks ,hooks :after ,(symbol-name requirement)) final-form))
241 (when binds 261;; (when binds
242 (push `(acdw/bind-after-map ,(symbol-name requirement) nil ,binds) 262;; (push `(acdw/bind-after-map ,(symbol-name requirement) nil ,binds)
243 final-form)) 263;; final-form))
244 (when settings 264;; (when settings
245 (push `(acdw/set ,settings) final-form)) 265;; (push `(acdw/set ,settings) final-form))
246 (when now-forms 266;; (when now-forms
247 (push `(progn ,@now-forms) final-form)) 267;; (push `(progn ,@now-forms) final-form))
248 (unless local-pkg 268;; (unless local-pkg
249 (push `(straight-use-package ',package) final-form)) 269;; (push `(straight-use-package ',package) final-form))
250 (when require-pkg 270;; (when require-pkg
251 (push `(require ',requirement) final-form)) 271;; (push `(require ',requirement) final-form))
252 `(progn 272;; `(progn
253 ,@final-form))) 273;; ,@final-form)))
274
275;;; Reading mode
276
277(define-minor-mode acdw/reading-mode
278 "A mode for reading."
279 :init-value t
280 :lighter " Read"
281 (if acdw/reading-mode
282 (progn ;; turn on
283 (display-fill-column-indicator-mode -1)
284 (dolist (mode '(visual-fill-column-mode
285 iscroll-mode))
286 (when (fboundp mode)
287 (funcall mode +1))))
288 ;; turn off
289 (display-fill-column-indicator-mode +1)
290 (dolist (mode '(visual-fill-column-mode
291 iscroll-mode))
292 (when (fboundp mode)
293 (funcall mode -1)))))
254 294
255;;; Keymap & Mode 295;;; Keymap & Mode
256 296
@@ -273,7 +313,7 @@ ARGS can include the following keywords:
273;; Set up a leader key for `acdw/mode' 313;; Set up a leader key for `acdw/mode'
274(defvar acdw/leader 314(defvar acdw/leader
275 (let ((map (make-sparse-keymap)) 315 (let ((map (make-sparse-keymap))
276 (c-z (global-key-binding "\C-z"))) 316 (c-z (global-key-binding "\C-z")))
277 (define-key acdw/map "\C-z" map) 317 (define-key acdw/map "\C-z" map)
278 (define-key map "\C-z" c-z) 318 (define-key map "\C-z" c-z)
279 map)) 319 map))