Skip to content

Commit 61bb207

Browse files
committed
feat(core): add +add-hook! & +remove-hook! from Doom
1 parent 5a04ae8 commit 61bb207

File tree

2 files changed

+112
-1
lines changed

2 files changed

+112
-1
lines changed

core/me-loaddefs.el

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,31 @@ Hook BODY in HOOK, it runs only once.
397397
398398
(fn HOOK &rest BODY)" nil t)
399399
(function-put '+hook-once! 'lisp-indent-function 1)
400+
(autoload '+add-hook! "../elisp/+minemacs" "\
401+
A convenience macro for adding N functions to M hooks.
402+
403+
This macro accepts, in order:
404+
405+
1. The mode(s) or hook(s) to add to. This is either an unquoted mode, an
406+
unquoted list of modes, a quoted hook variable or a quoted list of hook
407+
variables.
408+
2. Optional properties :local, :append, and/or :depth [N], which will make the
409+
hook buffer-local or append to the list of hooks (respectively),
410+
3. The function(s) to be added: this can be a quoted function, a quoted list
411+
thereof, a list of `defun' or `cl-defun' forms, or arbitrary forms (will
412+
implicitly be wrapped in a lambda).
413+
414+
(fn HOOKS [:append :local [:depth N]] FUNCTIONS-OR-FORMS...)" nil t)
415+
(function-put '+add-hook! 'lisp-indent-function '(lambda (indent-point state) (goto-char indent-point) (when (looking-at-p "\\s-*(") (lisp-indent-defform state indent-point))))
416+
(autoload '+remove-hook! "../elisp/+minemacs" "\
417+
A convenience macro for removing N functions from M hooks.
418+
419+
Takes the same arguments as `add-hook!'.
420+
421+
If N and M = 1, there's no benefit to using this macro over `remove-hook'.
422+
423+
(fn HOOKS [:append :local] FUNCTIONS)" nil t)
424+
(function-put '+remove-hook! 'lisp-indent-function 'defun)
400425
(autoload '+compile-functions "../elisp/+minemacs" "\
401426
Queue FNS to be byte/natively-compiled after a brief delay.
402427
@@ -421,7 +446,7 @@ Run all build functions registered with `+register-build-function!'.
421446
(fn &optional DONT-ASK-P)" t)
422447
(autoload 'minemacs-update "../elisp/+minemacs" "\
423448
Update MinEmacs packages." t)
424-
(register-definition-prefixes "../elisp/+minemacs" '("+eval-when-idle-" "+hook-once-num" "minemacs--build-functions"))
449+
(register-definition-prefixes "../elisp/+minemacs" '("+add-hook!" "+eval-when-idle-" "+hook-once-num" "+resolve-hook-forms" "minemacs--build-functions"))
425450

426451

427452
;;; Generated autoloads from ../elisp/+primitives.el

elisp/+minemacs.el

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,92 @@ DEPTH and LOCAL are passed as is to `add-hook'."
248248
,(macroexp-progn body)
249249
(remove-hook ',hook ',fn-name)))))
250250

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+
251337
;; Adapted from: Doom Emacs
252338
;;;###autoload
253339
(defun +compile-functions (&rest fns)

0 commit comments

Comments
 (0)