+(defun auto-revert-notify-rm-watch ()
+ "Disable file notification for current buffer's associated file."
+ (when auto-revert-notify-watch-descriptor
+ (maphash
+ (lambda (key value)
+ (when (equal key auto-revert-notify-watch-descriptor)
+ (setq value (delete (current-buffer) value))
+ (if value
+ (puthash key value auto-revert-notify-watch-descriptor-hash-list)
+ (remhash key auto-revert-notify-watch-descriptor-hash-list)
+ (ignore-errors
+ (file-notify-rm-watch auto-revert-notify-watch-descriptor)))))
+ auto-revert-notify-watch-descriptor-hash-list)
+ (remove-hook 'kill-buffer-hook 'auto-revert-notify-rm-watch))
+ (setq auto-revert-notify-watch-descriptor nil
+ auto-revert-notify-modified-p nil))
+
+(defun auto-revert-notify-add-watch ()
+ "Enable file notification for current buffer's associated file."
+ ;; We can assume that `buffer-file-name' and
+ ;; `auto-revert-use-notify' are non-nil.
+ (when (or (string-match auto-revert-notify-exclude-dir-regexp
+ (expand-file-name default-directory))
+ (file-symlink-p buffer-file-name))
+ ;; Fallback to file checks.
+ (set (make-local-variable 'auto-revert-use-notify) nil))
+
+ (when (not auto-revert-notify-watch-descriptor)
+ (setq auto-revert-notify-watch-descriptor
+ (ignore-errors
+ (file-notify-add-watch
+ (expand-file-name buffer-file-name default-directory)
+ '(change attribute-change) 'auto-revert-notify-handler)))
+ (if auto-revert-notify-watch-descriptor
+ (progn
+ (puthash
+ auto-revert-notify-watch-descriptor
+ (cons (current-buffer)
+ (gethash auto-revert-notify-watch-descriptor
+ auto-revert-notify-watch-descriptor-hash-list))
+ auto-revert-notify-watch-descriptor-hash-list)
+ (add-hook (make-local-variable 'kill-buffer-hook)
+ 'auto-revert-notify-rm-watch))
+ ;; Fallback to file checks.
+ (set (make-local-variable 'auto-revert-use-notify) nil))))
+
+(defun auto-revert-notify-handler (event)
+ "Handle an EVENT returned from file notification."
+ (with-demoted-errors
+ (let* ((descriptor (car event))
+ (action (nth 1 event))
+ (file (nth 2 event))
+ (file1 (nth 3 event)) ;; Target of `renamed'.
+ (buffers (gethash descriptor
+ auto-revert-notify-watch-descriptor-hash-list)))
+ ;; Check, that event is meant for us.
+ (cl-assert descriptor)
+ ;; We do not handle `deleted', because nothing has to be refreshed.
+ (unless (eq action 'deleted)
+ (cl-assert (memq action '(attribute-changed changed created renamed))
+ t)
+ ;; Since we watch a directory, a file name must be returned.
+ (cl-assert (stringp file))
+ (when (eq action 'renamed) (cl-assert (stringp file1)))
+ ;; Loop over all buffers, in order to find the intended one.
+ (cl-dolist (buffer buffers)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (when (and (stringp buffer-file-name)
+ (or
+ (and (memq action '(attribute-changed changed
+ created))
+ (string-equal
+ (file-name-nondirectory file)
+ (file-name-nondirectory buffer-file-name)))
+ (and (eq action 'renamed)
+ (string-equal
+ (file-name-nondirectory file1)
+ (file-name-nondirectory buffer-file-name)))))
+ ;; Mark buffer modified.
+ (setq auto-revert-notify-modified-p t)
+ ;; No need to check other buffers.
+ (cl-return)))))))))
+