Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs-lisp hooks for detecting change of active buffer?

Tags:

emacs

hook

I am trying to execute when the active buffer has changed by either

  1. Changing the buffer in the current window (e.g. C-x <left>).
  2. Switching to another window (C-x o).
  3. Switching to another frame.

Are their hooks suitable for detecting this?

What I figured out so far

Looking through the Standard Hooks I found the following options, none of which quite do what I want:

  • buffer-list-update-hook is called for both (1) and (2). It is however unsuitable, because it is run before the buffer is changed, while I want to know what the current-buffer after the change is.

  • window-configuration-change-hook can be used to detect a change of the buffer displayed in the current window, and it is run after the change, as needed. It is however not run for M-x other-window.

  • mouse-leave-buffer-hook seems viable for detecting mouse-based window switching, but it gets called a bit often (for me four times upon switching windows with the mouse, three times before and once after switching), which requires additional logical to prevent multiple execution.

  • post-command-hook would be viable but a bit heavy handed, risking significant slow-down of the editor by even minor bugs.

  • Since my action would need to use with-selected-window, which triggers these hooks, care has to be taken to avoid endless loops where the hook triggers itself.

like image 647
kdb Avatar asked Nov 23 '17 12:11

kdb


2 Answers

Judging from the comments, the answer to this question is “No, there is no such hook.”

Additionally, some of the hooks mentioned in my question, are also triggered by changes, which are not user-visible, such as temporary changes due to with-current-buffer and with-selected-window.

However, using post-command-hook has proven to be a non-issue for performance, since the required state-check is cheap.

Alternative

Probably obvious, but stated for completeness.

  • Store state information in a global variable, in a frame-parameter, in a window-parameter or in a buffer-local variable, whichever is most applicable to the use-case. In my use-case, this necessary unique state is was defined by current-buffer, current-window, and in one case line-beginning-position.*

  • In post-command-hook, check if the state has changed, possibly skipping even that, if this-command is self-insert-command.

  • If it has, perform the intended action and update the stored state.

* line-number-at-pos is unsuitable, because it counts lines by iterating over the buffer from point-min to point, making it generally cheap, but not cheap enough to be executed after every typed character.

like image 54
kdb Avatar answered Nov 11 '22 22:11

kdb


Emacs27.1 introduce a new variable called `window-buffer-change-functions'

like image 9
dingyi342 Avatar answered Nov 11 '22 21:11

dingyi342