@@ -248,6 +248,92 @@ DEPTH and LOCAL are passed as is to `add-hook'."
248
248
,(macroexp-progn body)
249
249
(remove-hook ', hook ', fn-name )))))
250
250
251
+ ; ; From Doom Emacs
252
+ (defun +resolve-hook-forms (hooks)
253
+ " Converts a list of modes into a list of hook symbols.
254
+
255
+ If a mode is quoted, it is left as is. If the entire HOOKS list is quoted, the
256
+ list is returned as-is."
257
+ (declare (pure t ) (side-effect-free t ))
258
+ (let ((hook-list (ensure-list (+unquote hooks))))
259
+ (if (eq (car-safe hooks) 'quote )
260
+ hook-list
261
+ (cl-loop for hook in hook-list
262
+ if (eq (car-safe hook) 'quote )
263
+ collect (cadr hook)
264
+ else collect (intern (format " %s -hook" (symbol-name hook)))))))
265
+
266
+ ; ; From Doom Emacs
267
+ ;;;### autoload
268
+ (defmacro +add-hook! (hooks &rest rest)
269
+ " A convenience macro for adding N functions to M hooks.
270
+
271
+ This macro accepts, in order:
272
+
273
+ 1. The mode(s) or hook(s) to add to. This is either an unquoted mode, an
274
+ unquoted list of modes, a quoted hook variable or a quoted list of hook
275
+ variables.
276
+ 2. Optional properties :local, :append, and/or :depth [N], which will make the
277
+ hook buffer-local or append to the list of hooks (respectively),
278
+ 3. The function(s) to be added: this can be a quoted function, a quoted list
279
+ thereof, a list of `defun' or `cl-defun' forms, or arbitrary forms (will
280
+ implicitly be wrapped in a lambda).
281
+
282
+ \( fn HOOKS [:append :local [:depth N]] FUNCTIONS-OR-FORMS...)"
283
+ (declare (indent (lambda (indent-point state )
284
+ (goto-char indent-point)
285
+ (when (looking-at-p " \\ s-*(" )
286
+ (lisp-indent-defform state indent-point))))
287
+ (debug t ))
288
+ (let* ((hook-forms (+resolve-hook-forms hooks))
289
+ (func-forms ())
290
+ (defn-forms ())
291
+ append-p local-p remove-p depth)
292
+ (while (keywordp (car rest))
293
+ (pcase (pop rest)
294
+ (:append (setq append-p t ))
295
+ (:depth (setq depth (pop rest)))
296
+ (:local (setq local-p t ))
297
+ (:remove (setq remove-p t ))))
298
+ (while rest
299
+ (let* ((next (pop rest))
300
+ (first (car-safe next)))
301
+ (push (cond ((memq first '(function nil ))
302
+ next)
303
+ ((eq first 'quote )
304
+ (let ((quoted (cadr next)))
305
+ (if (atom quoted)
306
+ next
307
+ (when (cdr quoted)
308
+ (setq rest (cons (list first (cdr quoted)) rest)))
309
+ (list first (car quoted)))))
310
+ ((memq first '(defun cl-defun))
311
+ (push next defn-forms)
312
+ (list 'function (cadr next)))
313
+ ((prog1 `(lambda (&rest _) ,@(cons next rest))
314
+ (setq rest nil ))))
315
+ func-forms)))
316
+ `(progn
317
+ ,@defn-forms
318
+ (dolist (hook (nreverse ', hook-forms ))
319
+ (dolist (func (list ,@func-forms ))
320
+ ,(if remove-p
321
+ `(remove-hook hook func , local-p )
322
+ `(add-hook hook func ,(or depth append-p) , local-p )))))))
323
+
324
+ ; ; From Doom Emacs
325
+ ;;;### autoload
326
+ (defmacro +remove-hook! (hooks &rest rest)
327
+ " A convenience macro for removing N functions from M hooks.
328
+
329
+ Takes the same arguments as `add-hook!' .
330
+
331
+ If N and M = 1, there's no benefit to using this macro over `remove-hook' .
332
+
333
+ \( fn HOOKS [:append :local] FUNCTIONS)"
334
+ (declare (indent defun ) (debug t ))
335
+ `(+add-hook! , hooks :remove ,@rest ))
336
+
251
337
; ; Adapted from: Doom Emacs
252
338
;;;### autoload
253
339
(defun +compile-functions (&rest fns)
0 commit comments