3

I'm trying to run a piece of code when a buffer/window becomes selected. For an example use case, suppose I'm editing a buffer, save it, and kill it.

Suppose also the buffer "below" (that appears and becomes selected after my kill operation) has a list of files or something (like dired) that should be refreshed after I did my editing.

I was hoping to find a hook like buffer-selected-hook or window-selected-hook, preferably a local buffer hook, so that each time my "dired-like buffer" gets activated, it could run a refresh function.

I looked at many dozens of hooks with apropos, but couldn't see anything close to what I seek. Is there a standard way (or possible way) to run a piece of my refresh code when a buffer/window becomes selected?

Kevin
  • 1,308
  • 8
  • 20
  • Have a look at the `buffer-list-update-hook`, which is mentioned in the doc-string of `select-window`. – lawlist Jul 21 '16 at 23:18
  • Thank you for pointing me directly at that hook. It was in the list that I looked at, but I did not connect the idea of monitoring _all_ buffer list changes for just my singleton case. But sure enough, following the doc from the hook to `select-window` doc, I found this sentence: ` So if you think of running a function each time a window gets selected put it on `buffer-list-update-hook'.` Very good, I'll see how I fare... :-) – Kevin Jul 21 '16 at 23:39
  • I ended up using `kill-buffer-hook`, since I kill buffers fewer times than changing the buffer-list. Also, I already had a lambda function on the `kill-buffer-hook`, so adding another one was pretty easy. Thanks again for your pointers. Too bad Emacs doesn't have a local kill-buffer-hook -- that would be a much more targeted hook than a general kill buffer hook. – Kevin Jul 22 '16 at 00:14
  • I use a custom `kill-buffer` function instead of relying upon a `kill-buffer-hook` or a `buffer-list-update-hook` -- e.g., running my own custom hooks on the newly selected window that only fire completely if certain criteria is met; add/remove scroll-bars; redraw a cross-hairs based on cursor position; update the mode-line; prompt me to properly kill or save an e-mail buffer; with a universal argument delete all buffers that do not begin with a leading space; kill the `*scratch*` buffer and load my own `.scratch` file; delete certain frames; delete certain windows; exit recursive-edit, etc. – lawlist Jul 22 '16 at 00:34
  • So you're saying that you bind a custom defun to a keybinding to kill buffers, and that it does lots of custom stuff, and then eventually calls the underlying kill buffer interface? I guess that approach would work for me too, if I bound that function to some keys for my special buffers. Yet more to think about.. :-) – Kevin Jul 22 '16 at 03:56
  • The advantage of a custom kill-buffer function is that you can get your lay of the land before actually killing the buffer, and in fact, you don't even need to be visiting that buffer/window when finally killing the buffer. I only use that custom function on an interactive basis with the super/command-w keyboard shortcut -- during the custom function, it does call `(kill-buffer buffer)`. The default behavior of `kill-buffer` and anything assigned to the `kill-buffer-hook` by any major/minor modes remain intact. I have custom interactive functions for switching to other windows and so forth. – lawlist Jul 22 '16 at 04:07
  • If you set up appropriate conditions, you can use your custom kill-buffer function interactively on all buffers rather than just special buffers -- i.e., programmatically limit the affect of certain components of the custom function -- e.g., `(when (eq major-mode 'name-of-mode) . . .)` or `(when name-of-minor-mode-is-active ...)`. – lawlist Jul 22 '16 at 04:10
  • @Kevin: like all hooks, you can add a function to the `kill-buffer-hook` of a particular buffer. Just use the `local` argument of `add-hook` for that, – Stefan Jul 22 '16 at 18:03
  • Thanks for your comments, both of you. @lawlist, I found out the hard way what you meant by having my hook function run when I'm not even visiting the buffer of interest. I added more qualification code to the hook to only treat the buffers of interest. @Stefan, ...Doh! I never even thought to read the doc on `add-hook` to read about local hooks. I would have thought local behaviour was described with the hook. Now I've learned something new again and will go try a local hook addition -- thanks to you both! – Kevin Jul 22 '16 at 20:34
  • There is an interesting answer in the link to the following thread discussing how a change of mode will not affect the value of the `kill-buffer-hook` due to a `permanent-local` assignment -- it is something to be aware of because the `kill-buffer-hook` is not buffer-local by design, but can be made local: http://emacs.stackexchange.com/a/16423/2287 – lawlist Jul 22 '16 at 22:16
  • Thank you for the thread link. The idea sounds familiar. I think I read somewhere that once you make a variable local for one buffer, it's local for _all_ buffers. As if the obarray could only carry one "type" of "this is local" indicator on the symbol name. I didn't have in my mind the difference between "local" and "permanent-local" though. From the doc: **Warning:** do not use `make-local-variable` for a hook variable. The hook variables are automatically made buffer-local as needed if you use the local argument to add-hook or remove-hook.` – Kevin Jul 22 '16 at 23:05
  • 1
    I tried out the local argument of `add-hook`, and it did the job just fine, without the hook function having to watch for other buffer kills. Thanks @stefan for the idea. – Kevin Jul 24 '16 at 19:41

1 Answers1

0

I'm posting a summary answer just to clear the question, so it has an "answer."

First, I think my original question was off target to the final answer. I wanted to notify a "parent" buffer when a child buffer that it spawned was killed, so the parent could refresh the buffer contents when it regained focus after the child (temp) buffer was killed. So my focus was on finding out how the parent buffer could figure out that it just became active.

There was not a easy way to find that out, or I suppose someone would have posted an answer.

So what really worked was having the child buffer call a defun (a hook function) that just updated the parent's contents. At first I used the global buffer-kill-hook, but that led to problems.

First, my hook function had to protect against every other killed buffer running the guts of my hook function. So I modified my hook function to look at the filename regexp of the killed buffer, so I could spot the filenames that were normally child buffers.

That was ok so long as only the parent edited those files by spawning them into a child buffer. But when I edited those special filenames through dired and killed them, my hook function tried to update a parent buffer that wasn't there.

When Stefan pointed out the "local" argument to add-hook, I used that feature to have the parent install a buffer-local hook on the child buffer, so that my hook function could only be run by a child who was spawned by the parent and who had the local buffer-kill-hook installed by the parent.

Now I can edit the special files through dired without bad effects, since the buffers don't have a local buffer-kill-hook installed by a parent, and because I'm not using the global buffer-kill-hook.

So everything is working fine now. Thanks to everyone for helping.

Kevin
  • 1,308
  • 8
  • 20