Eugene Burmako
Eugene Burmako

Reputation: 13048

Emacs - notify when a file has been modified externally

How do I make emacs notify me about the fact that one or more visited files are changed from elsewhere? Here's how this functionality is implemented in Gedit:

gedit - notify about external changes

I've taken a look at the approaches explained in the "Revert Buffer" document at EmacsWiki and found sort of a workaround (modified a bit for my personal preference):

(global-set-key (kbd "<f5>") (lambda ()
  (interactive)
  (if (string= (buffer-name) ecb-directories-buffer-name)
    (refresh-ecb)
    (if (buffer-modified-p)
      (revert-buffer) ; ask for confirmation
      (revert-buffer t t))))) ; don't ask for confirmation - it's unnecessary, since the buffer hasn't been modified

That's great, but what I would like is to have an automatic solution. Maybe, some kind of noisy message inlined in a buffer (like in the screenshot). Maybe, even a modal dialog as implemented in Visual Studio (that's annoying, but it does the trick, after all). What would be your suggestions?

Upvotes: 5

Views: 2947

Answers (2)

Eugene Burmako
Eugene Burmako

Reputation: 13048

Here's what I've been able to come up with - big thanks to the guys from EmacsWiki for hints. I created a callback that gets triggered every few seconds - it checks modtime and displays an annoying message if the file has been modified.

On the upside, the solution mostly works and notifies me about changes regardless of whether the buffer is modified or not. On the downside, it involves constant polling of current file for modtime, but my work scenarios can tolerate that.

emacs notify external changes

;(global-auto-revert-mode 1)
(defun ask-user-about-supersession-threat (fn) "blatantly ignore files that changed on disk")
(run-with-timer 0 2 'my-check-external-modifications)
(add-hook 'after-save-hook 'my-check-external-modifications)
(add-hook 'after-revert-hook 'my-check-external-modifications)

(defun my-load-external-modifications ()
  (interactive)
  (if (string= (buffer-name) ecb-directories-buffer-name)
    (refresh-ecb)
    (if (buffer-modified-p)
      (revert-buffer) ; ask for confirmation
      (revert-buffer t t)) ; don't ask for confirmation - it's unnecessary, since the buffer hasn't been modified
    (my-check-external-modifications))) 

(defun my-overwrite-external-modifications ()
  (interactive)
  (clear-visited-file-modtime)
  (set-buffer-modified-p (current-buffer))
  (save-buffer)
  (my-check-external-modifications))

(defun my-check-external-modifications ()
  (if (verify-visited-file-modtime (current-buffer))
    (progn
      (global-set-key (kbd "<f5>") 'my-load-external-modifications)
      (global-set-key (kbd "C-s") 'save-buffer)
      (setq header-line-format tabbar-header-line-format))
    (progn
      (global-set-key (kbd "<f5>") 'my-load-external-modifications)
      (global-set-key (kbd "C-s") 'my-overwrite-external-modifications)
      (setq header-line-format (format "%s. Press F5 to load external changes, C-s to overwrite them"
        (propertize "This file has been changed externally" 'face '(:foreground "#f00")))))))

Upvotes: 4

Tom
Tom

Reputation: 7586

If you want the warning for dirty buffers too then you could advise switch-to-buffer, so when you switch to a buffer and it's modified then it would check if the file is modified and if so then it could offer to revert it like the built-in check does in case of unmodified buffers.

Upvotes: 2

Related Questions