summary refs log tree commit diff stats
path: root/lisp/acdw.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/acdw.el')
-rw-r--r--lisp/acdw.el412
1 files changed, 226 insertions, 186 deletions
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))