Hook Helpers

Copying

Copyright (C) 2016 Ian Dunn Copyright (C) 2017 Free Software Foundation, Inc.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Introduction

Savannah Project

Often times, I see people define a function to be used once in a hook. If they don’t do this, then it will be an anonymous function. If the anonymous function is modified, then the function can’t be removed. With a function outside of the add-hook call, it looks messy.

Hook Helpers are a solution to this. A “hook helper” is an anonymous, modifiable function created for the sole purpose of being attached to a hook. This combines the two commonly used methods mentioned above. The functions don’t exist, so they don’t get in the way of C-h f, but they can be removed or modified as needed.

Installation

Hook Helpers requires Emacs 25.1 or later.

To install hook helpers, you can clone from the git repo:

git clone https://git.savannah.gnu.org/git/hook-helpers-el hook-helpers
make -C hook-helpers compile autoloads

After that, setup is easy. Just add the following to your .emacs file (or equivalent):

(add-to-list 'load-path "/path/to/hook-helpers")
(load "/path/to/hook-helpers/hook-helpers-autoloads.el")

Examples

Let’s look at some examples.

Without using a hook helper, one must do the following:

(defun my/after-init-hook ()
  (set-scroll-bar-mode nil))
(add-hook 'after-init-hook 'my/after-init-hook)

If you forget the add-hook call, then this doesn’t do any good. Alternatively, you can use a lambda function:

(add-hook 'after-init-hook (lambda () (set-scroll-bar-mode nil)))

But then if you want to modify the function, it’s permanently stuck on the after-init-hook variable, and you have to deal with it. It’s not a problem for after-init-hook, which is used once, but would be a problem for a mode hook, like text-mode-hook.

With a hook helper, this is reduced to the following:

(define-hook-helper after-init ()
  (set-scroll-bar-mode nil))

Which handles everything for you.

In-Depth Usage

There are two macros in hook helpers: define-hook-helper and create-hook-helper.

The former is a basic case; it creates and adds a helper for a single hook. Most hooks have the -hook suffix, so we take advantage of that here for a little less typing. In order to add a helper to a non-standard hook, use the :suffix argument:

(define-hook-helper my ()
  :suffix function
  :append t
  (message "Hello!"))

We also introduce the :append keyword above, which does exactly what it sounds like.

There’s one more keyword for define-hook-helper: :name. This specifies an additional name for the new helper. Without this, its helper ID is just the name of the hook; with a :name, its ID is HOOK-NAME/NAME.

The work horse of hook helpers is create-hook-helper. This is the generic case, capable of adding itself to any number of hooks:

(create-hook-helper new-helper ()
  :hooks (hook-1-hook
          (hook-2-hook . t)
          hook-3-function)
  (message "Look at all that we can do!"))

This creates a new hook helper called “new-helper”, and adds it to hook-1-hook, hook-2-hook, and hook-3-function, appending to the latter.

The :hooks keyword can have the following form:

  • A single hook
  • A cons cell (HOOK . APPEND)
  • A list containing a mixture of the above two forms

This is called a “hook spec”.

Adding and Removing Helpers

To add or remove helpers, the functions add-hook-helper and remove-hook-helper are provided.

(add-hook-helper 'test-helper '(hook-the-first hook-the-second))
(remove-hook-helper 'test-helper 'hook-the-second)

As you can see, each of them takes the same arguments: a symbol denoting the helper to add or remove, and a quoted hook spec.

Seeing all the Available Helpers

Seeing lambda functions in your hooks can be confusing. While we don’t have a solution for that, we do have describe-hook-helpers, an interactive function that creates a pretty buffer containing all the defined hook helpers, grouped by the hooks to which they are attached.

Created: 2017-04-23 Sun 12:56

Validate