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.