emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master dbdc459: File notifications: Support renaming over


From: Michael Albinus
Subject: [Emacs-diffs] master dbdc459: File notifications: Support renaming over directory boundaries
Date: Sun, 06 Sep 2015 12:22:07 +0000

branch: master
commit dbdc459a48091f5953faf14bcaaa7e6d37fbf024
Author: Michael Albinus <address@hidden>
Commit: Michael Albinus <address@hidden>

    File notifications: Support renaming over directory boundaries
    
    * lisp/filenotify.el (file-notify-handle-event):
    (file-notify--pending-event): Adapt docstring.
    (file-notify--descriptor, file-notify-callback): Reimplement in
    order to support renaming over directory boundaries.
    (file-notify-add-watch): Adapt `file-notify--descriptor' call.
    
    * doc/lispref/os.texi (File Notifications): Remove limitation of
    file renaming to the same directory.
---
 doc/lispref/os.texi |   22 +---------
 lisp/filenotify.el  |  114 ++++++++++++++++++++++++---------------------------
 2 files changed, 56 insertions(+), 80 deletions(-)

diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 8d7177d..f7d4117 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -2675,32 +2675,14 @@ being reported.  For example:
 @end example
 
 Whether the action @code{renamed} is returned, depends on the used
-watch library.  It can be expected, when a directory is watched, and
-both @var{file} and @var{file1} belong to this directory.  Otherwise,
-the actions @code{deleted} and @code{created} could be returned in a
-random order.
+watch library.  Otherwise, the actions @code{deleted} and
address@hidden could be returned in a random order.
 
 @example
 @group
 (rename-file "/tmp/foo" "/tmp/bla")
      @result{} Event (35025468 renamed "/tmp/foo" "/tmp/bla")
 @end group
-
address@hidden
-(file-notify-add-watch
-  "/var/tmp" '(change attribute-change) 'my-notify-callback)
-     @result{} 35025504
address@hidden group
-
address@hidden
-(rename-file "/tmp/bla" "/var/tmp/bla")
-     @result{} ;; gfilenotify
-        Event (35025468 renamed "/tmp/bla" "/var/tmp/bla")
-
-     @result{} ;; inotify
-        Event (35025504 created "/var/tmp/bla")
-        Event (35025468 deleted "/tmp/bla")
address@hidden group
 @end example
 @end defun
 
diff --git a/lisp/filenotify.el b/lisp/filenotify.el
index c94f631..5822cf0 100644
--- a/lisp/filenotify.el
+++ b/lisp/filenotify.el
@@ -54,7 +54,7 @@ different files from the same directory are watched.")
   "Handle file system monitoring event.
 If EVENT is a filewatch event, call its callback.  It has the format
 
-  \(file-notify (DESCRIPTOR ACTIONS FILE COOKIE) CALLBACK)
+  \(file-notify (DESCRIPTOR ACTIONS FILE [FILE1-OR-COOKIE]) CALLBACK)
 
 Otherwise, signal a `file-notify-error'."
   (interactive "e")
@@ -64,10 +64,10 @@ Otherwise, signal a `file-notify-error'."
     (signal 'file-notify-error
            (cons "Not a valid file-notify event" event))))
 
-(defvar file-notify--pending-events nil
-  "List of pending file notification events for a future `renamed' action.
-The entries are a list (DESCRIPTOR ACTION FILE COOKIE).  ACTION
-is either `moved-from' or `renamed-from'.")
+;; Needed for `inotify' and `w32notify'.  In the latter case, COOKIE is nil.
+(defvar file-notify--pending-event nil
+  "A pending file notification events for a future `renamed' action.
+It is a form ((DESCRIPTOR ACTION FILE [FILE1-OR-COOKIE]) CALLBACK).")
 
 (defun file-notify--event-file-name (event)
   "Return file name of file notification event, or nil."
@@ -92,26 +92,26 @@ This is available in case a file has been moved."
 ;; `inotify' returns the same descriptor when the file (directory)
 ;; uses the same inode.  We want to distinguish, and apply a virtual
 ;; descriptor which make the difference.
-(defun file-notify--descriptor (descriptor file)
+(defun file-notify--descriptor (descriptor)
   "Return the descriptor to be used in `file-notify-*-watch'.
 For `gfilenotify' and `w32notify' it is the same descriptor as
 used in the low-level file notification package."
   (if (and (natnump descriptor) (eq file-notify--library 'inotify))
-      (cons descriptor file)
+      (cons descriptor
+            (car (cadr (gethash descriptor file-notify-descriptors))))
     descriptor))
 
 ;; The callback function used to map between specific flags of the
 ;; respective file notifications, and the ones we return.
 (defun file-notify-callback (event)
   "Handle an EVENT returned from file notification.
-EVENT is the cdr of the event in `file-notify-handle-event'
-\(DESCRIPTOR ACTIONS FILE COOKIE)."
+EVENT is the cadr of the event in `file-notify-handle-event'
+\(DESCRIPTOR ACTIONS FILE [FILE1-OR-COOKIE])."
   (let* ((desc (car event))
         (registered (gethash desc file-notify-descriptors))
-        (pending-event (assoc desc file-notify--pending-events))
         (actions (nth 1 event))
         (file (file-notify--event-file-name event))
-        file1 callback)
+        file1 callback pending-event)
 
     ;; Make actions a list.
     (unless (consp actions) (setq actions (cons actions nil)))
@@ -129,22 +129,23 @@ EVENT is the cdr of the event in 
`file-notify-handle-event'
       (dolist (action actions)
 
        ;; Send pending event, if it doesn't match.
-       (when (and pending-event
+       (when (and file-notify--pending-event
                   ;; The cookie doesn't match.
-                  (not (eq (file-notify--event-cookie pending-event)
+                  (not (eq (file-notify--event-cookie
+                             (car file-notify--pending-event))
                            (file-notify--event-cookie event)))
                   (or
                    ;; inotify.
-                   (and (eq (nth 1 pending-event) 'moved-from)
+                   (and (eq (nth 1 (car file-notify--pending-event))
+                             'moved-from)
                         (not (eq action 'moved-to)))
                    ;; w32notify.
-                   (and (eq (nth 1 pending-event) 'renamed-from)
+                   (and (eq (nth 1 (car file-notify--pending-event))
+                             'renamed-from)
                         (not (eq action 'renamed-to)))))
-         (funcall callback
-                  (list desc 'deleted
-                        (file-notify--event-file-name pending-event)))
-         (setq file-notify--pending-events
-               (delete pending-event file-notify--pending-events)))
+          (setq pending-event file-notify--pending-event
+                file-notify--pending-event nil)
+          (setcar (cdar pending-event) 'deleted))
 
        ;; Map action.  We ignore all events which cannot be mapped.
        (setq action
@@ -156,46 +157,42 @@ EVENT is the cdr of the event in 
`file-notify-handle-event'
                (setq file1 (file-notify--event-file1-name event))
                'renamed)
 
-              ;; inotify.
+              ;; inotify, w32notify.
               ((eq action 'attrib) 'attribute-changed)
-              ((eq action 'create) 'created)
-              ((eq action 'modify) 'changed)
-              ((memq action '(delete 'delete-self move-self)) 'deleted)
+              ((memq action '(create added)) 'created)
+              ((memq action '(modify modified)) 'changed)
+              ((memq action '(delete 'delete-self move-self removed)) 'deleted)
               ;; Make the event pending.
-              ((eq action 'moved-from)
-               (add-to-list 'file-notify--pending-events
-                            (list desc action file
-                                  (file-notify--event-cookie event)))
+              ((memq action '(moved-from renamed-from))
+               (setq file-notify--pending-event
+                      `((,desc ,action ,file ,(file-notify--event-cookie 
event))
+                        ,callback))
                nil)
               ;; Look for pending event.
-              ((eq action 'moved-to)
-               (if (null pending-event)
+              ((memq action '(moved-to renamed-to))
+               (if (null file-notify--pending-event)
                    'created
                  (setq file1 file
-                       file (file-notify--event-file-name pending-event)
-                       file-notify--pending-events
-                       (delete pending-event file-notify--pending-events))
-                 'renamed))
-
-              ;; w32notify.
-              ((eq action 'added) 'created)
-              ((eq action 'modified) 'changed)
-              ((eq action 'removed) 'deleted)
-              ;; Make the event pending.
-              ((eq action 'renamed-from)
-               (add-to-list 'file-notify--pending-events
-                            (list desc action file
-                                  (file-notify--event-cookie event)))
-               nil)
-              ;; Look for pending event.
-              ((eq action 'renamed-to)
-               (if (null pending-event)
-                   'created
-                 (setq file1 file
-                       file (file-notify--event-file-name pending-event)
-                       file-notify--pending-events
-                       (delete pending-event file-notify--pending-events))
-                 'renamed))))
+                       file (file-notify--event-file-name
+                              (car file-notify--pending-event)))
+                  ;; If the source is handled by another watch, we
+                  ;; must fire the rename event there as well.
+                  (when (not (eq (file-notify--descriptor desc)
+                                 (file-notify--descriptor
+                                  (caar file-notify--pending-event))))
+                    (setq pending-event
+                          `((,(caar file-notify--pending-event)
+                             renamed ,file ,file1)
+                            ,(cadr file-notify--pending-event))))
+                  (setq file-notify--pending-event nil)
+                  'renamed))))
+
+        ;; Apply pending callback.
+        (when pending-event
+          (setcar
+           (car pending-event) (file-notify--descriptor (caar pending-event)))
+          (funcall (cadr pending-event) (car pending-event))
+          (setq pending-event nil))
 
        ;; Apply callback.
        (when (and action
@@ -213,12 +210,10 @@ EVENT is the cdr of the event in 
`file-notify-handle-event'
          (if file1
              (funcall
               callback
-              `(,(file-notify--descriptor desc (nth 0 entry))
-                ,action ,file ,file1))
+              `(,(file-notify--descriptor desc) ,action ,file ,file1))
            (funcall
             callback
-            `(,(file-notify--descriptor desc (nth 0 entry))
-              ,action ,file))))))))
+            `(,(file-notify--descriptor desc) ,action ,file))))))))
 
 ;; `gfilenotify' and `w32notify' return a unique descriptor for every
 ;; `file-notify-add-watch', while `inotify' returns a unique
@@ -325,8 +320,7 @@ FILE is the name of the file whose event is being reported."
      file-notify-descriptors)
 
     ;; Return descriptor.
-    (file-notify--descriptor
-     desc (unless (file-directory-p file) (file-name-nondirectory file)))))
+    (file-notify--descriptor desc)))
 
 (defun file-notify-rm-watch (descriptor)
   "Remove an existing watch specified by its DESCRIPTOR.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]