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?


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. 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

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

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
  • 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 '19 at 3:00
  • @sanityinc TIL derived-mode-hook-name. nice tip!
    – waymondo
    Apr 4 '19 at 5:19

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.


Following up on @legoscia's answer with some code, I solved the same problem as follows. Note the addition of a check for fundamental-mode, since otherwise the hook will trigger on mini-buffers as well.

(defcustom non-special-mode-hook nil
  "Hook run when entering non-special modes (catches 'prog-mode', 'text-mode', and 'fundamental-mode')."
  :type 'hook)

(add-hook 'after-change-major-mode-hook
          (lambda () "Trigger non-special-mode hooks that are also fundamental, so don't catch minibuffers."
            (when (and (not (derived-mode-p 'special-mode))
                       (derived-mode-p 'fundamental-mode))
              (run-hooks 'non-special-mode-hook))))

From there you can hook into 'non-special-mode-hook like normal, or change the predicates in the when call to narrow the scope of which modes trigger the hook.


Maybe you can try this:

(setq lisp-dialects-mode-hook '(lisp-mode-hook
                            ;; common-lisp-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.