14

There are certain things like the display of trailing whitespace, display of buffer boundaries, rainbow-colored delimiters and many more I'd like to enable in most modes or rather, all programming- and text-related ones (because displaying trailing spaces in, say ediff-mode, would clash with the major mode) instead of using a globalized minor mode with exception rules. Since most modes are derived from either prog-mode or text-mode, adding the function in question to both prog-mode-hook and text-mode-hook does work, however there are enough modes not following this specification, such as css-mode or LaTeX-mode.

I'd like to define a hook that encompasses all these modes for the time being to only add functions to one hook. Let's call it non-special-mode-hook (to distinguish it from special-mode-hook). How would I be able to create such a hook that is run for all major modes it is made for?

19

Just group those settings together into a function, and add that function to all of the relevant hook functions:

(defun my-non-special-mode-setup ()
  (setq show-trailing-whitespace t)
  ...)
(dolist (hook '(prog-mode-hook text-mode-hook css-mode-hook ...))
  (add-hook hook 'my-non-special-mode-setup))

No other way to do this would be more concise: whatever happens, somewhere you're going to have either a whitelist or blacklist of modes. In practice, you'll only find a few modes which need adding to the list, so I'd suggest just keeping things simple.

In my own config, I use exactly this trick to unify the configuration of several lisp-oriented modes.

  • Thank you, I think I'll adapt this solution for other useful groups (such as the lispy ones), too. – wasamasa Sep 30 '14 at 13:04
  • 1
    That's exactly what I do myself: github.com/purcell/emacs.d/blob/… – sanityinc Sep 30 '14 at 13:07
  • 1
    Excellent, could you maybe add the URL to your answer? I believe the highlighted snippet not only explains the actual usage very well, but also demonstrates further usage, such as using an Emacs Lisp related "hook" as subset of a bigger "hook" and how one would automatically create hook names from existing major modes with derived-mode-hook-name. – wasamasa Sep 30 '14 at 13:18
  • I like this more than mine, just for the (dolist ...) vs (add-hook ...) <repeat>. I'd only stick with mine when keeping mode-specific changes separate (file-per-mode, use-package, el-get). Both are all-in-one-place solutions, but from different points-of-view. – Jonathan Leech-Pepin Sep 30 '14 at 14:34
  • Be aware that if you do not provide a non-nil APPEND argument to add-hook here then the hooks will be invoked in the reverse order from the list order you provide. Nothing wrong with that; just be aware of it, in case the order matters. – Drew Sep 30 '14 at 22:41
5

You could add a function to after-change-major-mode-hook, that checks whether the new mode is an interesting one (possibly through (not (derived-mode-p 'special-mode))), and if so runs non-special-mode-hook.

  • This sounds pretty nifty (once one has figured out all "unspecial" modes since there are a few that just use fundamental-mode, but do more than just displaying text), but a bit too magic for my taste. Hence the upvote. – wasamasa Sep 30 '14 at 14:40
4

I found myself often doing @sanityinc's pattern of wrapping my settings and minor mode activations in a defun and looping through hooks to call it, but I wanted a cleaner approach so I wrote this macro:

(defmacro hook-modes (modes &rest body)
  (declare (indent 1))
  `(--each ,modes
     (add-hook (intern (format "%s-hook" it))
               (lambda () ,@body))))

Note: I'm dash.el for cleanliness but it could easily be adapted to use (dolist).

Then you can define grouped modes as list variables and use it like so:

(defvar progish-modes
  '(prog-mode css-mode sgml-mode))

(hook-modes progish-modes
  (highlight-symbol-mode)
  (highlight-symbol-nav-mode))
  • 1
    Note that here you can use derived-mode-hook-name to get the name of a mode's hook variable, thereby avoiding the intern trick. – sanityinc Apr 3 at 3:00
  • @sanityinc TIL derived-mode-hook-name. nice tip! – waymondo Apr 4 at 5:19
1

Rather than define a new hook that works for all these non-derived modes you can do the following.

(defun run-my-hooks ()
  "Run all the following functions in the hook"
  (smartparens-mode 1)
  (whitespace-mode 1)
  (my-needed-mode 1)
  ...)

(add-hook 'specific-mode-hook 'run-my-hooks)
(add-hook 'another-mode-hook 'run-my-hooks)

You'll still need to add it to all the modes, but by defining your function to include all the modes you will only have to change one definition when adding/removing addtional features.

-2

Maybe you can try this:

(setq lisp-dialects-mode-hook '(lisp-mode-hook
                            lisp-interaction-mode-hook
                            emacs-lisp-mode-hook
                            ;; common-lisp-mode-hook
                            scheme-mode-hook
                            clojure-mode-hook
                            cider-repl-mode-hook
                            ))

(add-hook 'lisp-dialects-mode-hook 'func)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.