Function: ediff-intersect-directories
ediff-intersect-directories is a byte-compiled function defined in
ediff-mult.el.gz.
Signature
(ediff-intersect-directories JOBNAME REGEXP DIR1 DIR2 &optional DIR3 MERGE-AUTOSTORE-DIR)
Source Code
;; Defined in /usr/src/emacs/lisp/vc/ediff-mult.el.gz
;; 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.
;; REGEXP is nil or a filter regexp; only file names that match the regexp
;; are considered.
;; If a file is a directory in dir1 but not dir2 (or vice versa), it is not
;; 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.
;; If COMPARISON-FUNC is given, use it. Otherwise, use string=
;;
;; Returns a list of the form:
;; (COMMON-PART DIFF-LIST)
;; COMMON-PART is car and DIFF-LIST is cdr.
;;
;; COMMON-PART is of the form:
;; (META-HEADER (f1 f2 f3) (f1 f2 f3) ...)
;; f3 can be nil if intersecting only 2 directories.
;; Each triple (f1 f2 f3) represents the files to be compared in the
;; corresponding ediff subsession.
;;
;; 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:
;; 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.
;;
;; Some operations might use a different meta header. For instance,
;; ediff-multifile-patch doesn't have dir2 and dir3, and regexp,
;; comparison-func don't apply.
;;
(defun ediff-intersect-directories (jobname
regexp dir1 dir2
&optional
dir3 merge-autostore-dir)
(let (lis1 lis2 lis3 common auxdir1 auxdir2 auxdir3 common-part difflist)
(setq auxdir1 (file-name-as-directory dir1)
lis1 (directory-files auxdir1 nil regexp)
lis1 (delete "." lis1)
lis1 (delete ".." lis1)
lis1 (mapcar
(lambda (elt)
(ediff-add-slash-if-directory auxdir1 elt))
lis1)
auxdir2 (file-name-as-directory dir2)
lis2 (directory-files auxdir2 nil regexp)
lis2 (delete "." lis2)
lis2 (delete ".." lis2)
lis2 (mapcar
(lambda (elt)
(ediff-add-slash-if-directory auxdir2 elt))
lis2))
(if (stringp dir3)
(setq auxdir3 (file-name-as-directory dir3)
lis3 (directory-files auxdir3 nil regexp)
lis3 (delete "." lis3)
lis3 (delete ".." lis3)
lis3 (mapcar
(lambda (elt)
(ediff-add-slash-if-directory auxdir3 elt))
lis3)))
(if (ediff-nonempty-string-p merge-autostore-dir)
(setq merge-autostore-dir
(file-name-as-directory merge-autostore-dir)))
(setq common (seq-intersection lis1 lis2 #'string=))
;; In merge with ancestor jobs, we don't intersect with lis3.
;; If there is no ancestor, we'll offer to merge without the ancestor.
;; So, we intersect with lis3 only when we are doing 3-way file comparison
(if (and lis3 (ediff-comparison-metajob3 jobname))
(setq common (seq-intersection common lis3 #'string=)))
;; copying is needed because sort sorts via side effects
(setq common (sort (copy-sequence common) #'string-lessp))
;; compute difference list
(setq difflist (seq-difference
(seq-union (seq-union lis1 lis2 #'string=)
lis3
#'string=)
common
#'string=)
difflist (delete "." difflist)
;; copying is needed because sort sorts via side effects
difflist (sort (copy-sequence (delete ".." difflist))
#'string-lessp))
(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.
(mapc (lambda (elt)
(if (member (car elt) lis1)
(setcdr elt (* (cdr elt) ediff-membership-code1)))
(if (member (car elt) lis2)
(setcdr elt (* (cdr elt) ediff-membership-code2)))
(if (member (car elt) lis3)
(setcdr elt (* (cdr elt) ediff-membership-code3)))
)
difflist)
(setq difflist (cons
;; diff metalist header
(ediff-make-new-meta-list-header regexp
auxdir1 auxdir2 auxdir3
merge-autostore-dir
#'string=)
difflist))
(setq common-part
(cons
;; metalist header
(ediff-make-new-meta-list-header regexp
auxdir1 auxdir2 auxdir3
merge-autostore-dir
#'string=)
(mapcar
(lambda (elt)
(ediff-make-new-meta-list-element
(expand-file-name (concat auxdir1 elt))
(expand-file-name (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))
(expand-file-name (concat auxdir3 elt)))))))
common)))
;; return result
(cons common-part difflist)
))