Set Variable in Hook

I've just recently started to use helm-dash for most of my documentation look-ups. I did however find it a bit awkward to configure. For it to work its magic, each major-mode should set helm-dash-docsets to a list of strings with the docsets it should activate. The most straightforward way that I found to do this was this was with a small lambda in the major-mode hook.

That is, something like this:

(use-package helm-dash
  :ensure t
  :pin melpa
  (add-hook 'python-mode-hook  (lambda () (setq-local helm-dash-docsets '("Python 3"))))
  (add-hook 'rust-mode-hook    (lambda () (setq-local helm-dash-docsets '("Rust"))))
  (add-hook 'shell-script-hook (lambda () (setq-local helm-dash-docsets '("Bash"))))
  (add-hook 'c-mode-hook       (lambda () (setq-local helm-dash-docsets '("C"))))
  (add-hook 'c++-mode-hook     (lambda () (setq-local helm-dash-docsets '("C++" "C")))))

Using lambda in a hook variable is discouraged however since there's no simple way to refer back to it. Naturally, you can use existing hooks to set this variable or create new functions to do so but that would either place out-of-context variables in hooks or be unnecessarily verbose. To that end, I figured that I might as well generate the functions for each hook with a lisp macro:

(defmacro set-variable-in-hook (hook variable value &optional name)
  "Create a proper HOOK function for setting VARIABLE to VALUE.

NAME can be used to set the name of the defined function."
  (let* ((hname (symbol-name hook))
	 (vname (symbol-name variable))
	 (fname (intern (or name (format "set-%s-in-%s" vname hname)))))
       (defun ,fname ()
	 (setq-local ,variable ,value))
       (add-hook (quote ,hook) (function ,fname)))))

This macro simply creates a function called set- variable -in- hook, and adds the hook as usual.

Using this macro for the helm-dash example above gives me this:

(use-package helm-dash
  :ensure t
  :pin melpa
  (set-variable-in-hook python-mode-hook  helm-dash-docsets '("Python 3"))
  (set-variable-in-hook rust-mode-hook    helm-dash-docsets '("Rust"))
  (set-variable-in-hook shell-script-hook helm-dash-docsets '("Bash"))
  (set-variable-in-hook c-mode-hook       helm-dash-docsets '("C"))
  (set-variable-in-hook c++-mode-hook     helm-dash-docsets '("C++" "C")))

In my opinion this improves the readability and the management of these kinds of variables quite a bit.


Comments powered by Disqus