There seems to be a bug in clojure-mode (mentioned here) because it does things in a mode hook (for paredit-mode) but doesn't undo them when the mode is turned off.

I understand that add-hook can register a function to run when a mode is turned on, but is there a way to run a hook when a mode is turned off?

Here's a github link see the clojure-mode code that adds the hook.

  • To further clarify, minor modes are entered and exited (and so hooks run on both occasions). Major modes are never 'exited' at all, so they cannot run a hook before a different major mode is called. Instead the new major mode effectively just clobbers all the buffer-local settings and starts over -- but the standard way that they do that means that change-major-mode-hook runs (with the original major mode still enabled), before anything else happens. – phils Jan 22 '19 at 19:39
  • stackoverflow.com/a/19295380/324105 has more details about major modes and hooks, if you're interested. – phils Jan 22 '19 at 19:46

You can use the hook variable change-major-mode-hook for cleaning up major mode settings. It is called right before killing the local variables of the old major mode.
Example code:

(defun clojure-leave-clojure-mode-function ()
  (when (eq major-mode 'clojure-mode)
    (message "Leaving clojure-mode.")))

(add-hook 'change-major-mode-hook #'clojure-leave-clojure-mode-function)
| improve this answer | |
  • This is a great suggestion, but in general I think users shouldn't need to run any cleanup code manually, the major-mode should take care of this by making changes buffer locally. – clemera Jan 22 '19 at 17:12
  • @clemera If there is a bug in clojure-mode then that bug must be fixed. That is clear. Beside that take a look at the value of change-major-mode-hook. If you have cc-mode loaded then there is at least c-leave-cc-mode-mode. It is not so uncommon to use it for cleanup tasks. – Tobias Jan 22 '19 at 17:16
  • Ok, but the major-mode should set it. – clemera Jan 22 '19 at 17:17

Not for major-modes, for minor-modes the hook runs on exit as well (See here). The major mode is responsible to make changes which affect other packages buffer locally. You probably should send a PR to change the add-hook code to install the hooks locally for the clojure-mode buffer:

(add-hook 'paredit-mode-hook #'clojure-paredit-setup nil 'local)


Looking at the code, this will not suffice. clojure-paredit-setup needs to be changed to do its changes buffer locally, too.

| improve this answer | |
  • This won't solve the problem consistently, because clojure-mode adds the hook to paredit-mode-hook every time it runs. Your code removes the offending hook, but it will be replaced every time you open a new file in clojure-mode. – Tyler Jan 22 '19 at 19:53
  • Hm, but I suggested to add it buffer locally, the idea is that when activating clojure-mode it changes paredit-mode-hook only locally, for every buffer where it's activated. This way the global paredit-mode-hook is not effected, so there is nothing that need to be undone for non clojure buffers. BUT as I pointed out in the edit, clojure-paredit-setup needs to be changed, too because it changes other global variables. – clemera Jan 22 '19 at 22:43

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.