Commit | Line | Data |
---|---|---|
5abdc915 | 1 | ;;; autorevert --- revert buffers when files on disk change |
4a35aff3 | 2 | |
48764ae2 | 3 | ;; Copyright (C) 1997, 1998 Free Software Foundation, Inc. |
4a35aff3 RS |
4 | |
5 | ;; Author: Anders Lindgren <andersl@csd.uu.se> | |
f5f727f8 | 6 | ;; Keywords: convenience |
4a35aff3 RS |
7 | ;; Created: 1 Jun 1997 |
8 | ;; Date: 3 Jul 1997 | |
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 | ;; | |
39 | ;; Auto-Revert Mode can be activated for individual buffers. | |
40 | ;; Global Auto-Revert Mode applies to all file buffers. | |
41 | ;; | |
48764ae2 DL |
42 | ;; Both modes operate by checking the time stamp of all files at |
43 | ;; intervals of `auto-revert-interval'. The default is every five | |
44 | ;; seconds. The check is aborted whenever the user actually uses | |
45 | ;; Emacs. You should never even notice that this package is active | |
46 | ;; (except that your buffers will be reverted, of course). | |
4a35aff3 RS |
47 | |
48 | ;; Usage: | |
49 | ;; | |
50 | ;; Go to the appropriate buffer and press: | |
51 | ;; M-x auto-revert-mode RET | |
52 | ;; | |
53 | ;; To activate Global Auto-Revert Mode, press: | |
54 | ;; M-x global-auto-revert-mode RET | |
55 | ;; | |
48764ae2 DL |
56 | ;; To activate Global Auto-Revert Mode every time Emacs is started |
57 | ;; customise the option `global-auto-revert-mode' or the following | |
58 | ;; line could be added to your ~/.emacs: | |
4a35aff3 RS |
59 | ;; (global-auto-revert-mode 1) |
60 | ;; | |
61 | ;; The function `turn-on-auto-revert-mode' could be added to any major | |
62 | ;; mode hook to activate Auto-Revert Mode for all buffers in that | |
63 | ;; mode. For example, the following line will activate Auto-Revert | |
64 | ;; Mode in all C mode buffers: | |
65 | ;; | |
66 | ;; (add-hook 'c-mode-hook 'turn-on-auto-revert-mode) | |
67 | ||
68 | ;;; Code: | |
69 | ||
70 | ;; Dependencies: | |
71 | ||
72 | (require 'timer) | |
73 | (eval-when-compile (require 'cl)) | |
74 | ||
75 | ||
76 | ;; Custom Group: | |
77 | ;; | |
78 | ;; The two modes will be placed next to Auto Save Mode under the | |
79 | ;; Files group under Emacs. | |
80 | ||
81 | (defgroup auto-revert nil | |
48764ae2 | 82 | "Revert individual buffers when files on disk change. |
4a35aff3 RS |
83 | |
84 | Auto-Revert Mode can be activated for individual buffer. | |
85 | Global Auto-Revert Mode applies to all buffers." | |
f5f727f8 DN |
86 | :group 'files |
87 | :group 'convenience) | |
4a35aff3 RS |
88 | |
89 | ||
90 | ;; Variables: | |
91 | ||
00d0fda8 DL |
92 | ;; Autoload for the benefit of `make-mode-line-mouse-sensitive'. |
93 | ;;;###autoload | |
4a35aff3 RS |
94 | (defvar auto-revert-mode nil |
95 | "*Non-nil when Auto-Revert Mode is active. | |
96 | ||
48764ae2 DL |
97 | Never set this variable directly, use the command `auto-revert-mode' |
98 | instead.") | |
4a35aff3 RS |
99 | |
100 | (defcustom global-auto-revert-mode nil | |
101 | "When on, buffers are automatically reverted when files on disk change. | |
102 | ||
48764ae2 DL |
103 | Set this variable using \\[customize] only. Otherwise, use the |
104 | command `global-auto-revert-mode'." | |
4a35aff3 RS |
105 | :group 'auto-revert |
106 | :initialize 'custom-initialize-default | |
107 | :set '(lambda (symbol value) | |
108 | (global-auto-revert-mode (or value 0))) | |
109 | :type 'boolean | |
110 | :require 'autorevert) | |
111 | ||
112 | (defcustom auto-revert-interval 5 | |
113 | "Time, in seconds, between Auto-Revert Mode file checks." | |
114 | :group 'auto-revert | |
115 | :type 'integer) | |
116 | ||
117 | (defcustom auto-revert-stop-on-user-input t | |
118 | "When non-nil Auto-Revert Mode stops checking files on user input." | |
119 | :group 'auto-revert | |
120 | :type 'boolean) | |
121 | ||
122 | (defcustom auto-revert-verbose t | |
123 | "When nil, Auto-Revert Mode will not generate any messages. | |
124 | ||
125 | Currently, messages are generated when the mode is activated or | |
126 | deactivated, and whenever a file is reverted." | |
127 | :group 'auto-revert | |
128 | :type 'boolean) | |
129 | ||
130 | (defcustom auto-revert-mode-text " ARev" | |
131 | "String to display in the mode line when Auto-Revert Mode is active. | |
132 | ||
133 | \(When the string is not empty, make sure that it has a leading space.)" | |
134 | :tag "Auto Revert Mode Text" ; To separate it from `global-...' | |
135 | :group 'auto-revert | |
136 | :type 'string) | |
137 | ||
138 | (defcustom auto-revert-mode-hook nil | |
139 | "Functions to run when Auto-Revert Mode is activated." | |
140 | :tag "Auto Revert Mode Hook" ; To separate it from `global-...' | |
141 | :group 'auto-revert | |
142 | :type 'hook) | |
143 | ||
144 | (defcustom global-auto-revert-mode-text "" | |
145 | "String to display when Global Auto-Revert Mode is active. | |
146 | ||
147 | The default is nothing since when this mode is active this text doesn't | |
48764ae2 | 148 | vary over time, or between buffers. Hence mode line text |
4a35aff3 RS |
149 | would only waste precious space." |
150 | :group 'auto-revert | |
151 | :type 'string) | |
152 | ||
153 | (defcustom global-auto-revert-mode-hook nil | |
154 | "Hook called when Global Auto-Revert Mode is activated." | |
155 | :group 'auto-revert | |
156 | :type 'hook) | |
157 | ||
158 | (defcustom global-auto-revert-non-file-buffers nil | |
159 | "*When nil only file buffers are reverted by Global Auto-Revert Mode. | |
160 | ||
161 | When non-nil, both file buffers and buffers with a custom | |
162 | `revert-buffer-function' are reverted by Global Auto-Revert Mode." | |
163 | :group 'auto-revert | |
164 | :type 'boolean) | |
165 | ||
166 | (defcustom global-auto-revert-non-file-buffers nil | |
167 | "When nil only file buffers are reverted by Global Auto-Revert Mode. | |
168 | ||
169 | When non-nil, both file buffers and buffers with a custom | |
170 | `revert-buffer-function' are reverted by Global Auto-Revert Mode. | |
171 | ||
172 | Use this option with care since it could lead to excessive reverts." | |
173 | :group 'auto-revert | |
174 | :type 'boolean) | |
175 | ||
176 | (defcustom global-auto-revert-ignore-modes '() | |
177 | "List of major modes Global Auto-Revert Mode should not check." | |
178 | :group 'auto-revert | |
179 | :type '(repeat sexp)) | |
180 | ||
181 | (defcustom auto-revert-load-hook nil | |
182 | "Functions to run when Auto-Revert Mode is first loaded." | |
183 | :tag "Load Hook" | |
184 | :group 'auto-revert | |
185 | :type 'hook) | |
186 | ||
187 | (defvar global-auto-revert-ignore-buffer nil | |
f1e3ff80 | 188 | "*When non-nil, Global Auto-Revert Mode will not revert this buffer. |
4a35aff3 | 189 | |
48764ae2 | 190 | This variable becomes buffer local when set in any fashion.") |
4a35aff3 RS |
191 | (make-variable-buffer-local 'global-auto-revert-ignore-buffer) |
192 | ||
193 | ||
194 | ;; Internal variables: | |
195 | ||
196 | (defvar auto-revert-buffer-list '() | |
197 | "List of buffers in Auto-Revert Mode. | |
198 | ||
199 | Note that only Auto-Revert Mode, never Global Auto-Revert Mode, adds | |
200 | buffers to this list. | |
201 | ||
202 | The timer function `auto-revert-buffers' is responsible for purging | |
203 | the list of old buffers.") | |
204 | ||
205 | (defvar auto-revert-timer nil | |
206 | "Timer used by Auto-Revert Mode.") | |
207 | ||
208 | (defvar auto-revert-remaining-buffers '() | |
209 | "Buffers not checked when user input stopped execution.") | |
210 | ||
211 | ||
212 | ;; Functions: | |
213 | ||
214 | ;;;###autoload | |
215 | (defun auto-revert-mode (&optional arg) | |
48764ae2 | 216 | "Toggle reverting buffer when file on disk changes. |
4a35aff3 | 217 | |
48764ae2 DL |
218 | With arg, turn Auto Revert mode on if and only if arg is positive. |
219 | This is a minor mode that affects only the current buffer. | |
4a35aff3 RS |
220 | Use `global-auto-revert-mode' to automatically revert all buffers." |
221 | (interactive "P") | |
222 | (make-local-variable 'auto-revert-mode) | |
afa95cac | 223 | (put 'auto-revert-mode 'permanent-local t) |
4a35aff3 RS |
224 | (setq auto-revert-mode |
225 | (if (null arg) | |
226 | (not auto-revert-mode) | |
227 | (> (prefix-numeric-value arg) 0))) | |
228 | (if (and auto-revert-verbose | |
229 | (interactive-p)) | |
230 | (message "Auto-Revert Mode is now %s." | |
231 | (if auto-revert-mode "on" "off"))) | |
232 | (if auto-revert-mode | |
233 | (if (not (memq (current-buffer) auto-revert-buffer-list)) | |
234 | (push (current-buffer) auto-revert-buffer-list)) | |
235 | (setq auto-revert-buffer-list | |
236 | (delq (current-buffer) auto-revert-buffer-list))) | |
237 | (auto-revert-set-timer) | |
238 | (when auto-revert-mode | |
239 | (auto-revert-buffers) | |
240 | (run-hooks 'auto-revert-mode-hook))) | |
241 | ||
242 | ||
243 | ;;;###autoload | |
244 | (defun turn-on-auto-revert-mode () | |
245 | "Turn on Auto-Revert Mode. | |
246 | ||
247 | This function is designed to be added to hooks, for example: | |
248 | (add-hook 'c-mode-hook 'turn-on-auto-revert-mode)" | |
249 | (auto-revert-mode 1)) | |
250 | ||
251 | ||
252 | ;;;###autoload | |
253 | (defun global-auto-revert-mode (&optional arg) | |
254 | "Revert any buffer when file on disk change. | |
255 | ||
48764ae2 DL |
256 | With arg, turn Auto Revert mode on globally if and only if arg is positive. |
257 | This is a minor mode that affects all buffers. | |
4a35aff3 RS |
258 | Use `auto-revert-mode' to revert a particular buffer." |
259 | (interactive "P") | |
260 | (setq global-auto-revert-mode | |
261 | (if (null arg) | |
262 | (not global-auto-revert-mode) | |
263 | (> (prefix-numeric-value arg) 0))) | |
264 | (if (and auto-revert-verbose | |
265 | (interactive-p)) | |
f1e3ff80 | 266 | (message "Global Auto-Revert Mode is now %s." |
4a35aff3 RS |
267 | (if global-auto-revert-mode "on" "off"))) |
268 | (auto-revert-set-timer) | |
269 | (when global-auto-revert-mode | |
270 | (auto-revert-buffers) | |
271 | (run-hooks 'global-auto-revert-mode-hook))) | |
272 | ||
273 | ||
274 | (defun auto-revert-set-timer () | |
275 | "Restart or cancel the timer." | |
276 | (if (timerp auto-revert-timer) | |
277 | (cancel-timer auto-revert-timer)) | |
278 | (if (or global-auto-revert-mode auto-revert-buffer-list) | |
279 | (setq auto-revert-timer (run-with-timer auto-revert-interval | |
280 | auto-revert-interval | |
281 | 'auto-revert-buffers)) | |
282 | (setq auto-revert-timer nil))) | |
283 | ||
284 | ||
285 | (defun auto-revert-buffers () | |
286 | "Revert buffers as specified by Auto-Revert and Global Auto-Revert Mode. | |
287 | ||
288 | Should `global-auto-revert-mode' be active all file buffers are checked. | |
289 | ||
290 | Should `auto-revert-mode' be active in some buffers, those buffers | |
291 | are checked. | |
292 | ||
293 | Non-file buffers that have a custom `revert-buffer-function' are | |
294 | reverted either when Auto-Revert Mode is active in that buffer, or | |
295 | when the variable `global-auto-revert-non-file-buffers' is non-nil | |
296 | and Global Auto-Revert Mode is active. | |
297 | ||
48764ae2 | 298 | This function stops whenever there is user input. The buffers not |
4a35aff3 RS |
299 | checked are stored in the variable `auto-revert-remaining-buffers'. |
300 | ||
301 | To avoid starvation, the buffers in `auto-revert-remaining-buffers' | |
302 | are checked first the next time this function is called. | |
303 | ||
48764ae2 | 304 | This function is also responsible for removing buffers no longer in |
4a35aff3 RS |
305 | Auto-Revert mode from `auto-revert-buffer-list', and for canceling |
306 | the timer when no buffers need to be checked." | |
307 | (let ((bufs (if global-auto-revert-mode | |
308 | (buffer-list) | |
309 | auto-revert-buffer-list)) | |
310 | (remaining '()) | |
311 | (new '())) | |
312 | ;; Partition `bufs' into two halves depending on whether or not | |
313 | ;; the buffers are in `auto-revert-remaining-buffers'. The two | |
314 | ;; halves are then re-joined with the "remaining" buffers at the | |
315 | ;; head of the list. | |
316 | (dolist (buf auto-revert-remaining-buffers) | |
317 | (if (memq buf bufs) | |
318 | (push buf remaining))) | |
319 | (dolist (buf bufs) | |
320 | (if (not (memq buf remaining)) | |
321 | (push buf new))) | |
322 | (setq bufs (nreverse (nconc new remaining))) | |
323 | (while (and bufs | |
324 | (not (and auto-revert-stop-on-user-input | |
325 | (input-pending-p)))) | |
326 | (let ((buf (car bufs))) | |
327 | (if (buffer-name buf) ; Buffer still alive? | |
328 | (save-excursion | |
329 | (set-buffer buf) | |
330 | ;; Test if someone has turned off Auto-Revert Mode in a | |
331 | ;; non-standard way, for example by changing major mode. | |
332 | (if (and (not auto-revert-mode) | |
333 | (memq buf auto-revert-buffer-list)) | |
334 | (setq auto-revert-buffer-list | |
335 | (delq buf auto-revert-buffer-list))) | |
336 | (when (and | |
337 | (or auto-revert-mode | |
338 | (and | |
339 | global-auto-revert-mode | |
340 | (not global-auto-revert-ignore-buffer) | |
341 | (not (memq major-mode | |
342 | global-auto-revert-ignore-modes)))) | |
343 | (not (buffer-modified-p)) | |
344 | (if (buffer-file-name) | |
345 | (and (file-readable-p (buffer-file-name)) | |
346 | (not (verify-visited-file-modtime buf))) | |
347 | (and revert-buffer-function | |
348 | (or (and global-auto-revert-mode | |
349 | global-auto-revert-non-file-buffers) | |
350 | auto-revert-mode)))) | |
351 | (if auto-revert-verbose | |
352 | (message "Reverting buffer `%s'." buf)) | |
353 | (revert-buffer t t))) | |
354 | ;; Remove dead buffer from `auto-revert-buffer-list'. | |
355 | (setq auto-revert-buffer-list | |
356 | (delq buf auto-revert-buffer-list)))) | |
357 | (setq bufs (cdr bufs))) | |
358 | (setq auto-revert-remaining-buffers bufs) | |
359 | ;; Check if we should cancel the timer. | |
360 | (when (and (not global-auto-revert-mode) | |
361 | (null auto-revert-buffer-list)) | |
362 | (cancel-timer auto-revert-timer) | |
363 | (setq auto-revert-timer nil)))) | |
364 | ||
365 | ||
366 | ;; The end: | |
367 | ||
368 | (unless (assq 'auto-revert-mode minor-mode-alist) | |
369 | (push '(auto-revert-mode auto-revert-mode-text) | |
370 | minor-mode-alist)) | |
371 | (unless (assq 'global-auto-revert-mode minor-mode-alist) | |
372 | (push '(global-auto-revert-mode global-auto-revert-mode-text) | |
373 | minor-mode-alist)) | |
374 | ||
375 | (provide 'autorevert) | |
376 | ||
377 | (run-hooks 'auto-revert-load-hook) | |
378 | ||
379 | ;; This makes it possible to set Global Auto-Revert Mode from | |
380 | ;; Customize. | |
381 | (if global-auto-revert-mode | |
382 | (global-auto-revert-mode 1)) | |
383 | ||
384 | ;; autorevert.el ends here. |