]> git.eshelyaron.com Git - emacs.git/commitdiff
New global minor mode vc-auto-revert-mode
authorSean Whitton <spwhitton@spwhitton.name>
Sun, 13 Jul 2025 11:50:22 +0000 (12:50 +0100)
committerEshel Yaron <me@eshelyaron.com>
Thu, 24 Jul 2025 08:22:57 +0000 (10:22 +0200)
* lisp/vc/vc-hooks.el (auto-revert-mode): Declare.
(vc-auto-revert-mode): New global minor mode.
(vc-turn-on-auto-revert-mode-for-tracked-files): New function.
* lisp/vc/vc-dispatcher.el (auto-revert-mode)
(auto-revert-buffers): Declare.
(vc-resynch-window): Don't call vc-revert-buffer-internal when
auto-revert-mode will revert the buffer.  Call
auto-revert-buffers to ensure that this reversion happens in a
timely manner.
* lisp/vc/vc.el (vc-register): Apply vc-auto-revert-mode to
buffers visiting newly registered files.
* lisp/emacs-lisp/easy-mmode.el (define-globalized-minor-mode):
Improve the generated docstring.
* doc/emacs/vc1-xtra.texi (VC Auto-Reverting):
* etc/NEWS: Document the new minor mode.

(cherry picked from commit 9d750c7e8041437758c919f6088d6f3686847812)

doc/emacs/vc1-xtra.texi
lisp/emacs-lisp/easy-mmode.el
lisp/vc/vc-dispatcher.el
lisp/vc/vc-hooks.el
lisp/vc/vc.el

index 51fefe231daed1e5e725ea1a8355f825e9a93432..fa7b3a6b3bafb15ae73c1373da9037c0104278ab 100644 (file)
@@ -16,7 +16,8 @@
 * Revision Tags::       Symbolic names for revisions.
 * Version Headers::     Inserting version control headers into working files.
 * Editing VC Commands:: Editing the VC shell commands that Emacs will run.
-* Preparing Patches::   Preparing and Composing patches from within VC
+* Preparing Patches::   Preparing and composing patches from within VC.
+* VC Auto-Reverting::   Updating buffer contents after VCS operations.
 @end menu
 
 @node Change Logs and VC
@@ -314,6 +315,33 @@ you wish to use.  This will be used as the default value when invoking
 @code{vc-prepare-patch}.  Project maintainers may consider setting
 this as a directory local variable (@pxref{Directory Variables}).
 
+@node VC Auto-Reverting
+@subsubsection Auto-Reverting Buffers Visiting Tracked Files
+
+  When Emacs executes VCS operations that it knows may change the
+contents of tracked files, it reverts buffers visiting those files
+(@pxref{Reverting}).  It does this in a VCS-aware fashion that retains
+the positions of point and the mark even when the VCS operation causes
+VCS keywords to be expanded (for example, CVS keywords: @pxref{Keyword
+substitution,,,cvs,CVS--Concurrent Versions System}).
+
+@findex vc-auto-revert-mode
+  An important limitation of this feature is that Emacs won't know to
+revert buffers when you execute additional VCS operations outside of
+Emacs, such as at a shell prompt, or by means of scripts.  If you
+regularly do this, and you don't use a VCS with keyword expansion (all
+modern VCS, absent special configuration), you may wish to enable
+@code{vc-auto-revert-mode} instead, by customizing that variable to
+non-@code{nil}.
+
+  This mode is just like @code{global-auto-revert-mode} (@pxref{Auto
+Revert}) except limited to files visiting VCS-tracked files.  It ensures
+that Emacs will always revert buffers when VCS operations change their
+contents, regardless of whether Emacs initiated those operations.
+
+  @xref{VC Mode Line} regarding Auto Revert mode in buffers visiting
+tracked files (which is what @code{vc-auto-revert-mode} enables).
+
 @node Customizing VC
 @subsection Customizing VC
 
index 8e219da79468c54d12d0e56cadc865541b6d2d19..915dcfa23924c8a8c1e7b18a2160144a6bc9693f 100644 (file)
@@ -540,7 +540,11 @@ on if the hook has explicitly disabled it.
          ,@(when predicate `((defvar ,MODE-predicate))))
        ;; The actual global minor-mode
        (define-minor-mode ,global-mode
-         ,(concat (format "Toggle %s in all buffers.\n" pretty-name)
+         ,(concat (format "Toggle %s in many buffers.\n" pretty-name)
+                  (internal--format-docstring-line
+                   "Specifically, %s is enabled in all buffers where `%s' would do it."
+                   pretty-name turn-on)
+                  "\n\n"
                   (internal--format-docstring-line
                    (concat "With prefix ARG, enable %s if ARG is positive; "
                            "otherwise, disable it.")
@@ -549,10 +553,6 @@ on if the hook has explicitly disabled it.
                   "If called from Lisp, toggle the mode if ARG is `toggle'.
 Enable the mode if ARG is nil, omitted, or is a positive number.
 Disable the mode if ARG is a negative number.\n\n"
-                  (internal--format-docstring-line
-                   "%s is enabled in all buffers where `%s' would do it."
-                   pretty-name turn-on)
-                  "\n\n"
                   (internal--format-docstring-line
                    "See `%s' for more information on %s."
                    mode pretty-name)
index a3b8a5af8ad8244b4433d559f430414ff9329861..d16e2fbb8d97e630ea0622d9beef0e853dc2649c 100644 (file)
@@ -656,9 +656,10 @@ CONTEXT is that which `vc-buffer-context' returns."
            (when new-mark (set-mark new-mark))))))
 
 (defun vc-revert-buffer-internal (&optional arg no-confirm)
-  "Revert buffer, keeping point and mark where user expects them.
-Try to be clever in the face of changes due to expanded version-control
-key words.  This is important for typeahead to work as expected.
+  "Revert buffer keeping point and the mark where the user expects them.
+Try to be clever in the face of changes due to expanded VCS
+keywords (cf., e.g., info node `(cvs)Keyword substitution').
+This is important for typeahead to work as expected.
 ARG and NO-CONFIRM are passed on to `revert-buffer'."
   (interactive "P")
   (widen)
@@ -678,6 +679,9 @@ ARG and NO-CONFIRM are passed on to `revert-buffer'."
 
 (defvar view-old-buffer-read-only)
 
+(defvar auto-revert-mode)
+(declare-function auto-revert-buffers "autorevert")
+
 (defun vc-resynch-window (file &optional keep noquery reset-vc-info)
   "If FILE is in the current buffer, either revert or unvisit it.
 The choice between revert (to see expanded keywords) and unvisit
@@ -686,31 +690,37 @@ reverting.  NOQUERY should be t *only* if it is known the only
 difference between the buffer and the file is due to
 modifications by the dispatcher client code, rather than user
 editing!"
-  (and (string= buffer-file-name
-                (if (file-name-absolute-p file)
-                    file
-                  (expand-file-name file (vc-root-dir))))
-       (if keep
-          (when (file-exists-p file)
-            (when reset-vc-info
-              (vc-file-clearprops file))
-            (vc-revert-buffer-internal t noquery)
-
-            ;; VC operations might toggle the read-only state.  In
-            ;; that case we need to adjust the `view-mode' status
-            ;; when `view-read-only' is non-nil.
-             (and view-read-only
-                  (if (file-writable-p file)
-                      (and view-mode
-                           (let ((view-old-buffer-read-only nil))
-                             (view-mode-exit t)))
-                    (and (not view-mode)
-                         (not (eq (get major-mode 'mode-class) 'special))
-                         (view-mode-enter))))
-
-             ;; FIXME: Why use a hook?  Why pass it buffer-file-name?
-            (run-hook-with-args 'vc-mode-line-hook buffer-file-name))
-        (kill-buffer (current-buffer)))))
+  (and (equal buffer-file-name
+              (if (file-name-absolute-p file)
+                  file
+                (expand-file-name file (vc-root-dir))))
+       (cond ((not keep)
+              (kill-buffer))
+             ((file-exists-p file)
+              (when reset-vc-info
+               (vc-file-clearprops file))
+              ;; If `auto-revert-mode' is on (probably due to either
+              ;; `global-auto-revert-mode' or `vc-auto-revert-mode')
+              ;; then defer to that.  Otherwise we do our own
+              ;; VC-specific reverting.
+              (if (and auto-revert-mode noquery)
+                  (auto-revert-buffers)
+               (vc-revert-buffer-internal t noquery))
+
+             ;; VC operations might toggle the read-only state.  In
+             ;; that case we need to adjust the `view-mode' status
+             ;; when `view-read-only' is non-nil.
+              (and view-read-only
+                   (if (file-writable-p file)
+                       (and view-mode
+                            (let ((view-old-buffer-read-only nil))
+                              (view-mode-exit t)))
+                     (and (not view-mode)
+                          (not (eq (get major-mode 'mode-class) 'special))
+                          (view-mode-enter))))
+
+              ;; FIXME: Why use a hook?  Why pass it buffer-file-name?
+             (run-hook-with-args 'vc-mode-line-hook buffer-file-name)))))
 
 (declare-function vc-dir-resynch-file "vc-dir" (&optional fname))
 
index 8a159d39c411e3a32defaec77652e435bb36a71a..3945e5c10cd935f8fa5e68cc582f68eeddf68052 100644 (file)
@@ -206,6 +206,20 @@ VC commands are globally reachable under the prefix \\[vc-prefix-map]:
 \\{vc-prefix-map}"
   nil)
 
+(defvar auto-revert-mode)
+(define-globalized-minor-mode vc-auto-revert-mode auto-revert-mode
+  vc-turn-on-auto-revert-mode-for-tracked-files
+  :group 'vc
+  :version "31.1")
+
+(defun vc-turn-on-auto-revert-mode-for-tracked-files ()
+  "Turn on Auto Revert mode in buffers visiting VCS-tracked files."
+  ;; This should turn on Auto Revert mode whenever `vc-mode' is non-nil.
+  ;; We can't just check that variable directly because `vc-mode-line'
+  ;; may not have been called yet.
+  (when (vc-backend buffer-file-name)
+    (auto-revert-mode 1)))
+
 (defmacro vc-error-occurred (&rest body)
   `(condition-case nil (progn ,@body nil) (error t)))
 
index 9645b82f317a736d6607b5bcd09334d2adefe093..e591f527be213475a19b9cd9df9a5c08768f1b1f 100644 (file)
@@ -1666,13 +1666,14 @@ from which to check out the file(s)."
          (find-file-other-window file))
        (if (save-window-excursion
              (vc-diff-internal nil
-                               (cons (car vc-fileset) (cons (cadr vc-fileset) (list file)))
+                               (cons (car vc-fileset)
+                                      (cons (cadr vc-fileset) (list file)))
                                (vc-working-revision file) nil)
              (goto-char (point-min))
              (let ((inhibit-read-only t))
                (insert
                 (format "Changes to %s since last lock:\n\n" file)))
-             (not (beep))
+             (beep)
              (yes-or-no-p (concat "File has unlocked changes.  "
                                   "Claim lock retaining changes? ")))
            (progn (vc-call-backend backend 'steal-lock file)
@@ -1733,7 +1734,9 @@ first backend that could register the file is used."
       (when-let* ((bname (get-file-buffer fname)))
         (with-current-buffer bname
           (unless vc-make-backup-files
-            (setq-local backup-inhibited t))))
+            (setq-local backup-inhibited t))
+          (when vc-auto-revert-mode
+            (auto-revert-mode 1))))
       (vc-resynch-buffer fname t t))
     (message "Registering %s... done" files)))