+ merge-buffer-file)))
+
+
+;;; Directory and file group operations
+
+;; Get appropriate default name for directory:
+;; If ediff-use-last-dir, use ediff-last-dir-A.
+;; In dired mode, use the directory that is under the point (if any);
+;; otherwise, use default-directory
+(defun ediff-get-default-directory-name ()
+ (cond (ediff-use-last-dir ediff-last-dir-A)
+ ((eq major-mode 'dired-mode)
+ (let ((f (dired-get-filename nil 'noerror)))
+ (if (and (stringp f) (file-directory-p f))
+ f
+ default-directory)))
+ (t default-directory)))
+
+
+;;;###autoload
+(defun ediff-directories (dir1 dir2 regexp)
+ "Run Ediff on a pair of directories, DIR1 and DIR2, comparing files that have
+the same name in both. The third argument, REGEXP, is nil or a regular
+expression; only file names that match the regexp are considered."
+ (interactive
+ (let ((dir-A (ediff-get-default-directory-name))
+ (default-regexp (eval ediff-default-filtering-regexp))
+ f)
+ (list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
+ (ediff-read-file-name "Directory B to compare:"
+ (if ediff-use-last-dir
+ ediff-last-dir-B
+ (ediff-strip-last-dir f))
+ nil)
+ (read-string
+ (if (stringp default-regexp)
+ (format "Filter through regular expression (default %s): "
+ default-regexp)
+ "Filter through regular expression: ")
+ nil
+ 'ediff-filtering-regexp-history
+ (eval ediff-default-filtering-regexp))
+ )))
+ (ediff-directories-internal
+ dir1 dir2 nil regexp 'ediff-files 'ediff-directories
+ ))
+
+;;;###autoload
+(defalias 'edirs 'ediff-directories)
+
+
+;;;###autoload
+(defun ediff-directory-revisions (dir1 regexp)
+ "Run Ediff on a directory, DIR1, comparing its files with their revisions.
+The second argument, REGEXP, is a regular expression that filters the file
+names. Only the files that are under revision control are taken into account."
+ (interactive
+ (let ((dir-A (ediff-get-default-directory-name))
+ (default-regexp (eval ediff-default-filtering-regexp))
+ )
+ (list (ediff-read-file-name
+ "Directory to compare with revision:" dir-A nil)
+ (read-string
+ (if (stringp default-regexp)
+ (format "Filter through regular expression (default %s): "
+ default-regexp)
+ "Filter through regular expression: ")
+ nil
+ 'ediff-filtering-regexp-history
+ (eval ediff-default-filtering-regexp))
+ )))
+ (ediff-directory-revisions-internal
+ dir1 regexp 'ediff-revision 'ediff-directory-revisions
+ ))
+
+;;;###autoload
+(defalias 'edir-revisions 'ediff-directory-revisions)
+
+
+;;;###autoload
+(defun ediff-directories3 (dir1 dir2 dir3 regexp)
+ "Run Ediff on three directories, DIR1, DIR2, and DIR3, comparing files that
+have the same name in all three. The last argument, REGEXP, is nil or a
+regular expression; only file names that match the regexp are considered."
+
+ (interactive
+ (let ((dir-A (ediff-get-default-directory-name))
+ (default-regexp (eval ediff-default-filtering-regexp))
+ f)
+ (list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
+ (setq f (ediff-read-file-name "Directory B to compare:"
+ (if ediff-use-last-dir
+ ediff-last-dir-B
+ (ediff-strip-last-dir f))
+ nil))
+ (ediff-read-file-name "Directory C to compare:"
+ (if ediff-use-last-dir
+ ediff-last-dir-C
+ (ediff-strip-last-dir f))
+ nil)
+ (read-string
+ (if (stringp default-regexp)
+ (format "Filter through regular expression (default %s): "
+ default-regexp)
+ "Filter through regular expression: ")
+ nil
+ 'ediff-filtering-regexp-history
+ (eval ediff-default-filtering-regexp))
+ )))
+ (ediff-directories-internal
+ dir1 dir2 dir3 regexp 'ediff-files3 'ediff-directories3
+ ))
+
+;;;###autoload
+(defalias 'edirs3 'ediff-directories3)
+
+;;;###autoload
+(defun ediff-merge-directories (dir1 dir2 regexp &optional merge-autostore-dir)
+ "Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have
+the same name in both. The third argument, REGEXP, is nil or a regular
+expression; only file names that match the regexp are considered."
+ (interactive
+ (let ((dir-A (ediff-get-default-directory-name))
+ (default-regexp (eval ediff-default-filtering-regexp))
+ f)
+ (list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
+ (ediff-read-file-name "Directory B to merge:"
+ (if ediff-use-last-dir
+ ediff-last-dir-B
+ (ediff-strip-last-dir f))
+ nil)
+ (read-string
+ (if (stringp default-regexp)
+ (format "Filter through regular expression (default %s): "
+ default-regexp)
+ "Filter through regular expression: ")
+ nil
+ 'ediff-filtering-regexp-history
+ (eval ediff-default-filtering-regexp))
+ )))
+ (ediff-directories-internal
+ dir1 dir2 nil regexp 'ediff-merge-files 'ediff-merge-directories
+ nil merge-autostore-dir
+ ))
+
+;;;###autoload
+(defalias 'edirs-merge 'ediff-merge-directories)
+
+;;;###autoload
+(defun ediff-merge-directories-with-ancestor (dir1 dir2 ancestor-dir regexp
+ &optional
+ merge-autostore-dir)
+ "Merge files in directories DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors.
+Ediff merges files that have identical names in DIR1, DIR2. If a pair of files
+in DIR1 and DIR2 doesn't have an ancestor in ANCESTOR-DIR, Ediff will merge
+without ancestor. The fourth argument, REGEXP, is nil or a regular expression;
+only file names that match the regexp are considered."
+ (interactive
+ (let ((dir-A (ediff-get-default-directory-name))
+ (default-regexp (eval ediff-default-filtering-regexp))
+ f)
+ (list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
+ (setq f (ediff-read-file-name "Directory B to merge:"
+ (if ediff-use-last-dir
+ ediff-last-dir-B
+ (ediff-strip-last-dir f))
+ nil))
+ (ediff-read-file-name "Ancestor directory:"
+ (if ediff-use-last-dir
+ ediff-last-dir-C
+ (ediff-strip-last-dir f))
+ nil)
+ (read-string
+ (if (stringp default-regexp)
+ (format "Filter through regular expression (default %s): "
+ default-regexp)
+ "Filter through regular expression: ")
+ nil
+ 'ediff-filtering-regexp-history
+ (eval ediff-default-filtering-regexp))
+ )))
+ (ediff-directories-internal
+ dir1 dir2 ancestor-dir regexp
+ 'ediff-merge-files-with-ancestor 'ediff-merge-directories-with-ancestor
+ nil merge-autostore-dir
+ ))
+
+;;;###autoload
+(defun ediff-merge-directory-revisions (dir1 regexp
+ &optional merge-autostore-dir)
+ "Run Ediff on a directory, DIR1, merging its files with their revisions.
+The second argument, REGEXP, is a regular expression that filters the file
+names. Only the files that are under revision control are taken into account."
+ (interactive
+ (let ((dir-A (ediff-get-default-directory-name))
+ (default-regexp (eval ediff-default-filtering-regexp))
+ )
+ (list (ediff-read-file-name
+ "Directory to merge with revisions:" dir-A nil)
+ (read-string
+ (if (stringp default-regexp)
+ (format "Filter through regular expression (default %s): "
+ default-regexp)
+ "Filter through regular expression: ")
+ nil
+ 'ediff-filtering-regexp-history
+ (eval ediff-default-filtering-regexp))
+ )))
+ (ediff-directory-revisions-internal
+ dir1 regexp 'ediff-merge-revisions 'ediff-merge-directory-revisions
+ nil merge-autostore-dir
+ ))
+
+;;;###autoload
+(defalias 'edir-merge-revisions 'ediff-merge-directory-revisions)
+
+;;;###autoload
+(defun ediff-merge-directory-revisions-with-ancestor (dir1 regexp
+ &optional
+ merge-autostore-dir)
+ "Run Ediff on a directory, DIR1, merging its files with their revisions and ancestors.
+The second argument, REGEXP, is a regular expression that filters the file
+names. Only the files that are under revision control are taken into account."
+ (interactive
+ (let ((dir-A (ediff-get-default-directory-name))
+ (default-regexp (eval ediff-default-filtering-regexp))
+ )
+ (list (ediff-read-file-name
+ "Directory to merge with revisions and ancestors:" dir-A nil)
+ (read-string
+ (if (stringp default-regexp)
+ (format "Filter through regular expression (default %s): "
+ default-regexp)
+ "Filter through regular expression: ")
+ nil
+ 'ediff-filtering-regexp-history
+ (eval ediff-default-filtering-regexp))
+ )))
+ (ediff-directory-revisions-internal
+ dir1 regexp 'ediff-merge-revisions-with-ancestor
+ 'ediff-merge-directory-revisions-with-ancestor
+ nil merge-autostore-dir
+ ))
+
+;;;###autoload
+(defalias
+ 'edir-merge-revisions-with-ancestor
+ 'ediff-merge-directory-revisions-with-ancestor)
+
+;;;###autoload
+(defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor)
+
+;; Run ediff-action (ediff-files, ediff-merge, ediff-merge-with-ancestors)
+;; on a pair of directories (three directories, in case of ancestor).
+;; The third argument, REGEXP, is nil or a regular expression;
+;; only file names that match the regexp are considered.
+;; JOBNAME is the symbol indicating the meta-job to be performed.
+;; MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
+(defun ediff-directories-internal (dir1 dir2 dir3 regexp action jobname
+ &optional startup-hooks
+ merge-autostore-dir)
+ ;; ediff-read-file-name is set to attach a previously entered file name if
+ ;; the currently entered file is a directory. This code takes care of that.
+ (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1))
+ dir2 (if (file-directory-p dir2) dir2 (file-name-directory dir2)))
+
+ (if (stringp dir3)
+ (setq dir3 (if (file-directory-p dir3) dir3 (file-name-directory dir3))))
+
+ (cond ((string= dir1 dir2)
+ (error "Directories A and B are the same: %s" dir1))
+ ((and (eq jobname 'ediff-directories3)
+ (string= dir1 dir3))
+ (error "Directories A and C are the same: %s" dir1))
+ ((and (eq jobname 'ediff-directories3)
+ (string= dir2 dir3))
+ (error "Directories B and C are the same: %s" dir1)))
+
+ (if merge-autostore-dir
+ (or (stringp merge-autostore-dir)
+ (error "%s: Directory for storing merged files must be a string"
+ jobname)))
+ (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))
+ (setq merge-autostore-dir
+ (read-file-name "Save merged files in directory: "
+ (if ediff-use-last-dir
+ ediff-last-merge-autostore-dir
+ (ediff-strip-last-dir dir1))
+ nil
+ 'must-match)))
+ ;; verify we are not merging into an orig directory
+ (if merge-autostore-dir
+ (cond ((and (stringp dir1) (string= merge-autostore-dir dir1))
+ (or (y-or-n-p
+ "Directory for saving merged files = Directory A. Sure? ")
+ (error "Directory merge aborted")))
+ ((and (stringp dir2) (string= merge-autostore-dir dir2))
+ (or (y-or-n-p
+ "Directory for saving merged files = Directory B. Sure? ")
+ (error "Directory merge aborted")))
+ ((and (stringp dir3) (string= merge-autostore-dir dir3))
+ (or (y-or-n-p
+ "Directory for saving merged files = Ancestor Directory. Sure? ")
+ (error "Directory merge aborted")))))
+
+ (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
+ (cons `(lambda ()
+ ;; 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
+ (cdr (quote ,dir-diff-struct))))
+ startup-hooks))
+ (setq meta-buf (ediff-prepare-meta-buffer
+ 'ediff-filegroup-action
+ (car dir-diff-struct)
+ "*Ediff Session Group Panel"
+ 'ediff-redraw-directory-group-buffer
+ jobname
+ startup-hooks))
+ (ediff-show-meta-buffer meta-buf)
+ ))
+
+;; MERGE-AUTOSTORE-DIR can be given to tell ediff where to store the merged
+;; files
+(defun ediff-directory-revisions-internal (dir1 regexp action jobname
+ &optional startup-hooks
+ merge-autostore-dir)
+ (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1)))
+
+ (if merge-autostore-dir
+ (or (stringp merge-autostore-dir)
+ (error "%S: Directory for storing merged files must be a string"
+ jobname)))
+ (let (file-list meta-buf)
+ (if (and ediff-autostore-merges
+ (ediff-merge-metajob jobname)
+ (not merge-autostore-dir))
+ (setq merge-autostore-dir
+ (read-file-name "Save merged files in directory: "
+ (if ediff-use-last-dir
+ ediff-last-merge-autostore-dir
+ (ediff-strip-last-dir dir1))
+ nil
+ 'must-match)))
+ ;; verify merge-autostore-dir != dir1
+ (if (and merge-autostore-dir
+ (stringp dir1)
+ (string= merge-autostore-dir dir1))
+ (or (y-or-n-p
+ "Directory for saving merged file = directory A. Sure? ")
+ (error "Merge of directory revisions aborted")))
+
+ (setq file-list
+ (ediff-get-directory-files-under-revision
+ jobname regexp dir1 merge-autostore-dir))
+ (setq startup-hooks
+ ;; this sets various vars in the meta buffer inside
+ ;; ediff-prepare-meta-buffer
+ (cons `(lambda ()
+ ;; tell what to do if the user clicks on a session record
+ (setq ediff-session-action-function (quote ,action)))
+ startup-hooks))
+ (setq meta-buf (ediff-prepare-meta-buffer
+ 'ediff-filegroup-action
+ file-list
+ "*Ediff Session Group Panel"
+ 'ediff-redraw-directory-group-buffer
+ jobname
+ startup-hooks))
+ (ediff-show-meta-buffer meta-buf)
+ ))