Hi everyone,
I noticed my emacs started to lag after a few days and it turned
out there were over 2000 `org-indent-initialize-agent' timers in
`timer-idle-list'.
That caused a delay of .45 secs on every .2s idle pause.
The patch attached cancels the timer if the
`org-indent-agentized-buffers' list is empty and there is a timer.
The code used to take an empty list as meaning there was no agent
running, but the list empties as soon as a buffer finishes
initializing or turns the mode off, while the agent only cancels
itself on its next run. A buffer enabling the mode in between
starts a second timer and overwrites `org-indent-agent-timer'; the
old timer later cancels the new one through that variable and
keeps running, unreferenced.
Reproducing:
#+begin_src emacs-lisp
(require 'org-indent)
(dotimes (_ 3)
(with-current-buffer (generate-new-buffer "x")
(insert "* H\nText\n")
(org-mode)
(org-indent-mode 1)
(org-indent-initialize-agent)))
(seq-count (lambda (tm)
(eq (timer--function tm)
#'org-indent-initialize-agent))
timer-idle-list)
;; => 3, expected 1
#+end_src
The patch could be better by moving the duplicated push above the `if', with the test becoming whether
the list was empty before it:
#+begin_src emacs-lisp
(push (current-buffer) org-indent-agentized-buffers)
(unless (cdr org-indent-agentized-buffers)
(when (timerp org-indent-agent-timer)
(cancel-timer org-indent-agent-timer))
(setq org-indent-agent-timer
(run-with-idle-timer
0.2 t #'org-indent-initialize-agent)))
#+end_src
That reads cleaner, but makes the diff a restructure rather than
an addition, so I kept the patch minimal.
Org main f46d8a23a, GNU Emacs 32.0.50.
Marcel
>From 2b12b6fec412d72e7f5f2901d8785cce1ae6b092 Mon Sep 17 00:00:00 2001
From: Marcel van der Boom <[email protected]>
Date: Mon, 2 Nov 2026 15:37:01 +0100
Subject: [PATCH] org-indent-mode: Do not orphan a still scheduled agent timer
* lisp/org-indent.el (org-indent-mode): Cancel a live
`org-indent-agent-timer' before starting a new one.
An empty `org-indent-agentized-buffers' does not mean the agent is
gone: it only cancels itself on its next run. A buffer enabling
`org-indent-mode' in between started a second timer and overwrote the
variable. The old timer then cancelled the new one through that
variable and kept running, unreferenced. Opening many Org buffers
programmatically accumulated 2109 such timers over six days, costing
about 0.45 s of every idle pause and making typing lag.
---
lisp/org-indent.el | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lisp/org-indent.el b/lisp/org-indent.el
index b6284da15..66708bcfc 100644
--- a/lisp/org-indent.el
+++ b/lisp/org-indent.el
@@ -204,6 +204,9 @@ define-minor-mode org-indent-mode
(if org-indent-agentized-buffers
(push (current-buffer) org-indent-agentized-buffers)
(push (current-buffer) org-indent-agentized-buffers)
+ ;; an empty list is not equal to agent gone!
+ (when (timerp org-indent-agent-timer)
+ (cancel-timer org-indent-agent-timer))
(setq org-indent-agent-timer
(run-with-idle-timer 0.2 t #'org-indent-initialize-agent))))
(t
--
2.55.0