8

I want to write a minor which evaluates some code in the buffer after saving a file. I activate after-save-hook for this mode:

(add-hook 'my-minor-mode-name-hook #'(lambda () (add-hook 'after-save-hook #'a-func-from-my-minor-mode))

Everything works as intended until I disable the minor mode with the command my-minor-mode-name. I get the message that the mode has been disabled but after-save-hook is still active (although evaluating after-save-hook in the buffer indicates that a-func-from-my-minor-mode is not on the list).

I want a behaviour where disabling the minor mode removes automatically the hook -- how should I fix that?

3
  • 2
    Don't quote lambdas or use #' with them. The latter doesn't add anything, and simple quoting (') prevents byte-compiling.
    – Drew
    Jan 13, 2019 at 6:44
  • Assuming this is a buffer-local minor mode, you definitely shouldn't be adding to after-save-hook globally. Use the LOCAL parameter.
    – phils
    Jan 13, 2019 at 7:21
  • @phils Yes, Stefan too pointed that out below. I had a misunderstanding of how the nested hooks work, treating the hook which runs them rather as a "context" than a "trigger".
    – caseneuve
    Jan 13, 2019 at 8:46

1 Answer 1

10

The minor mode's hook is called both when activating and deactivating the minor mode, so how 'bout

(add-hook 'my-minor-mode-name-hook
          (lambda ()
            (if my-minor-mode-name
                (add-hook 'after-save-hook #'a-func-from-my-minor-mode nil 'local)
              (remove-hook 'after-save-hook #'a-func-from-my-minor-mode 'local))))

Note that your calls to add-hook are both global, so even though you only add to after-save-hook when the minor mode is called, this addition applies to all buffers. Maybe that was indeed what you wanted, but I assumed it's not in the above example code.

6
  • Than you. Of course you're right -- I thought that nested hook would work only in the context of the mode that runs the hook, but it works rather like a trigger not a context. Can you please indicate where in the docs I can find the info "The minor mode's hook is called both when activating and deactivating the minor mode". I was looking in "Hooks" and "Minor modes" but I missed that.
    – caseneuve
    Jan 13, 2019 at 8:41
  • @caseneuve: good question, I don't know where it's documented. Can you open a bug report for that? It should at the very least be mentioned in the docstring.
    – Stefan
    Jan 13, 2019 at 14:40
  • 1
    OK, I sent (my first) bug report.
    – caseneuve
    Jan 14, 2019 at 9:15
  • Worth noting though, apparently that doesn't work if the buffer gets killed. So, if you want to undo something done when setting a minor mode up, apparently you need to come up with an ad-hock hack. The closest I've found to work is the delete-frame-functions hook.
    – Hi-Angel
    May 19, 2023 at 9:51
  • @Hi-Angel: usually what you setup when the minor mode is enabled affects only the buffer, so there's nothing to do when the buffer is killed (in which case the minor mode is never turned off). How to handle the other cases depends completely on the details of what your hook affects. A popular option is to disable your auxiliary code (e.g. your a-func-from-my-minor-mode) lazily: Instead of trying to detect precisely when the minor mode disappears, you can just check in a-func-from-my-minor-mode whether the minor mode is still around and if not, have it deactivate itself.
    – Stefan
    May 19, 2023 at 12:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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