Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs -- creating / deleting a `buffer-local` repeating idle-timer

Tags:

emacs

elisp

I have a minor-mode that uses a repeating idle-timer:

(timer-activate-when-idle
    (run-with-idle-timer 0.2 t 'function-name))

I am trying to figure out the best way to handle the same minor-mode being active in more than one buffer, and how to cancel the timer when killing the buffer or deactivating the minor-mode without affecting other buffers.

My preferred way to handle this, if it is even possible, would be to create a buffer-local idle-timer and assign it a unique name / identification for purposes of canceling. If this method is within the realm of possibility, then an example would be greatly appreciated.

My least preferred method to handle this would be to loop through all open buffers to ascertain whether this particular minor-mode is active in any of them, and if not, then cancel the timer. In other words, there would be one timer that services all buffers.

Any other ideas on how to handle this situation would be greatly appreciated.

[NOTE: I realize that I can put in a condition that prevents the timer from taking any action (e.g., if not minor-mode xyz), however, I like to be tidy and clean-up after myself when there is no longer a need for a particular timer.]

like image 897
lawlist Avatar asked Jun 03 '14 05:06

lawlist


1 Answers

Well, you can pretty much just do what you described.

(defvar-local my-local-timer nil "Buffer-local timer.")

(defun do-something-with (buf)
  "Callback function for `my-local-timer'."
  (when (buffer-live-p buf)
    (with-current-buffer buf
      ...)))

(setq my-local-timer
      (run-with-idle-timer 0.2 t 'do-something-with (current-buffer)))

(add-hook 'kill-buffer-hook
          (lambda () 
            (when (timerp my-local-timer) 
              (cancel-timer my-local-timer))))

The timer object is added to timer-idle-list, and the variable is just so that you can access it by name when you want to modify/cancel it. As such, there's no problem with the variable being buffer-local (unless you manage to kill the buffer without cancelling the timer).

Whether you actually want to have a separate timer running per-buffer is another matter, but you can certainly do it if you want to (or need to), and there's probably less house-keeping to do this way.

If you opt for the single timer route, but you'd rather not loop through all buffers, you might simply maintain a list of the buffers of interest (enabling the mode could add the current buffer; disabling the mode could remove it), and then you can iterate over those. As there are ways in which the list could be left with stale entries, your timer function would want to check that each buffer was valid, and that the mode variable was still set, and remove the invalid entries. If the list is ever empty, you can cancel the timer.

like image 147
phils Avatar answered Sep 19 '22 10:09

phils