Commit | Line | Data |
---|---|---|
e8af40ee | 1 | ;;; autorevert.el --- revert buffers when files on disk change |
4a35aff3 | 2 | |
bf2150fa | 3 | ;; Copyright (C) 1997, 1998, 1999, 2001 Free Software Foundation, Inc. |
4a35aff3 | 4 | |
a468671a | 5 | ;; Author: Anders Lindgren <andersl@andersl.com> |
f5f727f8 | 6 | ;; Keywords: convenience |
a468671a GM |
7 | ;; Created: 1997-06-01 |
8 | ;; Date: 1999-11-30 | |
4a35aff3 RS |
9 | |
10 | ;; This file is part of GNU Emacs. | |
11 | ||
12 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
13 | ;; it under the terms of the GNU General Public License as published by | |
14 | ;; the Free Software Foundation; either version 2, or (at your option) | |
15 | ;; any later version. | |
16 | ||
17 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ;; GNU General Public License for more details. | |
21 | ||
22 | ;; You should have received a copy of the GNU General Public License | |
23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
24 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
25 | ;; Boston, MA 02111-1307, USA. | |
26 | ||
27 | ;;; Commentary: | |
28 | ||
29 | ;; Introduction: | |
30 | ;; | |
31 | ;; Whenever a file that Emacs is editing has been changed by another | |
48764ae2 | 32 | ;; program the user normally has to execute the command `revert-buffer' |
4a35aff3 RS |
33 | ;; to load the new content of the file into Emacs. |
34 | ;; | |
35 | ;; This package contains two minor modes: Global Auto-Revert Mode and | |
48764ae2 | 36 | ;; Auto-Revert Mode. Both modes automatically revert buffers |
4a35aff3 RS |
37 | ;; whenever the corresponding files have been changed on disk. |
38 | ;; | |
ae229809 LT |
39 | ;; Auto-Revert Mode can be activated for individual buffers. Global |
40 | ;; Auto-Revert Mode applies to all file buffers. (If the user option | |
41 | ;; `global-auto-revert-non-file-buffers' is non-nil, it also applies | |
42 | ;; to some non-file buffers. This option is disabled by default.) | |
43 | ;; Since checking a remote file is too slow, these modes do not check | |
44 | ;; or revert remote files. | |
4a35aff3 | 45 | ;; |
48764ae2 DL |
46 | ;; Both modes operate by checking the time stamp of all files at |
47 | ;; intervals of `auto-revert-interval'. The default is every five | |
48 | ;; seconds. The check is aborted whenever the user actually uses | |
49 | ;; Emacs. You should never even notice that this package is active | |
50 | ;; (except that your buffers will be reverted, of course). | |
1f41bcba LT |
51 | ;; |
52 | ;; After reverting a file buffer, Auto Revert Mode normally puts point | |
53 | ;; at the same position that a regular manual revert would. However, | |
54 | ;; there is one exception to this rule. If point is at the end of the | |
55 | ;; buffer before reverting, it stays at the end. Similarly if point | |
56 | ;; is displayed at the end of a file buffer in any window, it will stay | |
57 | ;; at the end of the buffer in that window, even if the window is not | |
58 | ;; selected. This way, you can use Auto Revert Mode to `tail' a file. | |
59 | ;; Just put point at the end of the buffer and it will stay there. | |
60 | ;; These rules apply to file buffers. For non-file buffers, the | |
61 | ;; behavior may be mode dependent. | |
4a35aff3 RS |
62 | |
63 | ;; Usage: | |
64 | ;; | |
65 | ;; Go to the appropriate buffer and press: | |
66 | ;; M-x auto-revert-mode RET | |
67 | ;; | |
68 | ;; To activate Global Auto-Revert Mode, press: | |
69 | ;; M-x global-auto-revert-mode RET | |
70 | ;; | |
48764ae2 DL |
71 | ;; To activate Global Auto-Revert Mode every time Emacs is started |
72 | ;; customise the option `global-auto-revert-mode' or the following | |
73 | ;; line could be added to your ~/.emacs: | |
4a35aff3 RS |
74 | ;; (global-auto-revert-mode 1) |
75 | ;; | |
76 | ;; The function `turn-on-auto-revert-mode' could be added to any major | |
77 | ;; mode hook to activate Auto-Revert Mode for all buffers in that | |
78 | ;; mode. For example, the following line will activate Auto-Revert | |
79 | ;; Mode in all C mode buffers: | |
80 | ;; | |
81 | ;; (add-hook 'c-mode-hook 'turn-on-auto-revert-mode) | |
82 | ||
83 | ;;; Code: | |
84 | ||
85 | ;; Dependencies: | |
86 | ||
87 | (require 'timer) | |
0f98bc23 | 88 | |
71c8db4c | 89 | (eval-when-compile (require 'cl)) |
4a35aff3 RS |
90 | |
91 | ||
92 | ;; Custom Group: | |
93 | ;; | |
94 | ;; The two modes will be placed next to Auto Save Mode under the | |
95 | ;; Files group under Emacs. | |
96 | ||
97 | (defgroup auto-revert nil | |
48764ae2 | 98 | "Revert individual buffers when files on disk change. |
4a35aff3 RS |
99 | |
100 | Auto-Revert Mode can be activated for individual buffer. | |
101 | Global Auto-Revert Mode applies to all buffers." | |
f5f727f8 DN |
102 | :group 'files |
103 | :group 'convenience) | |
4a35aff3 RS |
104 | |
105 | ||
106 | ;; Variables: | |
107 | ||
00d0fda8 DL |
108 | ;; Autoload for the benefit of `make-mode-line-mouse-sensitive'. |
109 | ;;;###autoload | |
4a35aff3 RS |
110 | (defvar auto-revert-mode nil |
111 | "*Non-nil when Auto-Revert Mode is active. | |
0e4f9468 SM |
112 | Never set this variable directly, use the command `auto-revert-mode' instead.") |
113 | (put 'auto-revert-mode 'permanent-local t) | |
4a35aff3 | 114 | |
a2ac68f1 LT |
115 | (defvar auto-revert-timer nil |
116 | "Timer used by Auto-Revert Mode.") | |
117 | ||
4a35aff3 | 118 | (defcustom auto-revert-interval 5 |
ad660075 | 119 | "Time, in seconds, between Auto-Revert Mode file checks. |
a2ac68f1 LT |
120 | The value may be an integer or floating point number. |
121 | ||
122 | If a timer is already active, there are two ways to make sure | |
123 | that the new value will take effect immediately. You can set | |
124 | this variable through Custom or you can call the command | |
125 | `auto-revert-set-timer' after setting the variable. Otherwise, | |
126 | the new value will take effect the first time Auto Revert Mode | |
127 | calls `auto-revert-set-timer' for internal reasons or in your | |
128 | next editing session." | |
4a35aff3 | 129 | :group 'auto-revert |
a2ac68f1 LT |
130 | :type 'number |
131 | :set (lambda (variable value) | |
132 | (set-default variable value) | |
133 | (and (boundp 'auto-revert-timer) | |
134 | auto-revert-timer | |
135 | (auto-revert-set-timer)))) | |
4a35aff3 RS |
136 | |
137 | (defcustom auto-revert-stop-on-user-input t | |
138 | "When non-nil Auto-Revert Mode stops checking files on user input." | |
139 | :group 'auto-revert | |
140 | :type 'boolean) | |
141 | ||
142 | (defcustom auto-revert-verbose t | |
143 | "When nil, Auto-Revert Mode will not generate any messages. | |
0e5dcfd7 | 144 | When non-nil, a message is generated whenever a file is reverted." |
4a35aff3 RS |
145 | :group 'auto-revert |
146 | :type 'boolean) | |
147 | ||
148 | (defcustom auto-revert-mode-text " ARev" | |
149 | "String to display in the mode line when Auto-Revert Mode is active. | |
150 | ||
151 | \(When the string is not empty, make sure that it has a leading space.)" | |
152 | :tag "Auto Revert Mode Text" ; To separate it from `global-...' | |
153 | :group 'auto-revert | |
154 | :type 'string) | |
155 | ||
156 | (defcustom auto-revert-mode-hook nil | |
157 | "Functions to run when Auto-Revert Mode is activated." | |
158 | :tag "Auto Revert Mode Hook" ; To separate it from `global-...' | |
159 | :group 'auto-revert | |
160 | :type 'hook) | |
161 | ||
162 | (defcustom global-auto-revert-mode-text "" | |
163 | "String to display when Global Auto-Revert Mode is active. | |
164 | ||
165 | The default is nothing since when this mode is active this text doesn't | |
48764ae2 | 166 | vary over time, or between buffers. Hence mode line text |
4a35aff3 RS |
167 | would only waste precious space." |
168 | :group 'auto-revert | |
169 | :type 'string) | |
170 | ||
171 | (defcustom global-auto-revert-mode-hook nil | |
172 | "Hook called when Global Auto-Revert Mode is activated." | |
173 | :group 'auto-revert | |
174 | :type 'hook) | |
175 | ||
176 | (defcustom global-auto-revert-non-file-buffers nil | |
0e4f9468 | 177 | "When nil only file buffers are reverted by Global Auto-Revert Mode. |
4a35aff3 RS |
178 | |
179 | When non-nil, both file buffers and buffers with a custom | |
0e5dcfd7 LT |
180 | `revert-buffer-function' and a `buffer-stale-function' are |
181 | reverted by Global Auto-Revert Mode. | |
0e4f9468 | 182 | |
d4411cef LT |
183 | Use this option with care since it could lead to excessive reverts. |
184 | Note also that for some non-file buffers the check whether the | |
185 | buffer needs updating may be imperfect, due to efficiency | |
186 | considerations, and may not take all information listed in the | |
187 | buffer into account. Hence, a non-nil value for this option does | |
843c51ae LT |
188 | not necessarily make manual updates useless for non-file buffers. |
189 | ||
190 | To find out to which buffers this option currently applies, as | |
191 | well as for further details, see Info node `(emacs-xtra)Autorevert'." | |
4a35aff3 | 192 | :group 'auto-revert |
843c51ae LT |
193 | :type 'boolean |
194 | :link '(info-link "(emacs-xtra)Autorevert")) | |
4a35aff3 | 195 | |
4a35aff3 RS |
196 | (defcustom global-auto-revert-ignore-modes '() |
197 | "List of major modes Global Auto-Revert Mode should not check." | |
198 | :group 'auto-revert | |
199 | :type '(repeat sexp)) | |
200 | ||
201 | (defcustom auto-revert-load-hook nil | |
202 | "Functions to run when Auto-Revert Mode is first loaded." | |
203 | :tag "Load Hook" | |
204 | :group 'auto-revert | |
205 | :type 'hook) | |
206 | ||
71c8db4c LT |
207 | (defcustom auto-revert-check-vc-info nil |
208 | "If non-nil Auto Revert Mode reliably updates version control info. | |
209 | Auto Revert Mode updates version control info whenever the buffer | |
210 | needs reverting, regardless of the value of this variable. | |
211 | However, the version control state can change without changes to | |
212 | the work file. If the change is made from the current Emacs | |
213 | session, all info is updated. But if, for instance, a new | |
214 | version is checked in from outside the current Emacs session, the | |
215 | version control number in the mode line, as well as other version | |
216 | control related information, may not be properly updated. If you | |
217 | are worried about this, set this variable to a non-nil value. | |
218 | ||
219 | This currently works by automatically updating the version | |
220 | control info every `auto-revert-interval' seconds. Nevertheless, | |
221 | it should not cause excessive CPU usage on a reasonably fast | |
222 | machine, if it does not apply to too many version controlled | |
223 | buffers. CPU usage depends on the version control system" | |
224 | :group 'auto-revert | |
225 | :type 'boolean | |
226 | :version "21.4") | |
227 | ||
4a35aff3 | 228 | (defvar global-auto-revert-ignore-buffer nil |
f1e3ff80 | 229 | "*When non-nil, Global Auto-Revert Mode will not revert this buffer. |
4a35aff3 | 230 | |
48764ae2 | 231 | This variable becomes buffer local when set in any fashion.") |
4a35aff3 RS |
232 | (make-variable-buffer-local 'global-auto-revert-ignore-buffer) |
233 | ||
4a35aff3 RS |
234 | ;; Internal variables: |
235 | ||
236 | (defvar auto-revert-buffer-list '() | |
237 | "List of buffers in Auto-Revert Mode. | |
238 | ||
239 | Note that only Auto-Revert Mode, never Global Auto-Revert Mode, adds | |
240 | buffers to this list. | |
241 | ||
242 | The timer function `auto-revert-buffers' is responsible for purging | |
243 | the list of old buffers.") | |
244 | ||
4a35aff3 RS |
245 | (defvar auto-revert-remaining-buffers '() |
246 | "Buffers not checked when user input stopped execution.") | |
247 | ||
248 | ||
249 | ;; Functions: | |
250 | ||
251 | ;;;###autoload | |
0e4f9468 | 252 | (define-minor-mode auto-revert-mode |
48764ae2 | 253 | "Toggle reverting buffer when file on disk changes. |
4a35aff3 | 254 | |
48764ae2 DL |
255 | With arg, turn Auto Revert mode on if and only if arg is positive. |
256 | This is a minor mode that affects only the current buffer. | |
4a35aff3 | 257 | Use `global-auto-revert-mode' to automatically revert all buffers." |
0e4f9468 | 258 | nil auto-revert-mode-text nil |
4a35aff3 RS |
259 | (if auto-revert-mode |
260 | (if (not (memq (current-buffer) auto-revert-buffer-list)) | |
261 | (push (current-buffer) auto-revert-buffer-list)) | |
262 | (setq auto-revert-buffer-list | |
263 | (delq (current-buffer) auto-revert-buffer-list))) | |
264 | (auto-revert-set-timer) | |
265 | (when auto-revert-mode | |
0e4f9468 | 266 | (auto-revert-buffers))) |
4a35aff3 RS |
267 | |
268 | ||
269 | ;;;###autoload | |
270 | (defun turn-on-auto-revert-mode () | |
271 | "Turn on Auto-Revert Mode. | |
272 | ||
273 | This function is designed to be added to hooks, for example: | |
274 | (add-hook 'c-mode-hook 'turn-on-auto-revert-mode)" | |
275 | (auto-revert-mode 1)) | |
276 | ||
277 | ||
278 | ;;;###autoload | |
0e4f9468 | 279 | (define-minor-mode global-auto-revert-mode |
0e5dcfd7 | 280 | "Revert any buffer when file on disk changes. |
4a35aff3 | 281 | |
48764ae2 DL |
282 | With arg, turn Auto Revert mode on globally if and only if arg is positive. |
283 | This is a minor mode that affects all buffers. | |
4a35aff3 | 284 | Use `auto-revert-mode' to revert a particular buffer." |
0e4f9468 | 285 | :global t :group 'auto-revert :lighter global-auto-revert-mode-text |
4a35aff3 RS |
286 | (auto-revert-set-timer) |
287 | (when global-auto-revert-mode | |
0e4f9468 | 288 | (auto-revert-buffers))) |
4a35aff3 RS |
289 | |
290 | ||
291 | (defun auto-revert-set-timer () | |
0e5dcfd7 | 292 | "Restart or cancel the timer used by Auto-Revert Mode. |
d97c8375 | 293 | If such a timer is active, cancel it. Start a new timer if |
0e5dcfd7 LT |
294 | Global Auto-Revert Mode is active or if Auto-Revert Mode is active |
295 | in some buffer. Restarting the timer ensures that Auto-Revert Mode | |
296 | will use an up-to-date value of `auto-revert-interval'" | |
a2ac68f1 | 297 | (interactive) |
4a35aff3 RS |
298 | (if (timerp auto-revert-timer) |
299 | (cancel-timer auto-revert-timer)) | |
0e4f9468 SM |
300 | (setq auto-revert-timer |
301 | (if (or global-auto-revert-mode auto-revert-buffer-list) | |
302 | (run-with-timer auto-revert-interval | |
303 | auto-revert-interval | |
304 | 'auto-revert-buffers) | |
305 | nil))) | |
4a35aff3 | 306 | |
ed35db71 EZ |
307 | (defun auto-revert-active-p () |
308 | "Check if auto-revert is active (in current buffer or globally)." | |
309 | (or auto-revert-mode | |
310 | (and | |
311 | global-auto-revert-mode | |
312 | (not global-auto-revert-ignore-buffer) | |
313 | (not (memq major-mode | |
314 | global-auto-revert-ignore-modes))))) | |
315 | ||
ed35db71 | 316 | (defun auto-revert-handler () |
0e5dcfd7 LT |
317 | "Revert current buffer, if appropriate. |
318 | This is an internal function used by Auto-Revert Mode." | |
d4411cef | 319 | (unless (buffer-modified-p) |
1f41bcba LT |
320 | (let ((buffer (current-buffer)) revert eob eoblist) |
321 | (or (and buffer-file-name | |
e7893b53 | 322 | (not (file-remote-p buffer-file-name)) |
1f41bcba LT |
323 | (file-readable-p buffer-file-name) |
324 | (not (verify-visited-file-modtime buffer)) | |
71c8db4c LT |
325 | (setq revert t)) |
326 | (and (or auto-revert-mode global-auto-revert-non-file-buffers) | |
327 | revert-buffer-function | |
328 | (boundp 'buffer-stale-function) | |
329 | (functionp buffer-stale-function) | |
330 | (setq revert (funcall buffer-stale-function t)))) | |
d4411cef | 331 | (when revert |
71c8db4c LT |
332 | (when (and auto-revert-verbose |
333 | (not (eq revert 'fast))) | |
633e0363 | 334 | (message "Reverting buffer `%s'." (buffer-name))) |
1f41bcba LT |
335 | ;; If point (or a window point) is at the end of the buffer, |
336 | ;; we want to keep it at the end after reverting. This allows | |
337 | ;; to tail a file. | |
338 | (when buffer-file-name | |
339 | (setq eob (eobp)) | |
340 | (walk-windows | |
341 | #'(lambda (window) | |
342 | (and (eq (window-buffer window) buffer) | |
343 | (= (window-point window) (point-max)) | |
344 | (push window eoblist))) | |
345 | 'no-mini t)) | |
346 | (revert-buffer 'ignore-auto 'dont-ask 'preserve-modes) | |
347 | (when buffer-file-name | |
348 | (when eob (goto-char (point-max))) | |
349 | (dolist (window eoblist) | |
350 | (set-window-point window (point-max))))) | |
71c8db4c LT |
351 | ;; `preserve-modes' avoids changing the (minor) modes. But we |
352 | ;; do want to reset the mode for VC, so we do it manually. | |
353 | (when (or revert auto-revert-check-vc-info) | |
354 | (vc-find-file-hook))))) | |
ed35db71 | 355 | |
4a35aff3 RS |
356 | (defun auto-revert-buffers () |
357 | "Revert buffers as specified by Auto-Revert and Global Auto-Revert Mode. | |
358 | ||
359 | Should `global-auto-revert-mode' be active all file buffers are checked. | |
360 | ||
361 | Should `auto-revert-mode' be active in some buffers, those buffers | |
362 | are checked. | |
363 | ||
0e5dcfd7 LT |
364 | Non-file buffers that have a custom `revert-buffer-function' and |
365 | a `buffer-stale-function' are reverted either when Auto-Revert | |
366 | Mode is active in that buffer, or when the variable | |
367 | `global-auto-revert-non-file-buffers' is non-nil and Global | |
368 | Auto-Revert Mode is active. | |
4a35aff3 | 369 | |
48764ae2 | 370 | This function stops whenever there is user input. The buffers not |
4a35aff3 RS |
371 | checked are stored in the variable `auto-revert-remaining-buffers'. |
372 | ||
373 | To avoid starvation, the buffers in `auto-revert-remaining-buffers' | |
374 | are checked first the next time this function is called. | |
375 | ||
48764ae2 | 376 | This function is also responsible for removing buffers no longer in |
4a35aff3 RS |
377 | Auto-Revert mode from `auto-revert-buffer-list', and for canceling |
378 | the timer when no buffers need to be checked." | |
379 | (let ((bufs (if global-auto-revert-mode | |
380 | (buffer-list) | |
381 | auto-revert-buffer-list)) | |
382 | (remaining '()) | |
383 | (new '())) | |
384 | ;; Partition `bufs' into two halves depending on whether or not | |
385 | ;; the buffers are in `auto-revert-remaining-buffers'. The two | |
386 | ;; halves are then re-joined with the "remaining" buffers at the | |
387 | ;; head of the list. | |
388 | (dolist (buf auto-revert-remaining-buffers) | |
389 | (if (memq buf bufs) | |
390 | (push buf remaining))) | |
391 | (dolist (buf bufs) | |
392 | (if (not (memq buf remaining)) | |
393 | (push buf new))) | |
394 | (setq bufs (nreverse (nconc new remaining))) | |
395 | (while (and bufs | |
396 | (not (and auto-revert-stop-on-user-input | |
397 | (input-pending-p)))) | |
398 | (let ((buf (car bufs))) | |
399 | (if (buffer-name buf) ; Buffer still alive? | |
0e4f9468 | 400 | (with-current-buffer buf |
4a35aff3 RS |
401 | ;; Test if someone has turned off Auto-Revert Mode in a |
402 | ;; non-standard way, for example by changing major mode. | |
403 | (if (and (not auto-revert-mode) | |
404 | (memq buf auto-revert-buffer-list)) | |
405 | (setq auto-revert-buffer-list | |
406 | (delq buf auto-revert-buffer-list))) | |
c86afc19 | 407 | (when (auto-revert-active-p) (auto-revert-handler))) |
4a35aff3 RS |
408 | ;; Remove dead buffer from `auto-revert-buffer-list'. |
409 | (setq auto-revert-buffer-list | |
410 | (delq buf auto-revert-buffer-list)))) | |
411 | (setq bufs (cdr bufs))) | |
412 | (setq auto-revert-remaining-buffers bufs) | |
413 | ;; Check if we should cancel the timer. | |
414 | (when (and (not global-auto-revert-mode) | |
415 | (null auto-revert-buffer-list)) | |
416 | (cancel-timer auto-revert-timer) | |
417 | (setq auto-revert-timer nil)))) | |
418 | ||
419 | ||
420 | ;; The end: | |
4a35aff3 RS |
421 | (provide 'autorevert) |
422 | ||
423 | (run-hooks 'auto-revert-load-hook) | |
424 | ||
ab5796a9 | 425 | ;;; arch-tag: f6bcb07b-4841-477e-9e44-b18678e58876 |
e8af40ee | 426 | ;;; autorevert.el ends here |