Homepage: https://github.com/neil-smithline-elisp/defhook
Author: Neil Smithline
Updated:
Declare hook functionality rather dynamically implementing it
`defhook' provides a declarative mechanism for defining
functionality for hooks. For example:
(defhook ignore-case (dired-mode-hook)
"Always ignore case in `dired-mode' searches."
(make-local-variable 'case-fold-search)
(setq case-fold-search t))
Especially for new elispers, `defhook' provides hook manipulation
functionality in a simple and familiar (ie: `defhook' looks like
`defun') package.
`defhook' also encourages the use of multiple, well-documented hook
functions for one hook rather than a single function for that hook.
The simpler syntax and the smaller granularity of hook
functionality makes allows hook functions to be copied-and-pasted
-- even among non-elisp programmers.
Other than `defhook', hook functionality is generally written in
one of two ways: using functions or using `lambda's. An example of
a function to implement the case folding in `dired' buffers is:
(defun buffer-case-fold-search ()
"Always ignore case for searches in this buffer.
(make-local-variable 'case-fold-search)
(setq case-fold-search t))
(add-hook 'dired-mode-hook #'buffer-case-fold-search)
The readibility and maintainability of hook functionality using
`lambda's quickly degrades as the functionality requires more code
to be implemented. For example, using a `lambda' to implement the
above `dired-mode-hook' functionality looks like:
(add-hook 'dired-mode-hook
#'(lambda ()
(make-local-variable 'case-fold-search)
(setq case-fold-search t))
`defhook's declaration has additional functionality:
- Local hook functionality:
(defhook ignore-case (dired-mode-hook :local t) ...)
- Appending function to a hook rather than prepending it:
(defhook ignore-case (dired-mode-hook :append t) ...)
- Incorporation of `eval-after' functionality:
(defhook ignore-case (dired-mode-hook :eval-after 'dired-mode) ...)
- By default, `defhook' functions are declared to be
`interactive' so that they can be called for debugging or
other reasons. This can be disabled by:
(defhook ignore-case (dired-mode-hook :interactive-spec nil) ...)
- `defhook' helps to prevent typos by validating that the hook
actually exists and generating an error if not. This can
be disabled with:
(defhook ignore-case (dired-mode-hook :validate-hook-name nil) ...)
- While most hooks take no arguments, some do. `defhook'
allows you to declare parameters for hook functions with:
(defhook something-or-other
(window-scroll-function
:hook-args (window new-display-start) ...)
- `defhook' functions can be "commented out" by using the :op
keyword:
(defhook ignore-case (dired-mode-hook :op no-op) ...)
- While not a common operation, removing a specific hook can
sometimes be difficult. `defhook' will automatically remove
a hook function by evalating:
(defhook ignore-case (dired-mode-hook :op delete) ...)
- `defhook' has a series of informational messages that can be
controlled by customization settings.
- The naming functions generated by `defhook' are controlled
by the package customization options and are intended to
be self-documenting as well as easy to access via various
Emacs' help functions. The value of my `dired-mode-hook'
is:
'(ngs:dired-mode-hook:my-key-bindings
ngs:dired-mode-hook:ignore-case obof-inhibit-pop-up-windows
obof-inhibit-frame-creation)
FYI: "ngs" are my initials.