Skip to content

Commit

Permalink
💥 Refactor add-hook! macro & change arg order
Browse files Browse the repository at this point in the history
This update may potentially break your usage of add-hook! if you pass
the :local or :append properties to it. This is how they used to work:

  (add-hook! :append 'some-mode-hook #'do-something)

Thsoe properties must now follow the hooks, e.g.

  (add-hook! 'some-mode-hook :append #'do-something)

Other changes:
- Various add-hook calls have been renamed to add-hook! because I
  incorrectly assumed `defun` always returned its definition's symbol,
  when in fact, its return value is "undefined" (so sayeth the
  documentation). This should fix doomemacs#1597.
- This update adds the ability to add multiple functions to hooks
  without a list:

    (add-hook! 'some-mode-hook
               #'do-something
               #'do-something-else)

- The indentation logic has been changed so that consecutive function
  symbols at indented at the same level as the first argument, but forms
  are indent like a defun.

    (add-hook! 'some-mode-hook
               #'do-something
               #'do-something-else)

    (add-hook! 'some-mode-hook
      (message "Hello"))
  • Loading branch information
hlissner committed Jul 26, 2019
1 parent c2ae6f3 commit a3e262c
Show file tree
Hide file tree
Showing 42 changed files with 249 additions and 226 deletions.
2 changes: 1 addition & 1 deletion core/core-keybinds.el
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ localleader prefix."

;; Bind `doom-leader-key' and `doom-leader-alt-key' as late as possible to give
;; the user a chance to modify them.
(add-hook 'doom-after-init-modules-hook
(add-hook! 'doom-after-init-modules-hook
(defun doom-init-leader-keys-h ()
"Bind `doom-leader-key' and `doom-leader-alt-key'."
(let ((map general-override-mode-map))
Expand Down
78 changes: 42 additions & 36 deletions core/core-lib.el
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ advised)."
(put ',fn 'permanent-local-hook t)
(add-hook sym #',fn ,append))))))

(defmacro add-hook! (&rest args)
(defmacro add-hook! (hooks &rest rest)
"A convenience macro for adding N functions to M hooks.
If N and M = 1, there's no benefit to using this macro over `add-hook'.
Expand All @@ -272,45 +272,51 @@ This macro accepts, in order:
list of `defun's, or body forms (implicitly wrapped in a closure).
\(fn [:append :local] HOOKS FUNCTIONS)"
(declare (indent defun) (debug t))
(let ((hook-fn 'add-hook)
append-p local-p)
(while (keywordp (car args))
(pcase (pop args)
(declare (indent (lambda (indent-point state)
(goto-char indent-point)
(when (looking-at-p "\\s-*(")
(lisp-indent-defform state indent-point))))
(debug t))
(let* ((hook-forms (doom--resolve-hook-forms hooks))
(func-forms ())
(defn-forms ())
append-p
local-p
remove-p
forms)
(while (keywordp (car rest))
(pcase (pop rest)
(:append (setq append-p t))
(:local (setq local-p t))
(:remove (setq hook-fn 'remove-hook))))
(let* ((defun-forms nil)
(hooks (doom--resolve-hook-forms (pop args)))
(funcs
(let ((val (car args)))
(if (memq (car-safe val) '(quote function))
(if (cdr-safe (cadr val))
(cadr val)
(list (cadr val)))
(or (and (eq (car-safe val) 'defun)
(cl-loop for arg in args
if (not (eq (car-safe arg) 'defun))
return nil
else
collect (cadr arg)
and do (push arg defun-forms)))
(list args)))))
forms)
(dolist (fn funcs)
(setq fn (if (symbolp fn)
`(function ,fn)
`(lambda (&rest _) ,@args)))
(dolist (hook hooks)
(push (if (eq hook-fn 'remove-hook)
`(remove-hook ',hook ,fn ,local-p)
`(add-hook ',hook ,fn ,append-p ,local-p))
(:remove (setq remove-p t))))
(let ((first (car-safe (car rest))))
(cond ((null first)
(setq func-forms rest))

((eq first 'defun)
(setq func-forms (mapcar #'cadr rest)
defn-forms rest))

((memq first '(quote function))
(setq func-forms
(if (cdr rest)
(mapcar #'doom-unquote rest)
(doom-enlist (doom-unquote (car rest))))))

((setq func-forms (list `(lambda () ,@rest)))))
(dolist (hook hook-forms)
(dolist (func func-forms)
(push (if remove-p
`(remove-hook ',hook #',func ,local-p)
`(add-hook ',hook #',func ,append-p ,local-p))
forms)))
(macroexp-progn
(append (nreverse defun-forms)
(if append-p (nreverse forms) forms))))))
(append defn-forms
(if append-p
(nreverse forms)
forms))))))

(defmacro remove-hook! (&rest args)
(defmacro remove-hook! (hooks &rest rest)
"A convenience macro for removing N functions from M hooks.
Takes the same arguments as `add-hook!'.
Expand All @@ -319,7 +325,7 @@ If N and M = 1, there's no benefit to using this macro over `remove-hook'.
\(fn [:append :local] HOOKS FUNCTIONS)"
(declare (indent defun) (debug t))
`(add-hook! :remove ,@args))
`(add-hook! ,hooks :remove ,@rest))

(defmacro setq-hook! (hooks &rest var-vals)
"Sets buffer-local variables on HOOKS.
Expand Down
10 changes: 5 additions & 5 deletions core/core-modules.el
Original file line number Diff line number Diff line change
Expand Up @@ -472,11 +472,11 @@ to have them return non-nil (or exploit that to overwrite Doom's config)."
(error "'%s' isn't a valid hook for use-package-hook!" when))
`(progn
(setq use-package-inject-hooks t)
(add-hook!
',(intern (format "use-package--%s--%s-hook"
package
(substring (symbol-name when) 1)))
,@body)))
(add-hook ',(intern (format "use-package--%s--%s-hook"
package
(substring (symbol-name when) 1)))
(lambda () ,@body)
'append)))

(defmacro require! (category module &rest flags)
"Loads the CATEGORY MODULE module with FLAGS.
Expand Down
11 changes: 5 additions & 6 deletions core/core-ui.el
Original file line number Diff line number Diff line change
Expand Up @@ -384,14 +384,13 @@ treat Emacs as a non-application window."
:config
(defvar doom--ediff-saved-wconf nil)
;; Restore window config after quitting ediff
(add-hook 'ediff-before-setup-hook
(add-hook! 'ediff-before-setup-hook
(defun doom-ediff-save-wconf-h ()
(setq doom--ediff-saved-wconf (current-window-configuration))))
(add-hook! '(ediff-quit-hook ediff-suspend-hook)
(add-hook! '(ediff-quit-hook ediff-suspend-hook) :append
(defun doom-ediff-restore-wconf-h ()
(when (window-configuration-p doom--ediff-saved-wconf)
(set-window-configuration doom--ediff-saved-wconf)))
'append))
(set-window-configuration doom--ediff-saved-wconf)))))


(use-package! hl-line
Expand Down Expand Up @@ -468,7 +467,7 @@ treat Emacs as a non-application window."

;;;###package hide-mode-line-mode
(add-hook! '(completion-list-mode-hook Man-mode-hook)
#'hide-mode-line-mode)
#'hide-mode-line-mode)

;; Better fontification of number literals in code
(use-package! highlight-numbers
Expand All @@ -495,7 +494,7 @@ treat Emacs as a non-application window."

;; line numbers in most modes
(add-hook! '(prog-mode-hook text-mode-hook conf-mode-hook)
#'display-line-numbers-mode)
#'display-line-numbers-mode)

(defun doom-enable-line-numbers-h () (display-line-numbers-mode +1))
(defun doom-disable-line-numbers-h () (display-line-numbers-mode -1))
Expand Down
28 changes: 15 additions & 13 deletions docs/api.org
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,21 @@ It is integrated into Helpful, in Doom.
#+BEGIN_SRC elisp :eval no
;; With only one hook and one function, this is identical to `add-hook'. In that
;; case, use that instead.
(add-hook! 'some-mode-hook 'enable-something)
(add-hook! 'some-mode-hook #'enable-something)

;; Adding many-to-many functions to hooks
(add-hook! some-mode '(enable-something and-another))
(add-hook! '(one-mode-hook second-mode-hook) 'enable-something)
(add-hook! (one-mode second-mode) 'enable-something)
(add-hook! some-mode #'enable-something #'and-another)
(add-hook! some-mode #'(enable-something and-another))
(add-hook! '(one-mode-hook second-mode-hook) #'enable-something)
(add-hook! (one-mode second-mode) #'enable-something)

;; Appending and local hooks
(add-hook! :append (one-mode second-mode) 'enable-something)
(add-hook! :local (one-mode second-mode) 'enable-something)
(add-hook! (one-mode second-mode) :append #'enable-something)
(add-hook! (one-mode second-mode) :local #'enable-something)

;; With arbitrary forms
(add-hook! (one-mode second-mode) (setq v 5) (setq a 2))
(add-hook! :append :local (one-mode second-mode) (setq v 5) (setq a 2))
(add-hook! (one-mode second-mode) :append :local (setq v 5) (setq a 2))

;; Inline named hook functions
(add-hook! '(one-mode-hook second-mode-hook)
Expand Down Expand Up @@ -133,16 +134,17 @@ It is integrated into Helpful, in Doom.
#+BEGIN_SRC elisp :eval no
;; With only one hook and one function, this is identical to `add-hook'. In that
;; case, use that instead.
(remove-hook! 'some-mode-hook 'enable-something)
(remove-hook! 'some-mode-hook #'enable-something)

;; Adding many-to-many functions to hooks
(remove-hook! some-mode '(enable-something and-another))
(remove-hook! '(one-mode-hook second-mode-hook) 'enable-something)
(remove-hook! (one-mode second-mode) 'enable-something)
(remove-hook! some-mode #'enable-something #'and-another)
(remove-hook! some-mode #'(enable-something and-another))
(remove-hook! '(one-mode-hook second-mode-hook) #'enable-something)
(remove-hook! (one-mode second-mode) #'enable-something)

;; Appending and local hooks
(remove-hook! :append (one-mode second-mode) 'enable-something)
(remove-hook! :local (one-mode second-mode) 'enable-something)
(remove-hook! (one-mode second-mode) :append #'enable-something)
(remove-hook! (one-mode second-mode) :local #'enable-something)

;; With arbitrary forms
(remove-hook! (one-mode second-mode) (setq v 5) (setq a 2))
Expand Down
11 changes: 6 additions & 5 deletions modules/app/irc/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ playback.")
:after #'circe--irc-conn-disconnected
(run-hooks '+irc-disconnect-hook))

(add-hook 'lui-pre-output-hook
(add-hook! 'lui-pre-output-hook
(defun +irc-circe-truncate-nicks-h ()
"Truncate long nicknames in chat output non-destructively."
(when-let (beg (text-property-any (point-min) (point-max) 'lui-format-argument 'nick))
Expand All @@ -109,21 +109,21 @@ playback.")
(compose-region (+ beg +irc-left-padding -1) end
+irc-truncate-nick-char))))))

(add-hook 'doom-real-buffer-functions
(add-hook! 'doom-real-buffer-functions
(defun +circe-buffer-p (buf)
"Return non-nil if BUF is a `circe-mode' buffer."
(with-current-buffer buf
(and (derived-mode-p 'circe-mode)
(eq (safe-persp-name (get-current-persp))
+irc--workspace-name)))))

(add-hook 'circe-message-option-functions
(add-hook! 'circe-message-option-functions
(defun +irc-circe-message-option-bot-h (nick &rest ignored)
"Fontify known bots and mark them to not be tracked."
(when (member nick +irc-bot-list)
'((text-properties . (face circe-fool-face lui-do-not-track t))))))

(add-hook 'circe-mode-hook
(add-hook! 'circe-mode-hook
(defun +irc-add-circe-buffer-to-persp-h ()
(let ((persp (get-current-persp))
(buf (current-buffer)))
Expand Down Expand Up @@ -202,7 +202,8 @@ after prompt marker."
(goto-char (point-max))))

(add-hook! 'lui-mode-hook
(add-hook 'evil-insert-state-entry-hook #'+irc-evil-insert-h nil t))
(add-hook 'evil-insert-state-entry-hook #'+irc-evil-insert-h
nil 'local))

(mapc (lambda (cmd) (push cmd +irc-scroll-to-bottom-on-commands))
'(evil-paste-after evil-paste-before evil-open-above evil-open-below)))
Expand Down
4 changes: 2 additions & 2 deletions modules/app/rss/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ easier to scroll through.")
(make-directory elfeed-db-directory t)

;; Ensure elfeed buffers are treated as real
(add-hook 'doom-real-buffer-functions
(add-hook! 'doom-real-buffer-functions
(defun +rss-buffer-p (buf)
(string-match-p "^\\*elfeed" (buffer-name buf))))

;; Enhance readability of a post
(add-hook 'elfeed-show-mode-hook #'+rss-elfeed-wrap-h)
(add-hook! 'elfeed-search-mode-hook
(add-hook 'kill-buffer-hook #'+rss-cleanup-h nil t))
(add-hook 'kill-buffer-hook #'+rss-cleanup-h nil 'local))

;; Large images are annoying to scroll through, because scrolling follows the
;; cursor, so we force shr to insert images in slices.
Expand Down
3 changes: 2 additions & 1 deletion modules/completion/ido/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
(cl-loop for x in ido-temp-list
if (char-equal (string-to-char x) ?.)
collect x)))
(add-hook! (ido-make-file-list ido-make-dir-list) #'ido-sort-mtime)
(add-hook! '(ido-make-file-list-hook ido-make-dir-list-hook)
#'ido-sort-mtime)

;;
(ido-mode 1)
Expand Down
8 changes: 4 additions & 4 deletions modules/editor/multiple-cursors/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
;; disable evil-escape in evil-mc; causes unwanted text on invocation
(add-to-list 'evil-mc-incompatible-minor-modes 'evil-escape-mode nil #'eq)

(add-hook 'doom-escape-hook
(add-hook! 'doom-escape-hook
(defun +multiple-cursors-escape-multiple-cursors-h ()
"Clear evil-mc cursors and restore state."
(when (evil-mc-has-cursors-p)
Expand Down Expand Up @@ -80,7 +80,7 @@
(defvar +mc--compat-evil-prev-state nil)
(defvar +mc--compat-mark-was-active nil)

(add-hook 'multiple-cursors-mode-enabled-hook
(add-hook! 'multiple-cursors-mode-enabled-hook
(defun +multiple-cursors-compat-switch-to-emacs-state-h ()
(when (and (bound-and-true-p evil-mode)
(not (memq evil-state '(insert emacs))))
Expand All @@ -94,7 +94,7 @@
(goto-char point-before)
(set-mark mark-before))))))

(add-hook 'multiple-cursors-mode-disabled-hook
(add-hook! 'multiple-cursors-mode-disabled-hook
(defun +multiple-cursors-compat-back-to-previous-state-h ()
(when +mc--compat-evil-prev-state
(unwind-protect
Expand All @@ -115,7 +115,7 @@
(goto-char (1- (point)))
(push-mark (1- (mark))))))

(add-hook 'rectangular-region-mode-hook
(add-hook! 'rectangular-region-mode-hook
(defun +multiple-cursors-evil-compat-rect-switch-state-h ()
(if rectangular-region-mode
(+multiple-cursors-compat-switch-to-emacs-state-h)
Expand Down
8 changes: 4 additions & 4 deletions modules/editor/snippets/autoload/snippets.el
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ shadow the default snippet)."
+snippets-dir))))))))

;;;###autoload
(defun +snippets|show-hints-in-header-line ()
(defun +snippets-show-hints-in-header-line-h ()
(setq header-line-format
(substitute-command-keys
(concat "\\[yas-load-snippet-buffer-and-close] to finish, "
Expand All @@ -268,15 +268,15 @@ shadow the default snippet)."
;;; Hooks

;;;###autoload
(defun +snippets|enable-project-modes (mode &rest _)
(defun +snippets-enable-project-modes-h (mode &rest _)
"Automatically enable snippet libraries for project minor modes defined with
`def-project-mode!'."
(if (symbol-value mode)
(yas-activate-extra-mode mode)
(yas-deactivate-extra-mode mode)))

;;;###autoload
(defun +snippets|read-only-maybe ()
(defun +snippets-read-only-maybe-h ()
"Enable `read-only-mode' if snippet is built-in."
(when (file-in-directory-p default-directory doom-local-dir)
(read-only-mode 1)
Expand All @@ -287,7 +287,7 @@ shadow the default snippet)."
;;; Advice

;;;###autoload
(defun +snippets*expand-on-region (orig-fn &optional no-condition)
(defun +snippets-expand-on-region-a (orig-fn &optional no-condition)
"Fix off-by-one issue with expanding snippets on an evil visual region, and
switches to insert mode.
Expand Down
Loading

0 comments on commit a3e262c

Please sign in to comment.