Subject: Re: bug#75626: 31.0.50; Dired misses or double-processes files when auto-revert-mode is enabled

From: Michael Albinus <[email-masked]>
Date: Sun, 02 Feb 2025 11:05:57 +0100

Michael Heerdegen <[email-masked]> writes:

Hi Michael,

>> I know, that the variant with 'inhibit-auto-revert' has been
>> refused. However, I repeat this proposal. The difference is, that I
>> propose not to use t and nil as values, but a list of buffers or nil. By
>> this, a buffer could be suppressed temporarily from auto-revert by
>> adding it to this list, for example in a let-bind.
>
> But this will come with the same problems - or we need to change each
> command individually and third party packages can still be affected by
> the same issue - which is something I rather would prefer to avoid.

You must change any package, like you did already with
dired.el. auto-revert-mode needs an indication that it should pause for
the current buffer temporarily.

> What advantage would your approach have?  A global variable bound to a
> list of buffers has its advantages, but also its disadvantages, it still
> has to be kept up to date explicitly, dead buffers have to be removed,
> etc.  What you say seems a bit unrelated to what I outlined.

I have added a patch as proof-of-concept. It adresses your concerns.

It adds the global variable inhibit-auto-revert-buffers and the macro
inhibit-auto-revert. I ran the recipe given in the original posting of
this bug many times, even pressing 'Z' while the previous dired
operation didn't finish, and it works as expected.

Could you and Thassilo check this?

> I haven't thought about any other cases than dired at all, though.

They should apply a similar change as I have shown in dired.el. Of
course, this must be documented properly.

> Thx,
> Michael.

Best regards, Michael.

diff --git a/lisp/autorevert.el b/lisp/autorevert.el
index 1dcfe8e911f..135c09fc274 100644
--- a/lisp/autorevert.el
+++ b/lisp/autorevert.el
@@ -897,6 +897,31 @@ auto-revert--buffer-candidates
         (push buf new)))
     (nreverse (nconc new remaining))))

+;;;###autoload
+(defvar inhibit-auto-revert-buffers nil
+  "A list of buffers with suppressed auto-revert.")
+
+;;;###autoload
+(progn (defmacro inhibit-auto-revert (&rest body)
+  "Deactivate auto-reverting of current buffer temporarily.
+Run BODY."
+  (declare (indent 0) (debug ((form body) body)))
+  `(progn
+     ;; Cleanup.
+     (dolist (buf inhibit-auto-revert-buffers)
+       (unless (buffer-live-p buf)
+         (setq inhibit-auto-revert-buffers
+               (delq buf inhibit-auto-revert-buffers))))
+     (let ((buf (and (not (memq (current-buffer) inhibit-auto-revert-buffers))
+                     (current-buffer))))
+       (unwind-protect
+           (progn
+             (when buf (add-to-list 'inhibit-auto-revert-buffers buf))
+             ,@body)
+         (when buf
+           (setq inhibit-auto-revert-buffers
+                 (delq buf inhibit-auto-revert-buffers))))))))
+
 (defun auto-revert-buffer (buf)
   "Revert a single buffer BUF.

@@ -905,11 +930,12 @@ auto-revert-buffer
   (if (not (buffer-live-p buf))
       (auto-revert-remove-current-buffer buf)
     (with-current-buffer buf
-      ;; Test if someone has turned off Auto-Revert Mode
-      ;; in a non-standard way, for example by changing
-      ;; major mode.
-      (when (and (not auto-revert-mode)
-                 (not auto-revert-tail-mode))
+      ;; Test if someone has turned off Auto-Revert Mode in a
+      ;; non-standard way, for example by changing
+      ;; `inhibit-auto-revert-buffers' or major mode.
+      (when (or (and (not auto-revert-mode)
+                     (not auto-revert-tail-mode))
+                (memq (current-buffer) inhibit-auto-revert-buffers))
         (auto-revert-remove-current-buffer))
       (when (auto-revert-active-p)
         ;; Enable file notification.
diff --git a/lisp/dired.el b/lisp/dired.el
index 2eb6546107a..f967b00147f 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -944,9 +944,6 @@ dired-mark-if
                           ""))))
     (and (> count 0) count)))

-(defvar-local dired--inhibit-auto-revert nil
-  "A non-nil value prevents `auto-revert-mode' from reverting the buffer.")
-
 (defmacro dired-map-over-marks (body arg &optional show-progress
 				     distinguish-one-marked)
   "Eval BODY with point on each marked line.  Return a list of BODY's results.
@@ -983,8 +980,8 @@ dired-map-over-marks
   ;;endless loop.
   ;;This warning should not apply any longer, sk  2-Sep-1991 14:10.
   `(prog1
-       (let ((dired--inhibit-auto-revert t)
-             (inhibit-read-only t)
+       (inhibit-auto-revert
+       (let ((inhibit-read-only t)
              case-fold-search found results)
 	 (if (and ,arg (not (eq ,arg 'marked)))
 	     (if (integerp ,arg)
@@ -1024,7 +1021,7 @@ dired-map-over-marks
 	     (if found
 		 results
                (unless (eq ,arg 'marked)
-	         (list ,body))))))
+	         (list ,body)))))))
      ;; save-excursion loses, again
      (dired-move-to-filename)))

@@ -1295,11 +1292,11 @@ dired-buffer-stale-p
 	 ;; written by the user as in `wdired-mode'.
 	 buffer-read-only
          ;; When a dired operation using dired-map-over-marks is in
-         ;; progress, dired--inhibit-auto-revert is bound to some
-         ;; non-nil value and we must not auto-revert because that could
-         ;; change the order of files leading to skipping or
-         ;; double-processing (see bug#75626).
-         (not dired--inhibit-auto-revert)
+         ;; progress, inhibit-auto-revert-buffers is modified and we
+         ;; must not auto-revert because that could change the order of
+         ;; files leading to skipping or double-processing (see
+         ;; bug#75626).
+         (not (memq (current-buffer) inhibit-auto-revert-buffers))
 	 (dired-directory-changed-p dirname))))

 (defcustom dired-auto-revert-buffer nil
@@ -4089,10 +4086,10 @@ dired-internal-do-deletions
 	    (while l
 	      (goto-char (marker-position (cdr (car l))))
               (dired-move-to-filename)
-	      (let ((inhibit-read-only t)
-                    ;; Temporarily prevent auto-revert while deleting
-                    ;; entry in the dired buffer (bug#71264).
-                    (dired--inhibit-auto-revert t))
+              ;; Temporarily prevent auto-revert while deleting entry in
+              ;; the dired buffer (bug#71264).
+              (inhibit-auto-revert
+	      (let ((inhibit-read-only t))
 		(condition-case err
 		    (let ((fn (car (car l))))
 		      (dired-delete-file fn dired-recursive-deletes trash)
@@ -4108,7 +4105,7 @@ dired-internal-do-deletions
                   (quit (throw '--delete-cancel (message "OK, canceled")))
 		  (error ;; catch errors from failed deletions
 		   (dired-log "%s: %s\n" (car err) (error-message-string err))
-		   (setq failures (cons (car (car l)) failures)))))
+		   (setq failures (cons (car (car l)) failures))))))
 	      (setq l (cdr l)))
 	    (if (not failures)
 		(progress-reporter-done progress-reporter)