New global minor mode vc-auto-revert-mode

* 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.
This commit is contained in:
Sean Whitton 2025-07-13 12:50:22 +01:00
parent 24bd93b35b
commit 9d750c7e80
6 changed files with 98 additions and 35 deletions

View 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
@ -321,6 +322,33 @@ emacs, the Emacs Manual}).
(@pxref{Directory Variables}).
@end ifnottex
@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

View file

@ -1846,6 +1846,14 @@ the directory into which the repository was cloned.
*** 'C-x v u' ('vc-revert') now works on directories listed in VC Directory.
Reverting a directory means reverting changes to all files inside it.
+++
*** New minor mode 'vc-auto-revert-mode'.
This is like 'global-auto-revert-mode' but limited to VCS-tracked files.
As compared with VC's existing, default support for reverting files
after VCS operations, the new mode is a more reliable way to ensure that
Emacs reverts buffers visiting tracked files when VCS operations change
the contents of those files.
*** New command 'log-edit-done-strip-cvs-lines'.
This command strips all lines beginning with "CVS:" from the buffer.
It is intended to be added to the 'log-edit-done-hook' so that

View file

@ -529,7 +529,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.")
@ -538,10 +542,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)

View 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)
(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))))
;; 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)))))
;; 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))

View 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)))

View file

@ -1671,13 +1671,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)
@ -1738,7 +1739,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)))