After having a problem with debugging a package I write, I finally tracked down the problem to the following: auto-revert-mode is making kill-buffer-hook buffer-local (which is fine by me). The problem is that every library (auto-)loaded afterwards (while the buffer is still active) only "sees" the buffer-local binding, and any add-hook only modifies the buffer-local binding.

Here are a few steps to reproduce the problem using only standard emacs libraries:

(find-file "foo.el")

kill-buffer-hook                  ; => (uniquify-kill-buffer-function vc-kill-buffer-hook)
(default-value 'kill-buffer-hook) ; => (uniquify-kill-buffer-function vc-kill-buffer-hook)

;; Turn on `auto-revert-mode': `kill-buffer-hook' becomes buffer-local

kill-buffer-hook                  ; => (auto-revert-notify-rm-watch uniquify-kill-buffer-function vc-kill-buffer-hook)
(default-value 'kill-buffer-hook) ; => (uniquify-kill-buffer-function vc-kill-buffer-hook)

;; Subsequently load a library which adds a `kill-buffer-hook'
;;   only the local binding is modified; no other buffer will ever see
;;   the hook installed by `tramp'
(require 'tramp)

kill-buffer-hook                  ; => (tramp-delete-temp-file-function auto-revert-notify-rm-watch uniquify-kill-buffer-function vc-kill-buffer-hook)
(default-value 'kill-buffer-hook) ; => (uniquify-kill-buffer-function vc-kill-buffer-hook)

;; The same thing happens (unsurprisingly) for auto-loaded libraries
(browse-url "emacs.stackexchange.com")

kill-buffer-hook                  ; => (browse-url-delete-temp-file tramp-delete-temp-file-function auto-revert-notify-rm-watch uniquify-kill-buffer-function vc-kill-buffer-hook)
(default-value 'kill-buffer-hook) ; => (uniquify-kill-buffer-function vc-kill-buffer-hook)

So I guess my question is: is this normal and desired behaviour? Shouldn't all buffers see the hooks installed by subsequently loaded packages?

Although the problem here is specifically caused by auto-revert-mode and kill-buffer-hook, I'm guessing this situation is fairly more general and could happen for a lot of libraries and hooks...

1 Answer 1

  1. kill-buffer-hook is not automatically buffer-local. That it is, it does not automatically become buffer-local whenever its value is set.

  2. AFAICT, auto-revert-mode does not make kill-buffer-hook be buffer-local.

  3. Something else in your setup no doubt does make it buffer-local in some buffer.

  4. kill-buffer-hook, although not buffer-local to start with, has the property that it if it is ever made buffer local then it will be buffer-local permanently.

    You can see this from C-h v kill-buffer-hook:

    This variable's value is permanent if it is given a local binding.

    See the Elisp manual, node Creating Buffer-Local. There you will see this:

    A buffer-local variable is “permanent” if the variable name (a symbol) has a permanent-local property that is non-nil. Such variables are unaffected by kill-all-local-variables, and their local bindings are therefore not cleared by changing major modes. Permanent locals are appropriate for data pertaining to where the file came from or how to save it, rather than with how to edit the contents.

    This means that when you use a different major mode the last local binding is kept, which is exactly the behavior you reported.

  5. If you want to change the buffer-local value then you will need to do so explicitly, using, for example setq. You can also change the default value of the variable, using setq-default.

  • 1
    Thanks for looking at it. Regarding point 2., I had already checked this and found a (make-local-variable 'kill-buffer-hook) in file autorevert.el. After your comment, I double checked using the latest emacs sources, and it appears the problem has been fixed by commit 9e41e0bc. And from there I learned that this problem was reported as bug 20601 Sep 7, 2015 at 18:43
  • Ah! Interesting. And good checking. I too should have looked further than just checking the latest Emacs 25 snapshot I have. Your comment greatly improves this Q & A for others.
    – Drew
    Sep 7, 2015 at 20:43

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.