Mercurial > emacs
comparison lisp/autorevert.el @ 18597:515b7c955cd8
Initial revision
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Fri, 04 Jul 1997 05:07:07 +0000 |
parents | |
children | b644667dcd19 |
comparison
equal
deleted
inserted
replaced
18596:350a4dffed95 | 18597:515b7c955cd8 |
---|---|
1 ;; autorevert --- Revert buffers when file on disk change. | |
2 | |
3 ;; Copyright (C) 1997 Free Software Foundation, Inc. | |
4 | |
5 ;; Author: Anders Lindgren <andersl@csd.uu.se> | |
6 ;; Created: 1 Jun 1997 | |
7 ;; Date: 3 Jul 1997 | |
8 | |
9 ;; This file is part of GNU Emacs. | |
10 | |
11 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
12 ;; it under the terms of the GNU General Public License as published by | |
13 ;; the Free Software Foundation; either version 2, or (at your option) | |
14 ;; any later version. | |
15 | |
16 ;; GNU Emacs is distributed in the hope that it will be useful, | |
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 ;; GNU General Public License for more details. | |
20 | |
21 ;; You should have received a copy of the GNU General Public License | |
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
24 ;; Boston, MA 02111-1307, USA. | |
25 | |
26 ;;; Commentary: | |
27 | |
28 ;; Introduction: | |
29 ;; | |
30 ;; Whenever a file that Emacs is editing has been changed by another | |
31 ;; program the user normally have to execute the command `revert-buffer' | |
32 ;; to load the new content of the file into Emacs. | |
33 ;; | |
34 ;; This package contains two minor modes: Global Auto-Revert Mode and | |
35 ;; Auto-Revert Mode. Both modes automatically reverts buffers | |
36 ;; whenever the corresponding files have been changed on disk. | |
37 ;; | |
38 ;; Auto-Revert Mode can be activated for individual buffers. | |
39 ;; Global Auto-Revert Mode applies to all file buffers. | |
40 ;; | |
41 ;; Both modes operates by checking the time stamp of all files at | |
42 ;; given intervals, the default is every five seconds. The check is | |
43 ;; aborted whenever the user actually use Emacs. Hopefully you will | |
44 ;; never even notice that this package is active (except that your | |
45 ;; buffers will be reverted, of course). | |
46 | |
47 ;; Installation: | |
48 ;; | |
49 ;; To install this package, place it in somewhere on Emacs' load-path, | |
50 ;; byte-compile it (not necessary), and place the following lines in | |
51 ;; the appropriate init file: | |
52 ;; | |
53 ;; (autoload 'auto-revert-mode "autorevert" nil t) | |
54 ;; (autoload 'turn-on-auto-revert-mode "autorevert" nil nil) | |
55 ;; (autoload 'global-auto-revert-mode "autorevert" nil t) | |
56 | |
57 ;; Usage: | |
58 ;; | |
59 ;; Go to the appropriate buffer and press: | |
60 ;; M-x auto-revert-mode RET | |
61 ;; | |
62 ;; To activate Global Auto-Revert Mode, press: | |
63 ;; M-x global-auto-revert-mode RET | |
64 ;; | |
65 ;; To activate Global Auto-Revert Mode every time Emacs is started the | |
66 ;; following line could be added to your ~/.emacs: | |
67 ;; (global-auto-revert-mode 1) | |
68 ;; | |
69 ;; The function `turn-on-auto-revert-mode' could be added to any major | |
70 ;; mode hook to activate Auto-Revert Mode for all buffers in that | |
71 ;; mode. For example, the following line will activate Auto-Revert | |
72 ;; Mode in all C mode buffers: | |
73 ;; | |
74 ;; (add-hook 'c-mode-hook 'turn-on-auto-revert-mode) | |
75 | |
76 ;;; Code: | |
77 | |
78 ;; Dependencies: | |
79 | |
80 (require 'timer) | |
81 (eval-when-compile (require 'cl)) | |
82 | |
83 | |
84 ;; Custom Group: | |
85 ;; | |
86 ;; The two modes will be placed next to Auto Save Mode under the | |
87 ;; Files group under Emacs. | |
88 | |
89 (defgroup auto-revert nil | |
90 "Revert individual buffer when file on disk change. | |
91 | |
92 Auto-Revert Mode can be activated for individual buffer. | |
93 Global Auto-Revert Mode applies to all buffers." | |
94 :group 'files) | |
95 | |
96 | |
97 ;; Variables: | |
98 | |
99 (defvar auto-revert-mode nil | |
100 "*Non-nil when Auto-Revert Mode is active. | |
101 | |
102 Do never set this variable directly, use the command | |
103 `auto-revert-mode' instead.") | |
104 | |
105 (defcustom global-auto-revert-mode nil | |
106 "When on, buffers are automatically reverted when files on disk change. | |
107 | |
108 Set this variable when using \\[customize] only. Otherwise, use the | |
109 command `global-auto-revert-mode' instead." | |
110 :group 'auto-revert | |
111 :initialize 'custom-initialize-default | |
112 :set '(lambda (symbol value) | |
113 (global-auto-revert-mode (or value 0))) | |
114 :type 'boolean | |
115 :require 'autorevert) | |
116 | |
117 (defcustom auto-revert-interval 5 | |
118 "Time, in seconds, between Auto-Revert Mode file checks." | |
119 :group 'auto-revert | |
120 :type 'integer) | |
121 | |
122 (defcustom auto-revert-stop-on-user-input t | |
123 "When non-nil Auto-Revert Mode stops checking files on user input." | |
124 :group 'auto-revert | |
125 :type 'boolean) | |
126 | |
127 (defcustom auto-revert-verbose t | |
128 "When nil, Auto-Revert Mode will not generate any messages. | |
129 | |
130 Currently, messages are generated when the mode is activated or | |
131 deactivated, and whenever a file is reverted." | |
132 :group 'auto-revert | |
133 :type 'boolean) | |
134 | |
135 (defcustom auto-revert-mode-text " ARev" | |
136 "String to display in the mode line when Auto-Revert Mode is active. | |
137 | |
138 \(When the string is not empty, make sure that it has a leading space.)" | |
139 :tag "Auto Revert Mode Text" ; To separate it from `global-...' | |
140 :group 'auto-revert | |
141 :type 'string) | |
142 | |
143 (defcustom auto-revert-mode-hook nil | |
144 "Functions to run when Auto-Revert Mode is activated." | |
145 :tag "Auto Revert Mode Hook" ; To separate it from `global-...' | |
146 :group 'auto-revert | |
147 :type 'hook) | |
148 | |
149 (defcustom global-auto-revert-mode-text "" | |
150 "String to display when Global Auto-Revert Mode is active. | |
151 | |
152 The default is nothing since when this mode is active this text doesn't | |
153 vary neither over time, nor between buffers. Hence a mode line text | |
154 would only waste precious space." | |
155 :group 'auto-revert | |
156 :type 'string) | |
157 | |
158 (defcustom global-auto-revert-mode-hook nil | |
159 "Hook called when Global Auto-Revert Mode is activated." | |
160 :group 'auto-revert | |
161 :type 'hook) | |
162 | |
163 (defcustom global-auto-revert-non-file-buffers nil | |
164 "*When nil only file buffers are reverted by Global Auto-Revert Mode. | |
165 | |
166 When non-nil, both file buffers and buffers with a custom | |
167 `revert-buffer-function' are reverted by Global Auto-Revert Mode." | |
168 :group 'auto-revert | |
169 :type 'boolean) | |
170 | |
171 (defcustom global-auto-revert-non-file-buffers nil | |
172 "When nil only file buffers are reverted by Global Auto-Revert Mode. | |
173 | |
174 When non-nil, both file buffers and buffers with a custom | |
175 `revert-buffer-function' are reverted by Global Auto-Revert Mode. | |
176 | |
177 Use this option with care since it could lead to excessive reverts." | |
178 :group 'auto-revert | |
179 :type 'boolean) | |
180 | |
181 (defcustom global-auto-revert-ignore-modes '() | |
182 "List of major modes Global Auto-Revert Mode should not check." | |
183 :group 'auto-revert | |
184 :type '(repeat sexp)) | |
185 | |
186 (defcustom auto-revert-load-hook nil | |
187 "Functions to run when Auto-Revert Mode is first loaded." | |
188 :tag "Load Hook" | |
189 :group 'auto-revert | |
190 :type 'hook) | |
191 | |
192 (defvar global-auto-revert-ignore-buffer nil | |
193 "*When non-nil, Gobal Auto-Revert Mode will not revert this buffer. | |
194 | |
195 This variable becomes buffer local when set in any faishon.") | |
196 (make-variable-buffer-local 'global-auto-revert-ignore-buffer) | |
197 | |
198 | |
199 ;; Internal variables: | |
200 | |
201 (defvar auto-revert-buffer-list '() | |
202 "List of buffers in Auto-Revert Mode. | |
203 | |
204 Note that only Auto-Revert Mode, never Global Auto-Revert Mode, adds | |
205 buffers to this list. | |
206 | |
207 The timer function `auto-revert-buffers' is responsible for purging | |
208 the list of old buffers.") | |
209 | |
210 (defvar auto-revert-timer nil | |
211 "Timer used by Auto-Revert Mode.") | |
212 | |
213 (defvar auto-revert-remaining-buffers '() | |
214 "Buffers not checked when user input stopped execution.") | |
215 | |
216 | |
217 ;; Functions: | |
218 | |
219 ;;;###autoload | |
220 (defun auto-revert-mode (&optional arg) | |
221 "Revert buffer when file on disk change. | |
222 | |
223 This is a minor mode that affect only the current buffer. | |
224 Use `global-auto-revert-mode' to automatically revert all buffers." | |
225 (interactive "P") | |
226 (make-local-variable 'auto-revert-mode) | |
227 (setq auto-revert-mode | |
228 (if (null arg) | |
229 (not auto-revert-mode) | |
230 (> (prefix-numeric-value arg) 0))) | |
231 (if (and auto-revert-verbose | |
232 (interactive-p)) | |
233 (message "Auto-Revert Mode is now %s." | |
234 (if auto-revert-mode "on" "off"))) | |
235 (if auto-revert-mode | |
236 (if (not (memq (current-buffer) auto-revert-buffer-list)) | |
237 (push (current-buffer) auto-revert-buffer-list)) | |
238 (setq auto-revert-buffer-list | |
239 (delq (current-buffer) auto-revert-buffer-list))) | |
240 (auto-revert-set-timer) | |
241 (when auto-revert-mode | |
242 (auto-revert-buffers) | |
243 (run-hooks 'auto-revert-mode-hook))) | |
244 | |
245 | |
246 ;;;###autoload | |
247 (defun turn-on-auto-revert-mode () | |
248 "Turn on Auto-Revert Mode. | |
249 | |
250 This function is designed to be added to hooks, for example: | |
251 (add-hook 'c-mode-hook 'turn-on-auto-revert-mode)" | |
252 (auto-revert-mode 1)) | |
253 | |
254 | |
255 ;;;###autoload | |
256 (defun global-auto-revert-mode (&optional arg) | |
257 "Revert any buffer when file on disk change. | |
258 | |
259 This is a minor mode that affect all buffers. | |
260 Use `auto-revert-mode' to revert a particular buffer." | |
261 (interactive "P") | |
262 (setq global-auto-revert-mode | |
263 (if (null arg) | |
264 (not global-auto-revert-mode) | |
265 (> (prefix-numeric-value arg) 0))) | |
266 (if (and auto-revert-verbose | |
267 (interactive-p)) | |
268 (message "Gobal Auto-Revert Mode is now %s." | |
269 (if global-auto-revert-mode "on" "off"))) | |
270 (auto-revert-set-timer) | |
271 (when global-auto-revert-mode | |
272 (auto-revert-buffers) | |
273 (run-hooks 'global-auto-revert-mode-hook))) | |
274 | |
275 | |
276 (defun auto-revert-set-timer () | |
277 "Restart or cancel the timer." | |
278 (if (timerp auto-revert-timer) | |
279 (cancel-timer auto-revert-timer)) | |
280 (if (or global-auto-revert-mode auto-revert-buffer-list) | |
281 (setq auto-revert-timer (run-with-timer auto-revert-interval | |
282 auto-revert-interval | |
283 'auto-revert-buffers)) | |
284 (setq auto-revert-timer nil))) | |
285 | |
286 | |
287 (defun auto-revert-buffers () | |
288 "Revert buffers as specified by Auto-Revert and Global Auto-Revert Mode. | |
289 | |
290 Should `global-auto-revert-mode' be active all file buffers are checked. | |
291 | |
292 Should `auto-revert-mode' be active in some buffers, those buffers | |
293 are checked. | |
294 | |
295 Non-file buffers that have a custom `revert-buffer-function' are | |
296 reverted either when Auto-Revert Mode is active in that buffer, or | |
297 when the variable `global-auto-revert-non-file-buffers' is non-nil | |
298 and Global Auto-Revert Mode is active. | |
299 | |
300 This function stops whenever the user use Emacs. The buffers not | |
301 checked are stored in the variable `auto-revert-remaining-buffers'. | |
302 | |
303 To avoid starvation, the buffers in `auto-revert-remaining-buffers' | |
304 are checked first the next time this function is called. | |
305 | |
306 This function is also responslible for removing buffers no longer in | |
307 Auto-Revert mode from `auto-revert-buffer-list', and for canceling | |
308 the timer when no buffers need to be checked." | |
309 (let ((bufs (if global-auto-revert-mode | |
310 (buffer-list) | |
311 auto-revert-buffer-list)) | |
312 (remaining '()) | |
313 (new '())) | |
314 ;; Partition `bufs' into two halves depending on whether or not | |
315 ;; the buffers are in `auto-revert-remaining-buffers'. The two | |
316 ;; halves are then re-joined with the "remaining" buffers at the | |
317 ;; head of the list. | |
318 (dolist (buf auto-revert-remaining-buffers) | |
319 (if (memq buf bufs) | |
320 (push buf remaining))) | |
321 (dolist (buf bufs) | |
322 (if (not (memq buf remaining)) | |
323 (push buf new))) | |
324 (setq bufs (nreverse (nconc new remaining))) | |
325 (while (and bufs | |
326 (not (and auto-revert-stop-on-user-input | |
327 (input-pending-p)))) | |
328 (let ((buf (car bufs))) | |
329 (if (buffer-name buf) ; Buffer still alive? | |
330 (save-excursion | |
331 (set-buffer buf) | |
332 ;; Test if someone has turned off Auto-Revert Mode in a | |
333 ;; non-standard way, for example by changing major mode. | |
334 (if (and (not auto-revert-mode) | |
335 (memq buf auto-revert-buffer-list)) | |
336 (setq auto-revert-buffer-list | |
337 (delq buf auto-revert-buffer-list))) | |
338 (when (and | |
339 (or auto-revert-mode | |
340 (and | |
341 global-auto-revert-mode | |
342 (not global-auto-revert-ignore-buffer) | |
343 (not (memq major-mode | |
344 global-auto-revert-ignore-modes)))) | |
345 (not (buffer-modified-p)) | |
346 (if (buffer-file-name) | |
347 (and (file-readable-p (buffer-file-name)) | |
348 (not (verify-visited-file-modtime buf))) | |
349 (and revert-buffer-function | |
350 (or (and global-auto-revert-mode | |
351 global-auto-revert-non-file-buffers) | |
352 auto-revert-mode)))) | |
353 (if auto-revert-verbose | |
354 (message "Reverting buffer `%s'." buf)) | |
355 (revert-buffer t t))) | |
356 ;; Remove dead buffer from `auto-revert-buffer-list'. | |
357 (setq auto-revert-buffer-list | |
358 (delq buf auto-revert-buffer-list)))) | |
359 (setq bufs (cdr bufs))) | |
360 (setq auto-revert-remaining-buffers bufs) | |
361 ;; Check if we should cancel the timer. | |
362 (when (and (not global-auto-revert-mode) | |
363 (null auto-revert-buffer-list)) | |
364 (cancel-timer auto-revert-timer) | |
365 (setq auto-revert-timer nil)))) | |
366 | |
367 | |
368 ;; The end: | |
369 | |
370 (unless (assq 'auto-revert-mode minor-mode-alist) | |
371 (push '(auto-revert-mode auto-revert-mode-text) | |
372 minor-mode-alist)) | |
373 (unless (assq 'global-auto-revert-mode minor-mode-alist) | |
374 (push '(global-auto-revert-mode global-auto-revert-mode-text) | |
375 minor-mode-alist)) | |
376 | |
377 (provide 'autorevert) | |
378 | |
379 (run-hooks 'auto-revert-load-hook) | |
380 | |
381 ;; This makes it possible to set Global Auto-Revert Mode from | |
382 ;; Customize. | |
383 (if global-auto-revert-mode | |
384 (global-auto-revert-mode 1)) | |
385 | |
386 ;; autorevert.el ends here. |