Subject: bug#50762: diff-update-on-the-fly doesn't update hunk headers while regexp-replacing lines

From: Konstantin Kharlamov <[email-masked]>
Date: Thu, 22 May 2025 11:25:48 +0300

Seems fixed on master.  I don't know when exactly it was fixed, I was
running all that time with diff-update-on-the-fly set to nil.  But just
as I was writing a workaround patch (attached for history purposes, in
case it might be useful at some point, but right now it isn't), I
tested and it turns out both query-replace-regexp as well as delete-
matching-lines result in hunks being updated on the fly.

So bug has been fixed, the report can be closed.
From d9024809f08a9a687297c7ceeb5fec37ae6cca21 Mon Sep 17 00:00:00 2001
From: Konstantin Kharlamov <[email-masked]>
Date: Thu, 22 May 2025 10:53:49 +0300
Subject: [PATCH] diff-mode: always update hunks on save (bug#50762)

Diff-mode defaults to updating hunks on the fly, which has a bug that
not every buffer change actually triggers the update.  In particular,
using `query-replace' over the buffer doesn't trigger that.  Work
around the problem by invoking the update on save unconditionally.

* lisp/vc/diff-mode.el (diff-mode): Factor out setting up change hooks
to a separate function `diff--setup-change-hooks'.
(diff-minor-mode): Factor out setting up change hooks to a separate
nction `diff--setup-change-hooks', and stop removing
iff-write-contents-hooks' since it is now added unconditionally.
(diff--setup-change-hooks): New function to set up diff-mode hooks,
with the code being factored out of diff major and minor modes
definition, with the change that hunks are now updated
unconditionally.
---
 lisp/vc/diff-mode.el | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index 459154f534b..452d32a756f 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -1602,6 +1602,15 @@ diff-mode-read-only
 (defvar whitespace-style)
 (defvar whitespace-trailing-regexp)
 
+(defun diff--setup-change-hooks ()
+  ;; Update hunks on save disregarding the `diff-update-on-the-fly'
+  ;; since some changes like `query-replace' don't trigger auto-updates,
+  ;; so they may not be valid. (bug#50762)
+  (add-hook 'write-contents-functions #'diff-write-contents-hooks nil t)
+  (when diff-update-on-the-fly
+    (setq diff--track-changes
+          (track-changes-register #'diff--track-changes-signal :nobefore t))))
+
 ;; Prevent applying `view-read-only' to diff-mode buffers (bug#75993).
 ;; We don't derive from `special-mode' because that would inhibit the
 ;; `self-insert-command' binding of normal keys.
@@ -1653,11 +1662,7 @@ diff-mode
               (setq diff-mode-read-only buffer-read-only))
             nil t)
 
-  ;; setup change hooks
-  (if (not diff-update-on-the-fly)
-      (add-hook 'write-contents-functions #'diff-write-contents-hooks nil t)
-    (setq diff--track-changes
-          (track-changes-register #'diff--track-changes-signal :nobefore t)))
+  (diff--setup-change-hooks)
 
   ;; add-log support
   (setq-local add-log-current-defun-function #'diff-current-defun)
@@ -1679,13 +1684,8 @@ diff-minor-mode
   (when diff--track-changes
     (track-changes-unregister diff--track-changes)
     (setq diff--track-changes nil))
-  (remove-hook 'write-contents-functions #'diff-write-contents-hooks t)
   (when diff-minor-mode
-    (if (not diff-update-on-the-fly)
-        (add-hook 'write-contents-functions #'diff-write-contents-hooks nil t)
-      (setq diff--track-changes
-            (track-changes-register #'diff--track-changes-signal
-                                    :nobefore t)))))
+    (diff--setup-change-hooks)))
 
 ;;; Handy hook functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-- 
2.49.0