How can I show if a file has changed on disk, in the mode-line?
(I'm trying to troubleshoot why auto-revert doesn't work for me, and such an indication would help.)
Your question are actually two questions asked:
From what you provide as additional information:
I'm trying to troubleshoot why auto-revert doesn't work for me, and such an indication would help.
I conclude that the more important one and your actual question is:
How can I show if a file has changed on disk
One part required to arrive at a solution was already given in the comment to your question by Phil Hudson mentioning verify-visited-file-modtime
. The missing part was how to run this function periodically and give a visual feedback if a file was modified by an external application.
The code below if placed in the initialization file does what you ask for:
(defun check-external-file-modification ()
(if (verify-visited-file-modtime)
nil
(message "%s" "Info: BUFFER changed by external application")
)
(run-with-timer 5 nil 'check-external-file-modification)
)
(check-external-file-modification)
Notice that the value 5
in the code above means that the check is done each 5 seconds, but you can change it also to any (also a floating point) other value.
The notification about changed file status is shown each 5 seconds in the minibuffer and mirrored in *Messages*
.
Your other question:
is worth another question if the code you have written yourself for this purpose and for your specific Mode Line layout should for some reason not work as expected.
This is my different implementation of auto-revert
just wrapping revert-buffer
with change detection using file-attributes
that is provided only to retrieve file information, instead of verify-visited-file-modtime
used by the original auto-revert
.
I haven't tested this much, but if you don't mind, try using this to find out if the cause is auto-revert
or other environmental factors, HTH.
(setq-default my-file-attributes-table (make-hash-table)) ;; global hash table to store file attributes at visiting and saving.
;; to store file attributes.
(defun my-update-file-attributes (&optional buffer)
(let ((buf (or buffer (current-buffer))))
(puthash buf
(file-attributes (buffer-file-name buf)) ;; using `file-attributes` to get file info more directly than `verify-visited-file-modtime`
my-file-attributes-table)))
(add-hook 'find-file-hook 'my-update-file-attributes) ;; update at visiting.
(add-hook 'after-save-hook 'my-update-file-attributes) ;; update at saving.
;; to read modified date field in `file-attributes`
(defun my-read-modified-time (attributes)
(current-time-string (nth 5 attributes))) ;; the 5th element is "The time of last modification as a Lisp timestamp (file-attribute-modification-time). This is the last time when the file’s contents were modified." (ref: 26.6.4 File Attributes)
;; to check file difference and prompt `revert-file`
(defun my-check-files-diff ()
(maphash
(lambda (buf attrs)
(unless (string= (my-read-modified-time attrs) (my-read-modified-time (file-attributes (buffer-file-name buf))))
(switch-to-buffer buf)
(revert-buffer) ;; prompt
(my-update-file-attributes buf))) ;; update to prevent from asking again after canceling revert.
my-file-attributes-table))
(setq-default my-check-files-diff-interval 5) ;; check interval seconds.
(run-with-timer my-check-files-diff-interval my-check-files-diff-interval 'my-check-files-diff)
verify-visited-file-modtime
as part of whatever solution you end up using.