Search code examples
emacselisp

Emacs Lisp, how to monitor changes of a file/directory


I'm looking for a way to check periodically if a files under a certain directory were changed from the last check (a functionality symilar to FAM daemon or to gio.monitor_directory). In emacs lisp.

  • Are there any library/snippet that provide this functionality?
  • If not, how can I implement such a function?

Solution

  • (defun install-monitor (file secs)
      (run-with-timer
       0 secs
       (lambda (f p)
         (unless (< p (second (time-since (elt (file-attributes f) 5))))
           (message "File %s changed!" f)))
       file secs))
    
    (defvar monitor-timer (install-monitor "/tmp" 5)
      "Check if /tmp is changed every 5s.")
    

    To cancel,

    (cancel-timer monitor-timer)
    

    Edit:

    As mentioned by mankoff, the above code snippet monitors file modification in the last 5 seconds, instead of since last check. To achieve the latter, we will need to save the attributes each time we do the checking. Hope this works:

    (defvar monitor-attributes nil
      "Cached file attributes to be monitored.")
    
    (defun install-monitor (file secs)
      (run-with-timer
       0 secs
       (lambda (f p)
         (let ((att (file-attributes f)))
           (unless (or (null monitor-attributes) (equalp monitor-attributes att))
             (message "File %s changed!" f))
           (setq monitor-attributes att)))
       file secs))
    
    (defvar monitor-timer (install-monitor "/tmp" 5)
      "Check if /tmp is changed every 5s.")