Commit | Line | Data |
---|---|---|
e8af40ee | 1 | ;;; autorevert.el --- revert buffers when files on disk change |
4a35aff3 | 2 | |
ab422c4d | 3 | ;; Copyright (C) 1997-1999, 2001-2013 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 | ||
eb3fa2cf | 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
4a35aff3 | 13 | ;; it under the terms of the GNU General Public License as published by |
eb3fa2cf GM |
14 | ;; the Free Software Foundation, either version 3 of the License, or |
15 | ;; (at your option) any later version. | |
4a35aff3 RS |
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 | |
eb3fa2cf | 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
4a35aff3 RS |
24 | |
25 | ;;; Commentary: | |
26 | ||
27 | ;; Introduction: | |
28 | ;; | |
29 | ;; Whenever a file that Emacs is editing has been changed by another | |
48764ae2 | 30 | ;; program the user normally has to execute the command `revert-buffer' |
4a35aff3 RS |
31 | ;; to load the new content of the file into Emacs. |
32 | ;; | |
33 | ;; This package contains two minor modes: Global Auto-Revert Mode and | |
48764ae2 | 34 | ;; Auto-Revert Mode. Both modes automatically revert buffers |
2d677766 LT |
35 | ;; whenever the corresponding files have been changed on disk and the |
36 | ;; buffer contains no unsaved changes. | |
4a35aff3 | 37 | ;; |
ae229809 LT |
38 | ;; Auto-Revert Mode can be activated for individual buffers. Global |
39 | ;; Auto-Revert Mode applies to all file buffers. (If the user option | |
40 | ;; `global-auto-revert-non-file-buffers' is non-nil, it also applies | |
41 | ;; to some non-file buffers. This option is disabled by default.) | |
ef3544f6 MA |
42 | ;; |
43 | ;; Since checking a remote file is slow, these modes check or revert | |
44 | ;; remote files only if the user option `auto-revert-remote-files' is | |
45 | ;; non-nil. It is recommended to disable version control for remote | |
46 | ;; files. | |
4a35aff3 | 47 | ;; |
48764ae2 DL |
48 | ;; Both modes operate by checking the time stamp of all files at |
49 | ;; intervals of `auto-revert-interval'. The default is every five | |
50 | ;; seconds. The check is aborted whenever the user actually uses | |
51 | ;; Emacs. You should never even notice that this package is active | |
52 | ;; (except that your buffers will be reverted, of course). | |
1f41bcba | 53 | ;; |
ef3544f6 MA |
54 | ;; If Emacs is compiled with file notification support, notifications |
55 | ;; are used instead of checking the time stamp of the files. You can | |
a778dd57 | 56 | ;; disable this by setting the user option `auto-revert-use-notify' to |
ef3544f6 MA |
57 | ;; nil. Alternatively, a regular expression of directories to be |
58 | ;; excluded from file notifications can be specified by | |
59 | ;; `auto-revert-notify-exclude-dir-regexp'. | |
ed911257 | 60 | ;; |
1f41bcba LT |
61 | ;; After reverting a file buffer, Auto Revert Mode normally puts point |
62 | ;; at the same position that a regular manual revert would. However, | |
63 | ;; there is one exception to this rule. If point is at the end of the | |
64 | ;; buffer before reverting, it stays at the end. Similarly if point | |
65 | ;; is displayed at the end of a file buffer in any window, it will stay | |
66 | ;; at the end of the buffer in that window, even if the window is not | |
67 | ;; selected. This way, you can use Auto Revert Mode to `tail' a file. | |
68 | ;; Just put point at the end of the buffer and it will stay there. | |
69 | ;; These rules apply to file buffers. For non-file buffers, the | |
70 | ;; behavior may be mode dependent. | |
2d677766 LT |
71 | ;; |
72 | ;; While you can use Auto Revert Mode to tail a file, this package | |
73 | ;; contains a third minor mode, Auto Revert Tail Mode, which does so | |
74 | ;; more efficiently, as long as you are sure that the file will only | |
75 | ;; change by growing at the end. It only appends the new output, | |
76 | ;; instead of reverting the entire buffer. It does so even if the | |
77 | ;; buffer contains unsaved changes. (Because they will not be lost.) | |
4a35aff3 RS |
78 | |
79 | ;; Usage: | |
80 | ;; | |
dddc748b | 81 | ;; Go to the appropriate buffer and press either of: |
4a35aff3 | 82 | ;; M-x auto-revert-mode RET |
dddc748b | 83 | ;; M-x auto-revert-tail-mode RET |
4a35aff3 RS |
84 | ;; |
85 | ;; To activate Global Auto-Revert Mode, press: | |
86 | ;; M-x global-auto-revert-mode RET | |
87 | ;; | |
48764ae2 | 88 | ;; To activate Global Auto-Revert Mode every time Emacs is started |
e1dbe924 | 89 | ;; customize the option `global-auto-revert-mode' or the following |
48764ae2 | 90 | ;; line could be added to your ~/.emacs: |
4a35aff3 RS |
91 | ;; (global-auto-revert-mode 1) |
92 | ;; | |
93 | ;; The function `turn-on-auto-revert-mode' could be added to any major | |
94 | ;; mode hook to activate Auto-Revert Mode for all buffers in that | |
95 | ;; mode. For example, the following line will activate Auto-Revert | |
96 | ;; Mode in all C mode buffers: | |
97 | ;; | |
98 | ;; (add-hook 'c-mode-hook 'turn-on-auto-revert-mode) | |
99 | ||
100 | ;;; Code: | |
101 | ||
102 | ;; Dependencies: | |
103 | ||
96c421bb | 104 | (eval-when-compile (require 'cl-lib)) |
4a35aff3 | 105 | (require 'timer) |
0f98bc23 | 106 | |
4a35aff3 RS |
107 | ;; Custom Group: |
108 | ;; | |
109 | ;; The two modes will be placed next to Auto Save Mode under the | |
110 | ;; Files group under Emacs. | |
111 | ||
112 | (defgroup auto-revert nil | |
48764ae2 | 113 | "Revert individual buffers when files on disk change. |
cf20dee0 CY |
114 | Auto-Revert mode enables auto-revert in individual buffers. |
115 | Global Auto-Revert mode does so in all buffers." | |
f5f727f8 DN |
116 | :group 'files |
117 | :group 'convenience) | |
4a35aff3 RS |
118 | |
119 | ||
120 | ;; Variables: | |
121 | ||
dddc748b DP |
122 | ;;; What's this?: ;; Autoload for the benefit of `make-mode-line-mouse-sensitive'. |
123 | ;;; What's this?: ;;;###autoload | |
4a35aff3 | 124 | (defvar auto-revert-mode nil |
18cfb5a1 | 125 | "Non-nil when Auto-Revert Mode is active. |
0e4f9468 SM |
126 | Never set this variable directly, use the command `auto-revert-mode' instead.") |
127 | (put 'auto-revert-mode 'permanent-local t) | |
4a35aff3 | 128 | |
dddc748b | 129 | (defvar auto-revert-tail-mode nil |
18cfb5a1 | 130 | "Non-nil when Auto-Revert Tail Mode is active. |
9e559f9b LT |
131 | Never set this variable directly, use the command |
132 | `auto-revert-tail-mode' instead.") | |
dddc748b DP |
133 | (put 'auto-revert-tail-mode 'permanent-local t) |
134 | ||
a2ac68f1 LT |
135 | (defvar auto-revert-timer nil |
136 | "Timer used by Auto-Revert Mode.") | |
137 | ||
4a35aff3 | 138 | (defcustom auto-revert-interval 5 |
ad660075 | 139 | "Time, in seconds, between Auto-Revert Mode file checks. |
a2ac68f1 LT |
140 | The value may be an integer or floating point number. |
141 | ||
142 | If a timer is already active, there are two ways to make sure | |
143 | that the new value will take effect immediately. You can set | |
144 | this variable through Custom or you can call the command | |
145 | `auto-revert-set-timer' after setting the variable. Otherwise, | |
146 | the new value will take effect the first time Auto Revert Mode | |
147 | calls `auto-revert-set-timer' for internal reasons or in your | |
148 | next editing session." | |
4a35aff3 | 149 | :group 'auto-revert |
a2ac68f1 LT |
150 | :type 'number |
151 | :set (lambda (variable value) | |
152 | (set-default variable value) | |
153 | (and (boundp 'auto-revert-timer) | |
154 | auto-revert-timer | |
155 | (auto-revert-set-timer)))) | |
4a35aff3 RS |
156 | |
157 | (defcustom auto-revert-stop-on-user-input t | |
6547d313 | 158 | "When non-nil, user input temporarily interrupts Auto-Revert Mode. |
6dbbc01d | 159 | With this setting, Auto-Revert Mode checks for user input after |
5433e578 LT |
160 | handling each buffer and does not process any further buffers |
161 | \(until the next run of the timer) if user input is available. | |
162 | When nil, Auto-Revert Mode checks files and reverts buffers, | |
163 | with quitting disabled, without paying attention to user input. | |
8a593054 | 164 | Thus, with this setting, Emacs might be non-responsive at times." |
4a35aff3 RS |
165 | :group 'auto-revert |
166 | :type 'boolean) | |
167 | ||
168 | (defcustom auto-revert-verbose t | |
6547d313 | 169 | "When nil, Auto-Revert Mode does not generate any messages. |
0e5dcfd7 | 170 | When non-nil, a message is generated whenever a file is reverted." |
4a35aff3 RS |
171 | :group 'auto-revert |
172 | :type 'boolean) | |
173 | ||
174 | (defcustom auto-revert-mode-text " ARev" | |
175 | "String to display in the mode line when Auto-Revert Mode is active. | |
176 | ||
177 | \(When the string is not empty, make sure that it has a leading space.)" | |
178 | :tag "Auto Revert Mode Text" ; To separate it from `global-...' | |
179 | :group 'auto-revert | |
180 | :type 'string) | |
181 | ||
dddc748b DP |
182 | (defcustom auto-revert-tail-mode-text " Tail" |
183 | "String to display in the mode line when Auto-Revert Tail Mode is active. | |
184 | ||
185 | \(When the string is not empty, make sure that it has a leading space.)" | |
186 | :group 'auto-revert | |
0a306700 | 187 | :type 'string |
bf247b6e | 188 | :version "22.1") |
dddc748b | 189 | |
4a35aff3 RS |
190 | (defcustom auto-revert-mode-hook nil |
191 | "Functions to run when Auto-Revert Mode is activated." | |
192 | :tag "Auto Revert Mode Hook" ; To separate it from `global-...' | |
193 | :group 'auto-revert | |
194 | :type 'hook) | |
195 | ||
196 | (defcustom global-auto-revert-mode-text "" | |
197 | "String to display when Global Auto-Revert Mode is active. | |
198 | ||
199 | The default is nothing since when this mode is active this text doesn't | |
48764ae2 | 200 | vary over time, or between buffers. Hence mode line text |
4a35aff3 RS |
201 | would only waste precious space." |
202 | :group 'auto-revert | |
203 | :type 'string) | |
204 | ||
205 | (defcustom global-auto-revert-mode-hook nil | |
206 | "Hook called when Global Auto-Revert Mode is activated." | |
207 | :group 'auto-revert | |
208 | :type 'hook) | |
209 | ||
210 | (defcustom global-auto-revert-non-file-buffers nil | |
d9e4328d | 211 | "When nil, Global Auto-Revert mode operates only on file-visiting buffers. |
4a35aff3 RS |
212 | |
213 | When non-nil, both file buffers and buffers with a custom | |
0e5dcfd7 | 214 | `revert-buffer-function' and a `buffer-stale-function' are |
9ae0d84f | 215 | reverted by Global Auto-Revert mode. These include the Buffer |
fc2f6a26 GM |
216 | List buffer displayed by `buffer-menu', and Dired buffers showing |
217 | complete local directories. The Buffer List buffer reverts every | |
218 | `auto-revert-interval' seconds; Dired buffers when the file list of | |
219 | the main directory changes. Dired buffers do not auto-revert as | |
220 | a result of changes in subdirectories, or in the contents, size, | |
221 | modes, etc., of files. You may still sometimes want to revert | |
222 | them manually. | |
0e4f9468 | 223 | |
d9e4328d | 224 | Use this option with care since it could lead to excessive auto-reverts. |
415053a1 | 225 | For more information, see Info node `(emacs)Autorevert'." |
4a35aff3 | 226 | :group 'auto-revert |
843c51ae | 227 | :type 'boolean |
415053a1 | 228 | :link '(info-link "(emacs)Autorevert")) |
4a35aff3 | 229 | |
dddc748b | 230 | (defcustom global-auto-revert-ignore-modes () |
4a35aff3 RS |
231 | "List of major modes Global Auto-Revert Mode should not check." |
232 | :group 'auto-revert | |
233 | :type '(repeat sexp)) | |
234 | ||
235 | (defcustom auto-revert-load-hook nil | |
236 | "Functions to run when Auto-Revert Mode is first loaded." | |
237 | :tag "Load Hook" | |
238 | :group 'auto-revert | |
239 | :type 'hook) | |
240 | ||
71c8db4c LT |
241 | (defcustom auto-revert-check-vc-info nil |
242 | "If non-nil Auto Revert Mode reliably updates version control info. | |
243 | Auto Revert Mode updates version control info whenever the buffer | |
244 | needs reverting, regardless of the value of this variable. | |
245 | However, the version control state can change without changes to | |
246 | the work file. If the change is made from the current Emacs | |
247 | session, all info is updated. But if, for instance, a new | |
248 | version is checked in from outside the current Emacs session, the | |
249 | version control number in the mode line, as well as other version | |
250 | control related information, may not be properly updated. If you | |
251 | are worried about this, set this variable to a non-nil value. | |
252 | ||
253 | This currently works by automatically updating the version | |
254 | control info every `auto-revert-interval' seconds. Nevertheless, | |
255 | it should not cause excessive CPU usage on a reasonably fast | |
256 | machine, if it does not apply to too many version controlled | |
f9478d4d | 257 | buffers. CPU usage depends on the version control system." |
71c8db4c LT |
258 | :group 'auto-revert |
259 | :type 'boolean | |
bf247b6e | 260 | :version "22.1") |
71c8db4c | 261 | |
4a35aff3 | 262 | (defvar global-auto-revert-ignore-buffer nil |
18cfb5a1 | 263 | "When non-nil, Global Auto-Revert Mode will not revert this buffer. |
48764ae2 | 264 | This variable becomes buffer local when set in any fashion.") |
4a35aff3 RS |
265 | (make-variable-buffer-local 'global-auto-revert-ignore-buffer) |
266 | ||
ef3544f6 MA |
267 | (defcustom auto-revert-remote-files nil |
268 | "If non-nil remote files are also reverted." | |
269 | :group 'auto-revert | |
270 | :type 'boolean | |
271 | :version "24.4") | |
272 | ||
a778dd57 MA |
273 | (defconst auto-revert-notify-enabled |
274 | (or (featurep 'inotify) (featurep 'w32notify)) | |
ef3544f6 | 275 | "Non-nil when Emacs has been compiled with file notification support.") |
a778dd57 MA |
276 | |
277 | (defcustom auto-revert-use-notify auto-revert-notify-enabled | |
ef3544f6 MA |
278 | "If non-nil Auto Revert Mode uses file notification functions. |
279 | This requires Emacs being compiled with file notification | |
280 | support (see `auto-revert-notify-enabled'). You should set this | |
382936d1 | 281 | variable through Custom." |
a778dd57 MA |
282 | :group 'auto-revert |
283 | :type 'boolean | |
284 | :set (lambda (variable value) | |
285 | (set-default variable (and auto-revert-notify-enabled value)) | |
68a08a32 | 286 | (unless (symbol-value variable) |
a778dd57 MA |
287 | (when auto-revert-notify-enabled |
288 | (dolist (buf (buffer-list)) | |
289 | (with-current-buffer buf | |
68a08a32 MA |
290 | (when (symbol-value 'auto-revert-notify-watch-descriptor) |
291 | (auto-revert-notify-rm-watch))))))) | |
2f52b560 | 292 | :initialize 'custom-initialize-default |
a778dd57 MA |
293 | :version "24.4") |
294 | ||
ef3544f6 MA |
295 | (defcustom auto-revert-notify-exclude-dir-regexp |
296 | (concat | |
297 | ;; No mounted file systems. | |
298 | "^" (regexp-opt '("/afs/" "/media/" "/mnt" "/net/" "/tmp_mnt/")) | |
299 | ;; No remote files. | |
300 | (unless auto-revert-remote-files "\\|^/[^/|:][^/|]+:")) | |
301 | "Regular expression of directories to be excluded from file notifications." | |
302 | :group 'auto-revert | |
303 | :type 'regexp | |
304 | :version "24.4") | |
305 | ||
4a35aff3 RS |
306 | ;; Internal variables: |
307 | ||
dddc748b | 308 | (defvar auto-revert-buffer-list () |
4a35aff3 RS |
309 | "List of buffers in Auto-Revert Mode. |
310 | ||
311 | Note that only Auto-Revert Mode, never Global Auto-Revert Mode, adds | |
312 | buffers to this list. | |
313 | ||
314 | The timer function `auto-revert-buffers' is responsible for purging | |
315 | the list of old buffers.") | |
316 | ||
dddc748b | 317 | (defvar auto-revert-remaining-buffers () |
4a35aff3 RS |
318 | "Buffers not checked when user input stopped execution.") |
319 | ||
dddc748b DP |
320 | (defvar auto-revert-tail-pos 0 |
321 | "Position of last known end of file.") | |
322 | ||
323 | (add-hook 'find-file-hook | |
0917bb33 GM |
324 | (lambda () |
325 | (set (make-local-variable 'auto-revert-tail-pos) | |
326 | (nth 7 (file-attributes buffer-file-name))))) | |
4a35aff3 | 327 | |
ed911257 MA |
328 | (defvar auto-revert-notify-watch-descriptor-hash-list |
329 | (make-hash-table :test 'equal) | |
330 | "A hash table collecting all file watch descriptors. | |
ef3544f6 MA |
331 | Hash key is a watch descriptor, hash value is a list of buffers |
332 | which are related to files being watched and carrying the same | |
333 | default directory.") | |
ed911257 MA |
334 | |
335 | (defvar auto-revert-notify-watch-descriptor nil | |
336 | "The file watch descriptor active for the current buffer.") | |
0eb87688 | 337 | (make-variable-buffer-local 'auto-revert-notify-watch-descriptor) |
2daddd9e | 338 | (put 'auto-revert-notify-watch-descriptor 'permanent-local t) |
ed911257 MA |
339 | |
340 | (defvar auto-revert-notify-modified-p nil | |
341 | "Non-nil when file has been modified on the file system. | |
ef3544f6 | 342 | This has been reported by a file notification event.") |
ed911257 MA |
343 | (make-variable-buffer-local 'auto-revert-notify-modified-p) |
344 | ||
4a35aff3 RS |
345 | ;; Functions: |
346 | ||
347 | ;;;###autoload | |
0e4f9468 | 348 | (define-minor-mode auto-revert-mode |
06e21633 CY |
349 | "Toggle reverting buffer when the file changes (Auto Revert mode). |
350 | With a prefix argument ARG, enable Auto Revert mode if ARG is | |
351 | positive, and disable it otherwise. If called from Lisp, enable | |
352 | the mode if ARG is omitted or nil. | |
353 | ||
354 | Auto Revert mode is a minor mode that affects only the current | |
355 | buffer. When enabled, it reverts the buffer when the file on | |
356 | disk changes. | |
4a35aff3 | 357 | |
dddc748b DP |
358 | Use `global-auto-revert-mode' to automatically revert all buffers. |
359 | Use `auto-revert-tail-mode' if you know that the file will only grow | |
360 | without being changed in the part that is already in the buffer." | |
834b5c1e | 361 | :group 'auto-revert :lighter auto-revert-mode-text |
4a35aff3 RS |
362 | (if auto-revert-mode |
363 | (if (not (memq (current-buffer) auto-revert-buffer-list)) | |
364 | (push (current-buffer) auto-revert-buffer-list)) | |
a778dd57 | 365 | (when auto-revert-use-notify (auto-revert-notify-rm-watch)) |
4a35aff3 RS |
366 | (setq auto-revert-buffer-list |
367 | (delq (current-buffer) auto-revert-buffer-list))) | |
368 | (auto-revert-set-timer) | |
369 | (when auto-revert-mode | |
2a417372 MA |
370 | (let (auto-revert-use-notify) |
371 | (auto-revert-buffers) | |
372 | (setq auto-revert-tail-mode nil)))) | |
4a35aff3 RS |
373 | |
374 | ||
375 | ;;;###autoload | |
376 | (defun turn-on-auto-revert-mode () | |
377 | "Turn on Auto-Revert Mode. | |
378 | ||
379 | This function is designed to be added to hooks, for example: | |
380 | (add-hook 'c-mode-hook 'turn-on-auto-revert-mode)" | |
381 | (auto-revert-mode 1)) | |
382 | ||
383 | ||
dddc748b DP |
384 | ;;;###autoload |
385 | (define-minor-mode auto-revert-tail-mode | |
06e21633 CY |
386 | "Toggle reverting tail of buffer when the file grows. |
387 | With a prefix argument ARG, enable Auto-Revert Tail mode if ARG | |
388 | is positive, and disable it otherwise. If called from Lisp, | |
389 | enable the mode if ARG is omitted or nil. | |
dddc748b | 390 | |
06e21633 CY |
391 | When Auto Revert Tail mode is enabled, the tail of the file is |
392 | constantly followed, as with the shell command `tail -f'. This | |
393 | means that whenever the file grows on disk (presumably because | |
394 | some background process is appending to it from time to time), | |
395 | this is reflected in the current buffer. | |
dddc748b DP |
396 | |
397 | You can edit the buffer and turn this mode off and on again as | |
398 | you please. But make sure the background process has stopped | |
399 | writing before you save the file! | |
400 | ||
401 | Use `auto-revert-mode' for changes other than appends!" | |
402 | :group 'find-file :lighter auto-revert-tail-mode-text | |
403 | (when auto-revert-tail-mode | |
404 | (unless buffer-file-name | |
405 | (auto-revert-tail-mode 0) | |
406 | (error "This buffer is not visiting a file")) | |
407 | (if (and (buffer-modified-p) | |
0917bb33 | 408 | (zerop auto-revert-tail-pos) ; library was loaded only after finding file |
dddc748b DP |
409 | (not (y-or-n-p "Buffer is modified, so tail offset may be wrong. Proceed? "))) |
410 | (auto-revert-tail-mode 0) | |
0917bb33 GM |
411 | ;; a-r-tail-pos stores the size of the file at the time of the |
412 | ;; last revert. After this package loads, it adds a | |
413 | ;; find-file-hook to set this variable every time a file is | |
414 | ;; loaded. If the package is loaded only _after_ visiting the | |
415 | ;; file to be reverted, then we have no idea what the value of | |
416 | ;; a-r-tail-pos should have been when the file was visited. If | |
417 | ;; the file has changed on disk in the meantime, all we can do | |
418 | ;; is offer to revert the whole thing. If you choose not to | |
419 | ;; revert, then you might miss some output then happened | |
420 | ;; between visiting the file and activating a-r-t-mode. | |
421 | (and (zerop auto-revert-tail-pos) | |
422 | (not (verify-visited-file-modtime (current-buffer))) | |
423 | (y-or-n-p "File changed on disk, content may be missing. \ | |
424 | Perform a full revert? ") | |
425 | ;; Use this (not just revert-buffer) for point-preservation. | |
2a417372 MA |
426 | (let (auto-revert-use-notify) |
427 | (auto-revert-handler))) | |
dddc748b DP |
428 | ;; else we might reappend our own end when we save |
429 | (add-hook 'before-save-hook (lambda () (auto-revert-tail-mode 0)) nil t) | |
430 | (or (local-variable-p 'auto-revert-tail-pos) ; don't lose prior position | |
f373470d | 431 | (set (make-local-variable 'auto-revert-tail-pos) |
ced3c1e2 | 432 | (nth 7 (file-attributes buffer-file-name)))) |
dddc748b DP |
433 | ;; let auto-revert-mode set up the mechanism for us if it isn't already |
434 | (or auto-revert-mode | |
435 | (let ((auto-revert-tail-mode t)) | |
436 | (auto-revert-mode 1))) | |
437 | (setq auto-revert-mode nil)))) | |
438 | ||
439 | ||
440 | ;;;###autoload | |
441 | (defun turn-on-auto-revert-tail-mode () | |
06e21633 | 442 | "Turn on Auto-Revert Tail mode. |
dddc748b DP |
443 | |
444 | This function is designed to be added to hooks, for example: | |
445 | (add-hook 'my-logfile-mode-hook 'turn-on-auto-revert-tail-mode)" | |
446 | (auto-revert-tail-mode 1)) | |
447 | ||
448 | ||
4a35aff3 | 449 | ;;;###autoload |
0e4f9468 | 450 | (define-minor-mode global-auto-revert-mode |
fc2f6a26 | 451 | "Toggle Global Auto Revert mode. |
06e21633 CY |
452 | With a prefix argument ARG, enable Global Auto Revert mode if ARG |
453 | is positive, and disable it otherwise. If called from Lisp, | |
454 | enable the mode if ARG is omitted or nil. | |
fc2f6a26 | 455 | |
06e21633 CY |
456 | Global Auto Revert mode is a global minor mode that reverts any |
457 | buffer associated with a file when the file changes on disk. Use | |
458 | `auto-revert-mode' to revert a particular buffer. | |
fc2f6a26 GM |
459 | |
460 | If `global-auto-revert-non-file-buffers' is non-nil, this mode | |
461 | may also revert some non-file buffers, as described in the | |
462 | documentation of that variable. It ignores buffers with modes | |
463 | matching `global-auto-revert-ignore-modes', and buffers with a | |
464 | non-nil vale of `global-auto-revert-ignore-buffer'. | |
465 | ||
466 | This function calls the hook `global-auto-revert-mode-hook'. | |
467 | It displays the text that `global-auto-revert-mode-text' | |
468 | specifies in the mode line." | |
0e4f9468 | 469 | :global t :group 'auto-revert :lighter global-auto-revert-mode-text |
4a35aff3 | 470 | (auto-revert-set-timer) |
ed911257 | 471 | (if global-auto-revert-mode |
2a417372 MA |
472 | (let (auto-revert-use-notify) |
473 | (auto-revert-buffers)) | |
ef3544f6 MA |
474 | (dolist (buf (buffer-list)) |
475 | (with-current-buffer buf | |
476 | (when auto-revert-use-notify | |
ed911257 | 477 | (auto-revert-notify-rm-watch)))))) |
4a35aff3 RS |
478 | |
479 | (defun auto-revert-set-timer () | |
0e5dcfd7 | 480 | "Restart or cancel the timer used by Auto-Revert Mode. |
d97c8375 | 481 | If such a timer is active, cancel it. Start a new timer if |
0e5dcfd7 LT |
482 | Global Auto-Revert Mode is active or if Auto-Revert Mode is active |
483 | in some buffer. Restarting the timer ensures that Auto-Revert Mode | |
484 | will use an up-to-date value of `auto-revert-interval'" | |
a2ac68f1 | 485 | (interactive) |
4a35aff3 RS |
486 | (if (timerp auto-revert-timer) |
487 | (cancel-timer auto-revert-timer)) | |
0e4f9468 SM |
488 | (setq auto-revert-timer |
489 | (if (or global-auto-revert-mode auto-revert-buffer-list) | |
490 | (run-with-timer auto-revert-interval | |
491 | auto-revert-interval | |
dddc748b | 492 | 'auto-revert-buffers)))) |
4a35aff3 | 493 | |
ed911257 | 494 | (defun auto-revert-notify-rm-watch () |
ef3544f6 | 495 | "Disable file notification for current buffer's associated file." |
ed911257 | 496 | (when auto-revert-notify-watch-descriptor |
ef3544f6 MA |
497 | (maphash |
498 | (lambda (key value) | |
499 | (when (equal key auto-revert-notify-watch-descriptor) | |
500 | (setq value (delete (current-buffer) value)) | |
501 | (if value | |
502 | (puthash key value auto-revert-notify-watch-descriptor-hash-list) | |
503 | (remhash key auto-revert-notify-watch-descriptor-hash-list) | |
504 | (ignore-errors | |
505 | (funcall (if (fboundp 'inotify-rm-watch) | |
506 | 'inotify-rm-watch 'w32notify-rm-watch) | |
507 | auto-revert-notify-watch-descriptor))))) | |
508 | auto-revert-notify-watch-descriptor-hash-list) | |
68a08a32 | 509 | (remove-hook 'kill-buffer-hook 'auto-revert-notify-rm-watch)) |
ed911257 MA |
510 | (setq auto-revert-notify-watch-descriptor nil |
511 | auto-revert-notify-modified-p nil)) | |
512 | ||
513 | (defun auto-revert-notify-add-watch () | |
ef3544f6 MA |
514 | "Enable file notification for current buffer's associated file." |
515 | (when (string-match auto-revert-notify-exclude-dir-regexp | |
516 | (expand-file-name default-directory)) | |
517 | ;; Fallback to file checks. | |
518 | (set (make-local-variable 'auto-revert-use-notify) nil)) | |
519 | ||
68a08a32 MA |
520 | (when (and buffer-file-name auto-revert-use-notify |
521 | (not auto-revert-notify-watch-descriptor)) | |
ed911257 | 522 | (let ((func (if (fboundp 'inotify-add-watch) |
10e714d5 | 523 | 'inotify-add-watch 'w32notify-add-watch)) |
5d0acd9d | 524 | ;; `attrib' is needed for file modification time. |
ed911257 | 525 | (aspect (if (fboundp 'inotify-add-watch) |
5d0acd9d | 526 | '(attrib create modify moved-to) '(size last-write-time))) |
a7a84eea EZ |
527 | (file (if (fboundp 'inotify-add-watch) |
528 | (directory-file-name (expand-file-name default-directory)) | |
529 | (buffer-file-name)))) | |
ed911257 | 530 | (setq auto-revert-notify-watch-descriptor |
65adfa20 | 531 | (ignore-errors |
a7a84eea | 532 | (funcall func file aspect 'auto-revert-notify-handler))) |
65adfa20 | 533 | (if auto-revert-notify-watch-descriptor |
68a08a32 | 534 | (progn |
ef3544f6 MA |
535 | (puthash |
536 | auto-revert-notify-watch-descriptor | |
537 | (cons (current-buffer) | |
538 | (gethash auto-revert-notify-watch-descriptor | |
539 | auto-revert-notify-watch-descriptor-hash-list)) | |
540 | auto-revert-notify-watch-descriptor-hash-list) | |
68a08a32 MA |
541 | (add-hook (make-local-variable 'kill-buffer-hook) |
542 | 'auto-revert-notify-rm-watch)) | |
65adfa20 MA |
543 | ;; Fallback to file checks. |
544 | (set (make-local-variable 'auto-revert-use-notify) nil))))) | |
545 | ||
546 | (defun auto-revert-notify-event-p (event) | |
ef3544f6 | 547 | "Check that event is a file notification event." |
65adfa20 MA |
548 | (cond ((featurep 'inotify) |
549 | (and (listp event) (= (length event) 4))) | |
550 | ((featurep 'w32notify) | |
551 | (and (listp event) (= (length event) 3) (stringp (nth 2 event)))))) | |
552 | ||
553 | (defun auto-revert-notify-event-descriptor (event) | |
ef3544f6 | 554 | "Return watch descriptor of file notification event, or nil." |
65adfa20 MA |
555 | (and (auto-revert-notify-event-p event) (car event))) |
556 | ||
557 | (defun auto-revert-notify-event-action (event) | |
ef3544f6 | 558 | "Return action of file notification event, or nil." |
65adfa20 MA |
559 | (and (auto-revert-notify-event-p event) (nth 1 event))) |
560 | ||
561 | (defun auto-revert-notify-event-file-name (event) | |
ef3544f6 | 562 | "Return file name of file notification event, or nil." |
65adfa20 MA |
563 | (and (auto-revert-notify-event-p event) |
564 | (cond ((featurep 'inotify) (nth 3 event)) | |
565 | ((featurep 'w32notify) (nth 2 event))))) | |
ed911257 MA |
566 | |
567 | (defun auto-revert-notify-handler (event) | |
ef3544f6 | 568 | "Handle an event returned from file notification." |
65adfa20 MA |
569 | (when (auto-revert-notify-event-p event) |
570 | (let* ((descriptor (auto-revert-notify-event-descriptor event)) | |
571 | (action (auto-revert-notify-event-action event)) | |
572 | (file (auto-revert-notify-event-file-name event)) | |
ef3544f6 MA |
573 | (buffers (gethash descriptor |
574 | auto-revert-notify-watch-descriptor-hash-list))) | |
65adfa20 | 575 | (ignore-errors |
c88be996 MA |
576 | ;; Check, that event is meant for us. |
577 | ;; TODO: Filter events which stop watching, like `move' or `removed'. | |
96c421bb | 578 | (cl-assert descriptor) |
ef3544f6 | 579 | (when (featurep 'inotify) |
5d0acd9d MA |
580 | (cl-assert (or (memq 'attrib action) |
581 | (memq 'create action) | |
ef3544f6 MA |
582 | (memq 'modify action) |
583 | (memq 'moved-to action)))) | |
86fbb162 | 584 | (when (featurep 'w32notify) (cl-assert (eq 'modified action))) |
ef3544f6 MA |
585 | ;; Since we watch a directory, a file name must be returned. |
586 | (cl-assert (stringp file)) | |
587 | (dolist (buffer buffers) | |
588 | (when (buffer-live-p buffer) | |
589 | (with-current-buffer buffer | |
590 | (when (and (stringp buffer-file-name) | |
591 | (string-equal | |
592 | (file-name-nondirectory file) | |
593 | (file-name-nondirectory buffer-file-name))) | |
594 | ;; Mark buffer modified. | |
595 | (setq auto-revert-notify-modified-p t) | |
596 | ;; No need to check other buffers. | |
597 | (cl-return))))))))) | |
ed911257 | 598 | |
ed35db71 EZ |
599 | (defun auto-revert-active-p () |
600 | "Check if auto-revert is active (in current buffer or globally)." | |
601 | (or auto-revert-mode | |
dddc748b | 602 | auto-revert-tail-mode |
ed35db71 EZ |
603 | (and |
604 | global-auto-revert-mode | |
605 | (not global-auto-revert-ignore-buffer) | |
606 | (not (memq major-mode | |
607 | global-auto-revert-ignore-modes))))) | |
608 | ||
ed35db71 | 609 | (defun auto-revert-handler () |
0e5dcfd7 LT |
610 | "Revert current buffer, if appropriate. |
611 | This is an internal function used by Auto-Revert Mode." | |
dddc748b | 612 | (when (or auto-revert-tail-mode (not (buffer-modified-p))) |
fdc31e1d | 613 | (let* ((buffer (current-buffer)) size |
ef3544f6 MA |
614 | ;; Tramp caches the file attributes. Setting |
615 | ;; `remote-file-name-inhibit-cache' forces Tramp to reread | |
616 | ;; the values. | |
617 | (remote-file-name-inhibit-cache t) | |
dddc748b DP |
618 | (revert |
619 | (or (and buffer-file-name | |
ef3544f6 MA |
620 | (or auto-revert-remote-files |
621 | (not (file-remote-p buffer-file-name))) | |
629cb6ec MA |
622 | (or (not auto-revert-use-notify) |
623 | auto-revert-notify-modified-p) | |
fdc31e1d | 624 | (if auto-revert-tail-mode |
629cb6ec | 625 | (and (file-readable-p buffer-file-name) |
ef3544f6 MA |
626 | (/= auto-revert-tail-pos |
627 | (setq size | |
628 | (nth 7 (file-attributes | |
629 | buffer-file-name))))) | |
629cb6ec MA |
630 | (and (file-readable-p buffer-file-name) |
631 | (not (verify-visited-file-modtime buffer))))) | |
2d677766 | 632 | (and (or auto-revert-mode |
dddc748b DP |
633 | global-auto-revert-non-file-buffers) |
634 | revert-buffer-function | |
635 | (boundp 'buffer-stale-function) | |
636 | (functionp buffer-stale-function) | |
637 | (funcall buffer-stale-function t)))) | |
638 | eob eoblist) | |
629cb6ec | 639 | (setq auto-revert-notify-modified-p nil) |
d4411cef | 640 | (when revert |
71c8db4c LT |
641 | (when (and auto-revert-verbose |
642 | (not (eq revert 'fast))) | |
633e0363 | 643 | (message "Reverting buffer `%s'." (buffer-name))) |
1f41bcba LT |
644 | ;; If point (or a window point) is at the end of the buffer, |
645 | ;; we want to keep it at the end after reverting. This allows | |
646 | ;; to tail a file. | |
647 | (when buffer-file-name | |
648 | (setq eob (eobp)) | |
649 | (walk-windows | |
06641a47 JB |
650 | (lambda (window) |
651 | (and (eq (window-buffer window) buffer) | |
652 | (= (window-point window) (point-max)) | |
653 | (push window eoblist))) | |
1f41bcba | 654 | 'no-mini t)) |
dddc748b | 655 | (if auto-revert-tail-mode |
fdc31e1d | 656 | (auto-revert-tail-handler size) |
7ebc19f9 RS |
657 | ;; Bind buffer-read-only in case user has done C-x C-q, |
658 | ;; so as not to forget that. This gives undesirable results | |
659 | ;; when the file's mode changes, but that is less common. | |
90e118ab LT |
660 | (let ((buffer-read-only buffer-read-only)) |
661 | (revert-buffer 'ignore-auto 'dont-ask 'preserve-modes))) | |
1f41bcba LT |
662 | (when buffer-file-name |
663 | (when eob (goto-char (point-max))) | |
664 | (dolist (window eoblist) | |
665 | (set-window-point window (point-max))))) | |
71c8db4c LT |
666 | ;; `preserve-modes' avoids changing the (minor) modes. But we |
667 | ;; do want to reset the mode for VC, so we do it manually. | |
668 | (when (or revert auto-revert-check-vc-info) | |
669 | (vc-find-file-hook))))) | |
ed35db71 | 670 | |
3eedbc85 | 671 | (defun auto-revert-tail-handler (size) |
fdc31e1d | 672 | (let ((modified (buffer-modified-p)) |
ddd7c238 | 673 | (inhibit-read-only t) ; Ignore. |
dddc748b | 674 | (file buffer-file-name) |
ddd7c238 | 675 | (buffer-file-name nil)) ; Ignore that file has changed. |
fdc31e1d | 676 | (when (/= auto-revert-tail-pos size) |
ddd7c238 | 677 | (run-hooks 'before-revert-hook) |
d918508e | 678 | (undo-boundary) |
dddc748b DP |
679 | (save-restriction |
680 | (widen) | |
681 | (save-excursion | |
682 | (goto-char (point-max)) | |
fdc31e1d DK |
683 | (insert-file-contents file nil |
684 | (and (< auto-revert-tail-pos size) | |
685 | auto-revert-tail-pos) | |
686 | size))) | |
ddd7c238 | 687 | (run-hooks 'after-revert-hook) |
d918508e | 688 | (undo-boundary) |
dddc748b | 689 | (setq auto-revert-tail-pos size) |
ddd7c238 | 690 | (restore-buffer-modified-p modified))) |
dddc748b DP |
691 | (set-visited-file-modtime)) |
692 | ||
4a35aff3 RS |
693 | (defun auto-revert-buffers () |
694 | "Revert buffers as specified by Auto-Revert and Global Auto-Revert Mode. | |
695 | ||
696 | Should `global-auto-revert-mode' be active all file buffers are checked. | |
697 | ||
698 | Should `auto-revert-mode' be active in some buffers, those buffers | |
699 | are checked. | |
700 | ||
0e5dcfd7 LT |
701 | Non-file buffers that have a custom `revert-buffer-function' and |
702 | a `buffer-stale-function' are reverted either when Auto-Revert | |
703 | Mode is active in that buffer, or when the variable | |
704 | `global-auto-revert-non-file-buffers' is non-nil and Global | |
705 | Auto-Revert Mode is active. | |
4a35aff3 | 706 | |
48764ae2 | 707 | This function stops whenever there is user input. The buffers not |
4a35aff3 RS |
708 | checked are stored in the variable `auto-revert-remaining-buffers'. |
709 | ||
710 | To avoid starvation, the buffers in `auto-revert-remaining-buffers' | |
711 | are checked first the next time this function is called. | |
712 | ||
48764ae2 | 713 | This function is also responsible for removing buffers no longer in |
4a35aff3 RS |
714 | Auto-Revert mode from `auto-revert-buffer-list', and for canceling |
715 | the timer when no buffers need to be checked." | |
33512cbe LT |
716 | (save-match-data |
717 | (let ((bufs (if global-auto-revert-mode | |
718 | (buffer-list) | |
719 | auto-revert-buffer-list)) | |
720 | (remaining ()) | |
721 | (new ())) | |
722 | ;; Partition `bufs' into two halves depending on whether or not | |
723 | ;; the buffers are in `auto-revert-remaining-buffers'. The two | |
724 | ;; halves are then re-joined with the "remaining" buffers at the | |
725 | ;; head of the list. | |
726 | (dolist (buf auto-revert-remaining-buffers) | |
727 | (if (memq buf bufs) | |
728 | (push buf remaining))) | |
729 | (dolist (buf bufs) | |
730 | (if (not (memq buf remaining)) | |
731 | (push buf new))) | |
732 | (setq bufs (nreverse (nconc new remaining))) | |
733 | (while (and bufs | |
734 | (not (and auto-revert-stop-on-user-input | |
735 | (input-pending-p)))) | |
736 | (let ((buf (car bufs))) | |
aa657fbf | 737 | (if (buffer-live-p buf) |
33512cbe LT |
738 | (with-current-buffer buf |
739 | ;; Test if someone has turned off Auto-Revert Mode in a | |
740 | ;; non-standard way, for example by changing major mode. | |
741 | (if (and (not auto-revert-mode) | |
742 | (not auto-revert-tail-mode) | |
743 | (memq buf auto-revert-buffer-list)) | |
744 | (setq auto-revert-buffer-list | |
745 | (delq buf auto-revert-buffer-list))) | |
ed911257 | 746 | (when (auto-revert-active-p) |
ef3544f6 | 747 | ;; Enable file notification. |
a778dd57 | 748 | (when (and auto-revert-use-notify buffer-file-name |
ef3544f6 MA |
749 | (not auto-revert-notify-watch-descriptor)) |
750 | (auto-revert-notify-add-watch)) | |
ed911257 | 751 | (auto-revert-handler))) |
33512cbe LT |
752 | ;; Remove dead buffer from `auto-revert-buffer-list'. |
753 | (setq auto-revert-buffer-list | |
754 | (delq buf auto-revert-buffer-list)))) | |
755 | (setq bufs (cdr bufs))) | |
756 | (setq auto-revert-remaining-buffers bufs) | |
757 | ;; Check if we should cancel the timer. | |
758 | (when (and (not global-auto-revert-mode) | |
759 | (null auto-revert-buffer-list)) | |
760 | (cancel-timer auto-revert-timer) | |
761 | (setq auto-revert-timer nil))))) | |
4a35aff3 RS |
762 | |
763 | ||
764 | ;; The end: | |
4a35aff3 RS |
765 | (provide 'autorevert) |
766 | ||
767 | (run-hooks 'auto-revert-load-hook) | |
768 | ||
e8af40ee | 769 | ;;; autorevert.el ends here |