]> git.eshelyaron.com Git - emacs.git/commitdiff
* ediff-init.el: comments.
authorMichael Kifer <kifer@cs.stonybrook.edu>
Tue, 5 Mar 2002 05:34:19 +0000 (05:34 +0000)
committerMichael Kifer <kifer@cs.stonybrook.edu>
Tue, 5 Mar 2002 05:34:19 +0000 (05:34 +0000)
* ediff-hook.el: Got rid of autoloads. Not needed, since the hook
is loaded.

* ediff-mult.el (ediff-intersect-directories,
ediff-prepare-meta-buffer,ediff-get-directory-files-under-revision):
cleanup.
(ediff-draw-dir-diffs): now supports the "C" command in directory
difference buffer.
(ediff-dir-diff-copy-file): new function that implements copying
of files from one Ediff dir to another
(ediff-bury-dir-diffs-buffer): kills the buffer instead.
(ediff-append-custom-diff): better error msgs.

* ediff-util.el (ediff-compute-custom-diffs-maybe): buglet fix.
(ediff-inferior-compare-regions): Use
ediff-clone-buffer-for-region-comparison. Better and simpler interface.

* ediff.el (ediff-directories-internal): Cleanup.
(ediff-clone-buffer-for-region-comparison): Better interface.

lisp/ChangeLog
lisp/ediff-init.el
lisp/ediff-mult.el
lisp/ediff-util.el
lisp/ediff.el

index 59a852f20575af0eda21d583ed904daa7e80fcd7..899d1a9fffaa0089d3345b8efa39795b74f0f8db 100644 (file)
@@ -1,3 +1,27 @@
+2002-03-05  Michael Kifer  <kifer@cs.stonybrook.edu>
+       
+       * ediff-init.el: comments.
+       
+       * ediff-hook.el: Got rid of autoloads. Not needed, since the hook
+       is loaded.
+       
+       * ediff-mult.el (ediff-intersect-directories,
+       ediff-prepare-meta-buffer,ediff-get-directory-files-under-revision):
+       cleanup.
+       (ediff-draw-dir-diffs): now supports the "C" command in directory
+       difference buffer.
+       (ediff-dir-diff-copy-file): new function that implements copying
+       of files from one Ediff dir to another
+       (ediff-bury-dir-diffs-buffer): kills the buffer instead.
+       (ediff-append-custom-diff): better error msgs.
+       
+       * ediff-util.el (ediff-compute-custom-diffs-maybe): buglet fix.
+       (ediff-inferior-compare-regions): Use
+       ediff-clone-buffer-for-region-comparison. Better and simpler interface.
+       
+       * ediff.el (ediff-directories-internal): Cleanup.
+       (ediff-clone-buffer-for-region-comparison): Better interface.
+       
 2002-03-04  Richard M. Stallman  <rms@gnu.org>
 
        * emacs-lisp/easy-mmode.el (define-minor-mode): 
index ae6d05ab40a9fb4d8c5562c4d930a7b5da33cd6b..cfa1ce9da7d511d0b9bd281e5ab4ffcbd617f9ab 100644 (file)
@@ -344,12 +344,13 @@ It needs to be killed when we quit the session.")
       (ediff-patch-metajob metajob)
       ;; add more here
       ))
+;; jobs suitable for the operation of collecting diffs into a multifile patch
 (defsubst ediff-collect-diffs-metajob (&optional metajob)
   (memq (or metajob ediff-metajob-name)
        '(ediff-directories
-         ediff-directory-revisions
          ediff-merge-directories
          ediff-merge-directories-with-ancestor
+         ediff-directory-revisions
          ediff-merge-directory-revisions
          ediff-merge-directory-revisions-with-ancestor
          ;; add more here
index b8e576d72b76872ffa68700edcc341b7eedfb6ef..83dde656a15efa363c033f51a19e2d0f243135a2 100644 (file)
 ;;     3. Provide a list of pairs or triples of file names (or buffers,
 ;;        depending on the particular Ediff operation you want to invoke)
 ;;        in the following format:
-;;             (descriptor (obj1 obj2 obj3) (...) ...)
+;;             (descriptor-header (nil nil (obj1 nil) (obj2 nil) (obj3 nil))
+;;                                 (...) ...)
+;;         The function ediff-make-new-meta-list-element can be used to create
+;;         2nd and subsequent elements of that list.
 ;;        Actually, the format of this list is pretty much up to the
 ;;        developer.  The only thing is that it must be a list of lists,
 ;;        and the first list must describe the meta session, and subsequent
 ;;        elements must describe individual sessions.
-;;        This descriptor must be a list of two, three, or four elements (nil
-;;        or string).  The function ediff-redraw-registry-buffer displays the
-;;        second through last of these in the registry buffer. 
+;;        This descriptor-header must be a list of SIX elements (nil or
+;;         string).  The function ediff-redraw-registry-buffer displays the 
+;;        1st - 4th of these in the registry buffer. 
 ;;        Also, keep in mind that the function ediff-prepare-meta-buffer
-;;        (which see) prepends the session group buffer to the descriptor, and
-;;        nil in front of each subsequent list (i.e., the above list 
-;;        will become
-;;              ((meta-buf descriptor) (nil obj1 obj2 obj3) (nil ...) ...)
+;;        (which see) prepends the session group buffer to the descriptor, so
+;;        the descriptor becomes 7-long.
 ;;        Ediff expects that your function (in 2 above) will arrange to
 ;;        replace this prepended nil (via setcar) with the actual ediff
 ;;        control buffer associated with an appropriate Ediff session.
@@ -225,9 +226,14 @@ buffers."
 
 ;;; API for ediff-meta-list
 
+;; A meta-list is either ediff-meta-list, which contains a header and the list
+;; of ediff sessions or ediff-dir-difference-list, which is a header followed
+;; by the list of differences among the directories (i.e., files that are not
+;; in all directories). The header is the same in all meta lists, but the rest
+;; is different.
 ;; Structure of the meta-list:
 ;; (HEADER SESSION1 SESSION2 ...)
-;;    HEADER: (GROUP-BUF REGEXP OBJA OBJB OBJC SAVE-DIR)
+;;    HEADER: (GROUP-BUF REGEXP OBJA OBJB OBJC SAVE-DIR COMPARISON-FUNC)
 ;;               OBJA - first directory
 ;;               OBJB - second directory
 ;;               OBJC - third directory
@@ -247,11 +253,14 @@ buffers."
   (nth 4 (car meta-list)))
 (defsubst ediff-get-group-merge-autostore-dir (meta-list)
   (nth 5 (car meta-list)))
+(defsubst ediff-get-group-comparison-func (meta-list)
+  (nth 6 (car meta-list)))
 
 ;; ELT is a session meta descriptor (what is being preserved as
 ;; 'ediff-meta-info)
 ;;  The structure is:  (SESSION-CTL-BUFFER STATUS OBJA OBJB OBJC)
-;;   STATUS is ?I, ?*, ?H
+;;   STATUS is ?I (hidden or invalid), ?* (marked for operation), ?H (hidden)
+;;             nil (nothing)
 ;;   OBJA/B/C is (FILENAME EQSTATUS)
 ;;     EQSTATUS is ?= or nil (?= means that this file is equal to some other
 ;;                                    file in this session)
@@ -281,6 +290,20 @@ buffers."
 (defsubst ediff-set-file-eqstatus (elt value)
   (setcar (cdr elt) value))
 
+;; Create a new element for the meta list out of obj1/2/3, which usually are
+;; files
+;;
+;; The first nil in such an is later replaced with the session buffer.  The
+;; second nil is reserved for session status.
+;;
+;; Also, session objects A/B/C are turned into lists of the form (obj nil).
+;; This nill is a placeholder for eq-indicator. It is either nil or =.
+;; If it is discovered that this file is = to some other
+;; file in the same session, eq-indicator is changed to `='.
+;; Curently, the eq-indicator is used only for 2 and 3-file jobs.
+(defun ediff-make-new-meta-list-element (obj1 obj2 obj3)
+  (list nil nil (list obj1 nil) (list obj2 nil) (list obj3 nil)))
+
 ;; The activity marker is either or + (active session, i.e., ediff is currently
 ;; run in it), or - (finished session, i.e., we've ran ediff in it and then
 ;; exited).  Return nil, if session is neither active nor finished
@@ -331,6 +354,7 @@ buffers."
   ;; modify ediff-meta-buffer-map here
   (run-hooks 'ediff-meta-buffer-keymap-setup-hook))
 
+
 (defun ediff-meta-mode ()
   "This mode controls all operations on Ediff session groups.
 It is entered through one of the following commands:
@@ -363,6 +387,10 @@ Commands:
 (define-key ediff-dir-diffs-buffer-map "n" 'next-line)
 (define-key ediff-dir-diffs-buffer-map "\C-?" 'previous-line)
 (define-key ediff-dir-diffs-buffer-map "p" 'previous-line)
+(define-key ediff-dir-diffs-buffer-map "C" 'ediff-dir-diff-copy-file)
+(if ediff-emacs-p
+    (define-key ediff-dir-diffs-buffer-map [mouse-2] 'ediff-dir-diff-copy-file)
+  (define-key ediff-dir-diffs-buffer-map [button2] 'ediff-dir-diff-copy-file))
 (define-key ediff-dir-diffs-buffer-map [delete] 'previous-line)
 (define-key ediff-dir-diffs-buffer-map [backspace] 'previous-line)
 
@@ -440,6 +468,16 @@ behavior."
   (ediff-update-meta-buffer (current-buffer) 'must-redraw))
 
 
+;; These are used to encode membership of files in directory1/2/3
+;; Membership code of a file is a product of codes for the directories where
+;; this file is in
+(defvar ediff-membership-code1 2)
+(defvar ediff-membership-code2 3)
+(defvar ediff-membership-code3 5)
+(defvar ediff-product-of-memcodes (* ediff-membership-code1
+                                    ediff-membership-code2
+                                    ediff-membership-code3))
+
 ;; DIR1, DIR2, DIR3 are directories.  DIR3 can be nil.
 ;; OUTPUT-DIR is a directory for auto-storing the results of merge jobs.
 ;;           Can be nil.
@@ -448,21 +486,23 @@ behavior."
 ;; included in the intersection.  However, a regular file that is a dir in dir3
 ;; is included, since dir3 files are supposed to be ancestors for merging.
 ;; Returns a list of the form:
-;;     ((dir1 dir2 dir3) (f1 f2 f3) (f1 f2 f3) ...)
+;;     (DIFF-LIST META-HEADER (f1 f2 f3) (f1 f2 f3) ...)
 ;; dir3, f3 can be nil if intersecting only 2 directories.
 ;; If COMPARISON-FUNC is given, use it.  Otherwise, use string=
-;; DIFF-VAR contains the name of the variable in which to return the
-;; difference list (which represents the differences among the contents of
-;; directories).  The diff list is of the form:
-;;     ((dir1 dir2 dir3) (file . num) (file . num)...)
+;; DIFF-LIST is of the form:
+;;     (META-HEADER (file . num) (file . num)...)
 ;; where num encodes the set of dirs where the file is found:
 ;; 2 - only dir1; 3 - only dir2; 5 - only dir3; 6 - dir1&2; 10 - dir1&3; etc.
+;; META-HEADER is of the form
+;;       It contains the meta info about this ediff operation
+;;       (regexp dir1 dir2 dir3 merge-auto-store-dir comparison-func)
+;;       Later the meta-buffer is prepended to this list.
 (defun ediff-intersect-directories (jobname
-                                   diff-var regexp dir1 dir2
+                                   regexp dir1 dir2
                                    &optional
                                    dir3 merge-autostore-dir comparison-func)
   (setq comparison-func (or comparison-func 'string=))
-  (let (lis1 lis2 lis3 common auxdir1 auxdir2 auxdir3 difflist)
+  (let (lis1 lis2 lis3 common auxdir1 auxdir2 auxdir3 common-part difflist)
 
     (setq auxdir1      (file-name-as-directory dir1)
          lis1          (directory-files auxdir1 nil regexp)
@@ -514,39 +554,56 @@ behavior."
     (setq difflist (mapcar (lambda (elt) (cons elt 1)) difflist))
 
     ;; check for files belonging to lis1/2/3
+    ;; Each elt is of the norm (file . number)
+    ;; Number encodes the directories to which file belongs.
+    ;; It is a product of a subset of ediff-membership-code1=2,
+    ;; ediff-membership-code2=3, and ediff-membership-code3=5.
+    ;; If file belongs to dir 1 only, the membership code is 2.
+    ;; If it is in dir1 and dir3, then the membership code is 2*5=10;
+    ;; if it is in dir1 and dir2, then the membership code is 2*3=6, etc.
     (mapcar (lambda (elt)
              (if (member (car elt) lis1)
-                 (setcdr elt (* (cdr elt) 2)))
+                 (setcdr elt (* (cdr elt) ediff-membership-code1)))
              (if (member (car elt) lis2)
-                 (setcdr elt (* (cdr elt) 3)))
+                 (setcdr elt (* (cdr elt) ediff-membership-code2)))
              (if (member (car elt) lis3)
-                 (setcdr elt (* (cdr elt) 5)))
+                 (setcdr elt (* (cdr elt) ediff-membership-code3)))
              )
            difflist)
-    (setq difflist (cons (list regexp auxdir1 auxdir2 auxdir3) difflist))
+    (setq difflist (cons
+                   ;; diff metalist header
+                   (list regexp
+                         auxdir1 auxdir2 auxdir3
+                         merge-autostore-dir
+                         comparison-func)
+                   difflist))
     
-    ;; return the difference list back to the calling function
-    (set diff-var difflist)
-
+    (setq common-part
+         (cons 
+          ;; metalist header
+          (list regexp
+                auxdir1 auxdir2 auxdir3
+                merge-autostore-dir
+                comparison-func)
+          (mapcar
+           (lambda (elt) 
+             (ediff-make-new-meta-list-element
+              (concat auxdir1 elt)
+              (concat auxdir2 elt)
+              (if lis3
+                  (progn
+                    ;; The following is done because: In merging with
+                    ;; ancestor, we don't intersect with lis3.  So, it is
+                    ;; possible that elt is a file in auxdir1/2 but a
+                    ;; directory in auxdir3 Or elt may not exist in auxdir3 at
+                    ;; all.  In the first case, we add a slash at the end.  In
+                    ;; the second case, we insert nil.
+                    (setq elt (ediff-add-slash-if-directory auxdir3 elt))
+                    (if (file-exists-p (concat auxdir3 elt))
+                        (concat auxdir3 elt))))))
+           common)))
     ;; return result
-    (cons (list regexp auxdir1 auxdir2 auxdir3 merge-autostore-dir)
-         (mapcar
-          (lambda (elt) 
-            (list (concat auxdir1 elt)
-                  (concat auxdir2 elt)
-                  (if lis3
-                      (progn
-                        ;; The following is done because:
-                        ;;   In merging with ancestor, we don't intersect
-                        ;;   with lis3.  So, it is possible that elt is a
-                        ;;   file in auxdir1/2 but a directory in auxdir3
-                        ;;   Or elt may not exist in auxdir3 at all.
-                        ;;   In the first case, we add a slash at the end.
-                        ;;   In the second case, we insert nil.
-                        (setq elt (ediff-add-slash-if-directory auxdir3 elt))
-                        (if (file-exists-p (concat auxdir3 elt))
-                            (concat auxdir3 elt))))))
-          common))
+    (cons common-part difflist)
     ))
 
 ;; find directory files that are under revision.  Include subdirectories, since
@@ -592,9 +649,13 @@ behavior."
     (setq common (sort (ediff-copy-list common) 'string-lessp))
 
     ;; return result
-    (cons (list regexp auxdir1 nil nil merge-autostore-dir)
-         (mapcar (lambda (elt) (list (concat auxdir1 elt) nil nil))
-                 common))
+    (cons 
+     ;; header -- has 6 elements. Meta buffer is prepended later by
+     ;; ediff-prepare-meta-buffer 
+     (list regexp auxdir1 nil nil merge-autostore-dir nil)
+     (mapcar (lambda (elt) (ediff-make-new-meta-list-element
+                           (concat auxdir1 elt) nil nil))
+            common))
     ))
       
 
@@ -657,30 +718,11 @@ behavior."
            ;; meta-buffs.
            (define-key
              ediff-meta-buffer-map "M" 'ediff-show-meta-buff-from-registry))
-       ;; Initialize the meta list -- don't do this for registry.
-       ;;
-       ;; We prepend '(nil nil) to all elts of meta-list, except the first.
-       ;; The first nil will later be replaced by the session buffer.  The
-       ;; second is reserved for session status.
-       ;;
-       ;; (car ediff-meta-list) gets cons'ed with the session group buffer.
-       ;; Also, session objects A/B/C are turned into lists of the form
-       ;; (obj eq-indicator).  Eq-indicator is either nil or =. Initialized to
-       ;; nil.  If later it is discovered that this file is = to some other
-       ;; file in the same session, eq-indicator is changed to `='.
-       ;; For now, the eq-indicator is used only for 2 and 3-file jobs.
+       ;; Initialize the meta list -- we don't do this for registry.
        (setq ediff-meta-list
+             ;; add meta-buffer to the list header
              (cons (cons meta-buffer (car meta-list))
-                   (mapcar
-                    (lambda (elt)
-                      (cons nil
-                            (cons nil
-                                  ;; convert each obj to (obj nil),
-                                  ;; where nil is the initial value
-                                  ;; for eq-indicator -- see above
-                                  (mapcar (lambda (obj) (list obj nil))
-                                          elt))))
-                    (cdr meta-list)))))
+                   (cdr meta-list))))
        
       (or (eq meta-buffer ediff-registry-buffer)
          (setq ediff-session-registry
@@ -1048,52 +1090,46 @@ behavior."
     (if dir3 (insert "*** Directory C: " dir3 "\n"))
     (insert "\n")))
 
-(defun ediff-draw-dir-diffs (diff-list)
+(defun ediff-draw-dir-diffs (diff-list &optional buf-name)
   (if (null diff-list) (error "Lost difference info on these directories"))
-  (let* ((buf-name (ediff-unique-buffer-name
-                   "*Ediff File Group Differences" "*"))
-        (regexp (ediff-get-group-regexp diff-list))
+  (setq buf-name
+       (or buf-name
+           (ediff-unique-buffer-name "*Ediff File Group Differences" "*")))
+  (let* ((regexp (ediff-get-group-regexp diff-list))
         (dir1 (ediff-abbreviate-file-name (ediff-get-group-objA diff-list)))
         (dir2 (ediff-abbreviate-file-name (ediff-get-group-objB diff-list)))
         (dir3 (ediff-get-group-objC diff-list))
         (dir3 (if (stringp dir3) (ediff-abbreviate-file-name dir3)))
         (meta-buf (ediff-get-group-buffer diff-list))
         (underline (make-string 26 ?-))
-        file code 
+        file membership-code saved-point
         buffer-read-only)
     ;; skip the directory part
     (setq diff-list (cdr diff-list))
     (setq ediff-dir-diffs-buffer (get-buffer-create buf-name))
     (ediff-with-current-buffer ediff-dir-diffs-buffer
+      (setq saved-point (point))
       (use-local-map ediff-dir-diffs-buffer-map)
       (erase-buffer)
       (setq ediff-meta-buffer meta-buf)
       (insert "\t\t*** Directory Differences ***\n")
       (insert "
 Useful commands:
-     `q': hide this buffer
-   n,SPC: next line
-   p,DEL: previous line\n\n")
-
+  C,button2: over file name -- copy this file to directory that doesn't have it
+          q: hide this buffer
+      n,SPC: next line
+      p,DEL: previous line\n\n")
+
+      (insert (format "\n*** Directory A: %s\n" dir1))
+      (if dir2 (insert (format "*** Directory B: %s\n" dir2)))
+      (if dir3 (insert (format "*** Directory C: %s\n" dir3)))
       (if (and (stringp regexp) (> (length regexp) 0))
          (insert
-          (format "\n*** Filter-through regular expression: %s\n" regexp)))
+          (format "*** Filter-through regular expression: %s\n" regexp)))
       (insert "\n")
-      (insert (format "\n%-27s%-26s"
-                     (ediff-truncate-string-left
-                      (ediff-abbreviate-file-name
-                       (file-name-as-directory dir1))
-                      25)
-                     (ediff-truncate-string-left
-                      (ediff-abbreviate-file-name
-                       (file-name-as-directory dir2))
-                      25)))
+      (insert (format "\n%-27s%-26s" "Directory A" "Directory B"))
       (if dir3
-         (insert (format " %-25s\n"
-                         (ediff-truncate-string-left
-                          (ediff-abbreviate-file-name
-                           (file-name-as-directory dir3))
-                          25)))
+         (insert (format " %-25s\n" "Directory C"))
        (insert "\n"))
       (insert (format "%s%s" underline underline))
       (if (stringp dir3)
@@ -1105,47 +1141,64 @@ Useful commands:
 
       (while diff-list
        (setq file (car (car diff-list))
-             code (cdr (car diff-list))
+             membership-code (cdr (car diff-list))
              diff-list (cdr diff-list))
-       (if (= (mod code 2) 0) ; dir1
-           (insert (format "%-27s"
-                           (ediff-truncate-string-left
-                            (ediff-abbreviate-file-name
-                             (if (file-directory-p (concat dir1 file))
-                                 (file-name-as-directory file)
-                               file))
-                            24)))
+       (if (= (mod membership-code ediff-membership-code1) 0) ; dir1
+           (let ((beg (point)))
+             (insert (format "%-27s"
+                             (ediff-truncate-string-left
+                              (ediff-abbreviate-file-name
+                               (if (file-directory-p (concat dir1 file))
+                                   (file-name-as-directory file)
+                                 file))
+                              24)))
+             ;; format of meta info in the dir-diff-buffer:
+             ;;    (filename-tail filename-full otherdir1 otherdir2 otherdir3)
+             (ediff-set-meta-overlay
+              beg (point)
+              (list meta-buf file (concat dir1 file) dir1 dir2 dir3)))
          (insert (format "%-27s" "---")))
-       (if (= (mod code 3) 0) ; dir2
-           (insert (format "%-26s"
-                           (ediff-truncate-string-left
-                            (ediff-abbreviate-file-name
-                             (if (file-directory-p (concat dir2 file))
-                                 (file-name-as-directory file)
-                               file))
-                            24)))
+       (if (= (mod membership-code ediff-membership-code2) 0) ; dir2
+           (let ((beg (point)))
+             (insert (format "%-26s"
+                             (ediff-truncate-string-left
+                              (ediff-abbreviate-file-name
+                               (if (file-directory-p (concat dir2 file))
+                                   (file-name-as-directory file)
+                                 file))
+                              24)))
+             (ediff-set-meta-overlay
+              beg (point)
+              (list meta-buf file (concat dir2 file) dir1 dir2 dir3)))
          (insert (format "%-26s" "---")))
        (if (stringp dir3)
-           (if (= (mod code 5) 0) ; dir3
-               (insert (format " %-25s" 
-                               (ediff-truncate-string-left
-                                (ediff-abbreviate-file-name
-                                 (if (file-directory-p (concat dir3 file))
-                                     (file-name-as-directory file)
-                                   file))
-                                24)))
+           (if (= (mod membership-code ediff-membership-code3) 0) ; dir3
+               (let ((beg (point)))
+                 (insert (format " %-25s" 
+                                 (ediff-truncate-string-left
+                                  (ediff-abbreviate-file-name
+                                   (if (file-directory-p (concat dir3 file))
+                                       (file-name-as-directory file)
+                                     file))
+                                  24)))
+                 (ediff-set-meta-overlay
+                  beg (point)
+                  (list meta-buf file (concat dir3 file) dir1 dir2 dir3)))
              (insert (format " %-25s" "---"))))
        (insert "\n"))
       (setq buffer-read-only t)
-      (set-buffer-modified-p nil)) ; eval in diff buffer
+      (set-buffer-modified-p nil)
+      (goto-char saved-point)) ; end eval in diff buffer
   ))
 
 (defun ediff-bury-dir-diffs-buffer ()
   "Bury the directory difference buffer.  Display the meta buffer instead."
   (interactive)
+  ;; ediff-meta-buffer is set in ediff-draw-dir-diffs so the directory
+  ;; difference buffer remembers the meta buffer
   (let ((buf ediff-meta-buffer)
        wind)
-    (bury-buffer)
+    (ediff-kill-buffer-carefully ediff-dir-diffs-buffer)
     (if (setq wind (ediff-get-visible-buffer-window buf))
        (select-window wind)
       (set-window-buffer (selected-window) buf))))
@@ -1164,6 +1217,70 @@ Useful commands:
     (set-window-buffer (selected-window) buf)
     (goto-char (point-min))))
 
+;; Format of meta info in dir-diff-buffer:
+;;               (filename-tail filename-full otherdir1 otherdir2)
+(defun ediff-dir-diff-copy-file ()
+  "Copy file described at point to directories where this file is missing."
+  (interactive)
+  (let* ((pos (ediff-event-point last-command-event))
+        (info (ediff-get-meta-info (current-buffer) pos 'noerror))
+        (meta-buf (car info))
+        (file-tail (nth 1 info))
+        (file-abs  (nth 2 info))
+        (otherdir1 (nth 3 info))
+        (otherfile1 (if otherdir1 (concat otherdir1 file-tail)))
+        (otherdir2 (nth 4 info))
+        (otherfile2 (if otherdir2 (concat otherdir2 file-tail)))
+        (otherdir3 (nth 5 info))
+        (otherfile3 (if otherdir3 (concat otherdir3 file-tail)))
+        meta-list dir-diff-list
+        )
+    (if (null info)
+       (error "No file suitable for copying described at this location"))
+    (ediff-with-current-buffer meta-buf
+      (setq meta-list ediff-meta-list
+           dir-diff-list ediff-dir-difference-list))
+
+    ;; copy file to directories where it doesn't exist, update
+    ;; ediff-dir-difference-list and redisplay
+    (mapcar
+     (lambda (otherfile-struct)
+       (let ((otherfile (car otherfile-struct))
+            (file-mem-code (cdr otherfile-struct)))
+        (if otherfile
+            (or (file-exists-p otherfile)
+                (if (y-or-n-p
+                     (format "Copy %s to %s ? " file-abs otherfile))
+                    (let* ((file-diff-record (assoc file-tail dir-diff-list))
+                           (new-mem-code
+                            (* (cdr file-diff-record) file-mem-code)))
+                      (copy-file file-abs otherfile)
+                      (setcdr file-diff-record new-mem-code)
+                      (ediff-draw-dir-diffs dir-diff-list (buffer-name))
+                      (sit-for 0)
+                      ;; if file is in all three dirs or in two dirs and only
+                      ;; two dirs are involved, delete this file's record
+                      (if (or (= new-mem-code ediff-product-of-memcodes)
+                              (and (> new-mem-code ediff-membership-code3)
+                                   (null otherfile3)))
+                          (delq file-diff-record dir-diff-list))
+                      ))))
+        ))
+     ;; 2,3,5 are numbers used to encode membership of a file in
+     ;;       dir1/2/3. See ediff-intersect-directories.
+     (list (cons otherfile1 2) (cons otherfile2 3) (cons otherfile3 5)))
+
+    (if (and (file-exists-p otherfile1)
+            (file-exists-p otherfile2)
+            (or (not otherfile3) (file-exists-p otherfile3)))
+       ;; update ediff-meta-list by direct modification
+       (nconc meta-list
+              (list (ediff-make-new-meta-list-element
+                     otherfile1 otherfile2 otherfile3)))
+      )
+    (ediff-update-meta-buffer meta-buf 'must-redraw)
+  ))
+
 (defun ediff-up-meta-hierarchy ()
   "Go to the parent session group buffer."
   (interactive)
@@ -1404,6 +1521,8 @@ Useful commands:
             (save-excursion
               (setq numMarked (1+ numMarked))
               (funcall operation elt sessionNum)))
+           ;; The following goes into a session represented by a subdirectory
+           ;; and applies operation to marked sessions there
            ((and  (ediff-meta-session-p elt) 
                   (ediff-buffer-live-p 
                    (setq session-buf (ediff-get-session-buffer elt))))
@@ -1420,7 +1539,7 @@ Useful commands:
 
 (defun ediff-append-custom-diff (session sessionNum)
   (or (ediff-collect-diffs-metajob)
-      (error "Hmm, I'd hate to do it to you ..."))
+      (error "Can't compute multifile patch in this context"))
   (let ((session-buf (ediff-get-session-buffer session))
        (meta-diff-buff ediff-meta-diff-buffer)
        (metajob ediff-metajob-name)
@@ -1433,14 +1552,17 @@ Useful commands:
                (setq custom-diff-buf ediff-custom-diff-buffer)))))
 
     (or (ediff-buffer-live-p meta-diff-buff)
-       (error "Ediff: something wrong--no multiple diffs buffer"))
+       (error "Ediff: something wrong--killed multiple diff's buffer"))
 
     (cond ((ediff-buffer-live-p custom-diff-buf)
+          ;; for live session buffers we do them first because the user may
+          ;; have changed them with respect to the underlying files
           (save-excursion
             (set-buffer meta-diff-buff)
             (goto-char (point-max))
             (insert-buffer custom-diff-buf)
             (insert "\n")))
+         ;; if ediff session is not live, run diff directly on the files
          ((memq metajob '(ediff-directories 
                           ediff-merge-directories
                           ediff-merge-directories-with-ancestor))
@@ -1460,7 +1582,8 @@ Useful commands:
             (insert-buffer tmp-buf)
             (insert "\n")))
          (t
-          (error "Can't make context diff for Session %d" sessionNum )))
+          (ediff-kill-buffer-carefully meta-diff-buff)
+          (error "Session %d compares versions of file. Such session must be active to enable multifile patch collection" sessionNum )))
     ))
 
 (defun ediff-collect-custom-diffs ()
@@ -1475,6 +1598,7 @@ all marked sessions must be active."
            (get-buffer-create
             (ediff-unique-buffer-name "*Ediff Multifile Diffs" "*"))))
   (ediff-with-current-buffer ediff-meta-diff-buffer
+    (setq buffer-read-only nil)
     (erase-buffer))
   (if (> (ediff-operate-on-marked-sessions 'ediff-append-custom-diff) 0)
       ;; did something
index e1dbdc7f336df1cee1cd7bc0fe52b420e6bf8a9b..be9fbb424d3b2b93a037bf353694f228e03b9d14 100644 (file)
@@ -3302,6 +3302,7 @@ Without an argument, it saves customized diff argument, if available
            )
     (save-buffer)))
 
+;; This function operates only from an ediff control buffer
 (defun ediff-compute-custom-diffs-maybe ()
   (let ((buf-A-file-name (buffer-file-name ediff-buffer-A))
        (buf-B-file-name (buffer-file-name ediff-buffer-B))
@@ -3317,6 +3318,9 @@ Without an argument, it saves customized diff argument, if available
        (setq ediff-custom-diff-buffer
              (get-buffer-create
               (ediff-unique-buffer-name "*ediff-custom-diff" "*"))))
+    (ediff-with-current-buffer ediff-custom-diff-buffer
+      (setq buffer-read-only nil)
+      (erase-buffer))
     (ediff-exec-process
      ediff-custom-diff-program ediff-custom-diff-buffer 'synchronize
      ediff-custom-diff-options file-A file-B)
@@ -3373,6 +3377,7 @@ Ediff Control Panel to restore highlighting."
 
     (cond ((ediff-merge-job)
           (setq bufB ediff-buffer-C)
+          ;; ask which buffer to compare to the merge buffer
           (while (cond ((eq answer ?A)
                         (setq bufA ediff-buffer-A
                               possibilities '(?B))
@@ -3387,10 +3392,12 @@ Ediff Control Panel to restore highlighting."
                           (sit-for 2)
                           t))
             (let ((cursor-in-echo-area t))
-              (message "Which buffer to compare to the merge buffer (A/B)? ")
+              (message
+               "Which buffer to compare to the merge buffer (A or B)? ")
               (setq answer (capitalize (read-char-exclusive))))))
 
          ((ediff-3way-comparison-job)
+          ;; ask which two buffers to compare
           (while (cond ((memq answer possibilities)
                         (setq possibilities (delq answer possibilities))
                         (setq bufA
@@ -3407,7 +3414,7 @@ Ediff Control Panel to restore highlighting."
                           t))
             (let ((cursor-in-echo-area t))
               (message "Enter the 1st buffer you want to compare (%s): "
-                       (mapconcat 'char-to-string possibilities "/"))
+                       (mapconcat 'char-to-string possibilities " or "))
               (setq answer (capitalize (read-char-exclusive)))))
           (setq answer "") ; silence error msg
           (while (cond ((memq answer possibilities)
@@ -3433,9 +3440,9 @@ Ediff Control Panel to restore highlighting."
                 bufB ediff-buffer-B
                 possibilities nil)))
 
+    (setq bufA (ediff-clone-buffer-for-region-comparison
+               (buffer-name bufA) "-Region.A-"))
     (ediff-with-current-buffer bufA
-      (or (mark t)
-         (error "You forgot to specify a region in buffer %s" (buffer-name)))
       (setq begA (region-beginning)
            endA (region-end))
       (goto-char begA)
@@ -3445,9 +3452,10 @@ Ediff Control Panel to restore highlighting."
       (end-of-line)
       (or (eobp) (forward-char)) ; include the newline char
       (setq endA (point)))
+
+    (setq bufB (ediff-clone-buffer-for-region-comparison
+               (buffer-name bufB) "-Region.B-"))
     (ediff-with-current-buffer bufB
-      (or (mark t)
-         (error "You forgot to specify a region in buffer %s" (buffer-name)))
       (setq begB (region-beginning)
            endB (region-end))
       (goto-char begB)
@@ -3458,52 +3466,6 @@ Ediff Control Panel to restore highlighting."
       (or (eobp) (forward-char)) ; include the newline char
       (setq endB (point)))
 
-    (ediff-unselect-and-select-difference
-     ediff-current-difference 'unselect-only)
-    (ediff-paint-background-regions 'unhighlight)
-
-    (ediff-with-current-buffer bufA
-      (goto-char begA)
-      (set-mark endA)
-      (narrow-to-region begA endA)
-      ;; (ediff-activate-mark)
-      )
-    ;; (sit-for 0)
-    (ediff-with-current-buffer bufB
-      (goto-char begB)
-      (set-mark endB)
-      (narrow-to-region begB endB)
-      ;; (ediff-activate-mark)
-      )
-    ;; (sit-for 0)
-    
-    ;; At this point, possibilities contains either the window char A/B/C
-    ;; that was not selected, or it is nil.  We delete the window that is not
-    ;; selected.
-    (if possibilities
-       (ediff-with-current-buffer ctl-buf
-         (let* ((wind-to-delete (eval
-                                 (ediff-get-symbol-from-alist
-                                  (car possibilities)
-                                   ediff-window-alist)))
-                (frame (window-frame wind-to-delete)))
-           (delete-window wind-to-delete)
-           (select-frame frame)
-           (balance-windows))))
-    (or (y-or-n-p 
-        "Please check regions selected for comparison.  Continue? ")
-       (setq quit-now t))
-    
-    (ediff-with-current-buffer bufA
-      (widen))
-    (ediff-with-current-buffer bufB
-      (widen))
-    (if quit-now
-       (ediff-with-current-buffer ctl-buf
-         (ediff-recenter)
-         (sit-for 0)
-         (error "All right.  Make up your mind and come back...")))
-
     (ediff-regions-internal
      bufA begA endA bufB begB endB
      nil                       ; setup-hook
index d07075bbac8b53fb8082aa3b142ff3ed94675800..05f0fcbabfa0626582977cc22e6021fb19924fe2 100644 (file)
@@ -6,8 +6,8 @@
 ;; Created: February 2, 1994
 ;; Keywords: comparing, merging, patching, tools, unix
 
-(defconst ediff-version "2.76.1" "The current version of Ediff")
-(defconst ediff-date "January 4, 2002" "Date of last update")  
+(defconst ediff-version "2.77" "The current version of Ediff")
+(defconst ediff-date "March 5, 2002" "Date of last update")  
 
 
 ;; This file is part of GNU Emacs.
 ;; Last directory used by an Ediff command for the ancestor file.
 (defvar ediff-last-dir-ancestor nil)
 ;; Last directory used by an Ediff command as the output directory for merge.
-(defvar ediff-last-merge-autostore-dir)
+(defvar ediff-last-merge-autostore-dir nil)
 
 
 ;; Used as a startup hook to set `_orig' patch file read-only.
@@ -688,8 +688,11 @@ names.  Only the files that are under revision control are taken into account."
       (or (stringp merge-autostore-dir)
          (error "%s: Directory for storing merged files must be a string"
                 jobname)))
-  (let (diffs ; var where ediff-intersect-directories returns the diff list
-       file-list meta-buf)
+  (let (;; dir-diff-struct is of the form (common-list diff-list) 
+       ;; It is a structure where ediff-intersect-directories returns
+       ;; commonalities and differences among directories
+       dir-diff-struct
+       meta-buf)
     (if (and ediff-autostore-merges
             (ediff-merge-metajob jobname)
             (not merge-autostore-dir))
@@ -715,9 +718,9 @@ names.  Only the files that are under revision control are taken into account."
                    "Directory for saving merged files = Ancestor Directory.  Sure? ")
                   (error "Directory merge aborted")))))
     
-    (setq file-list (ediff-intersect-directories 
-                    jobname 'diffs
-                    regexp dir1 dir2 dir3 merge-autostore-dir))
+    (setq dir-diff-struct (ediff-intersect-directories 
+                          jobname
+                          regexp dir1 dir2 dir3 merge-autostore-dir))
     (setq startup-hooks
          ;; this sets various vars in the meta buffer inside
          ;; ediff-prepare-meta-buffer
@@ -725,11 +728,12 @@ names.  Only the files that are under revision control are taken into account."
                   ;; tell what to do if the user clicks on a session record
                   (setq ediff-session-action-function (quote ,action))
                   ;; set ediff-dir-difference-list 
-                  (setq ediff-dir-difference-list (quote ,diffs)))
+                  (setq ediff-dir-difference-list
+                        (cdr (quote ,dir-diff-struct))))
                startup-hooks))
     (setq meta-buf (ediff-prepare-meta-buffer 
                    'ediff-filegroup-action
-                   file-list
+                   (car dir-diff-struct)
                    "*Ediff Session Group Panel"
                    'ediff-redraw-directory-group-buffer
                    jobname
@@ -839,10 +843,10 @@ If WIND-B is nil, use window next to WIND-A."
              end-B (window-end))))
     (setq buffer-A
          (ediff-clone-buffer-for-window-comparison
-          buffer-A wind-A "-Window1-")
+          buffer-A wind-A "-Window.A-")
          buffer-B
          (ediff-clone-buffer-for-window-comparison
-          buffer-B wind-B "-Window2-"))
+          buffer-B wind-B "-Window.B-"))
     (ediff-regions-internal
      buffer-A beg-A end-A buffer-B beg-B end-B
      startup-hooks job-name word-mode nil)))
@@ -853,18 +857,32 @@ If WIND-B is nil, use window next to WIND-A."
                      buff-name
                      (concat buff-name region-name
                              (symbol-name (gensym)))))
-       (wind (ediff-get-visible-buffer-window buff-name)))
+       (wind (ediff-get-visible-buffer-window buff-name))
+       (pop-up-windows t)
+       other-wind
+       msg-buf)
     (ediff-with-current-buffer cloned-buff
       (setq ediff-temp-indirect-buffer t))
     (if (window-live-p wind)
        (set-window-buffer wind cloned-buff))
     (pop-to-buffer cloned-buff)
-    (message 
-     "Mark a region in buffer %s; then type %s. Use %s to abort."
-     (buffer-name cloned-buff)
-     (ediff-format-bindings-of 'exit-recursive-edit)
-     (ediff-format-bindings-of 'abort-recursive-edit))
-    (recursive-edit)
+    (with-temp-buffer
+      (erase-buffer)
+      (insert
+       (format "\n   *******  Mark a region in buffer %s  *******\n"
+              (buffer-name cloned-buff)))
+      (insert
+       (format "\n\t      When done, type %s       Use %s to abort\n    "
+              (ediff-format-bindings-of 'exit-recursive-edit)
+              (ediff-format-bindings-of 'abort-recursive-edit)))
+      (goto-char (point-min))
+      (setq msg-buf (current-buffer))
+      (other-window 1)
+      (set-window-buffer (selected-window) msg-buf)
+      (shrink-window-if-larger-than-buffer)
+      (select-window wind)
+      (recursive-edit)
+      )
     cloned-buff))
 
 (defun ediff-clone-buffer-for-window-comparison (buff wind region-name)
@@ -910,9 +928,9 @@ lines.  For large regions, use `ediff-regions-linewise'."
   
   
   (let ((buffer-A
-         (ediff-clone-buffer-for-region-comparison buffer-A "-Region1-"))
+         (ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
        (buffer-B
-         (ediff-clone-buffer-for-region-comparison buffer-B "-Region2-"))
+         (ediff-clone-buffer-for-region-comparison buffer-B "-Region.B-"))
         reg-A-beg reg-A-end reg-B-beg reg-B-end)
     (save-excursion
       (set-buffer buffer-A)
@@ -954,9 +972,9 @@ lines.  For small regions, use `ediff-regions-wordwise'."
       (error "Buffer %S doesn't exist" buffer-B))
   
   (let ((buffer-A
-         (ediff-clone-buffer-for-region-comparison buffer-A "-Region1-"))
+         (ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
        (buffer-B
-         (ediff-clone-buffer-for-region-comparison buffer-B "-Region2-"))
+         (ediff-clone-buffer-for-region-comparison buffer-B "-Region.B-"))
         reg-A-beg reg-A-end reg-B-beg reg-B-end)
     (save-excursion
       (set-buffer buffer-A)