* 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)
* 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
@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
,@(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.")
"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)
(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)
(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
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))
\\{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)))
(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)
(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)))