Mercurial > hg > xemacs-beta
diff lisp/ediff/ediff-mult.el @ 70:131b0175ea99 r20-0b30
Import from CVS: tag r20-0b30
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:02:59 +0200 |
parents | 0293115a14e9 |
children | c7528f8e288d |
line wrap: on
line diff
--- a/lisp/ediff/ediff-mult.el Mon Aug 13 09:00:04 2007 +0200 +++ b/lisp/ediff/ediff-mult.el Mon Aug 13 09:02:59 2007 +0200 @@ -1,6 +1,6 @@ ;;; ediff-mult.el --- support for multi-file/multi-buffer processing in Ediff -;; Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. +;; Copyright (C) 1995, 1996 Free Software Foundation, Inc. ;; Author: Michael Kifer <kifer@cs.sunysb.edu> @@ -26,7 +26,7 @@ ;; Users are encouraged to add functionality to this file. ;; The present file contains all the infrastructure needed for that. ;; -;; Generally, to to implement a new multisession capability within Ediff, +;; Generally, to implement a new multisession capability within Ediff, ;; you need to tell it ;; ;; 1. How to display the session group buffer. @@ -90,20 +90,7 @@ ;;; Code: -(provide 'ediff-mult) - -;; compiler pacifier -(eval-when-compile - (let ((load-path (cons (expand-file-name ".") load-path))) - (or (featurep 'ediff-init) - (load "ediff-init.el" nil nil 'nosuffix)) - (or (featurep 'ediff-util) - (load "ediff-util.el" nil nil 'nosuffix)) - )) -;; end pacifier - (require 'ediff-init) -(require 'ediff-util) ;; meta-buffer (ediff-defvar-local ediff-meta-buffer nil "") @@ -168,17 +155,10 @@ (defvar ediff-session-group-setup-hook nil "*Hooks run just after a meta-buffer controlling a session group, such as ediff-directories, is run.") -(defvar ediff-quit-session-group-hook nil - "*Hooks run just before exiting a session group.") (defvar ediff-show-registry-hook nil "*Hooks run just after the registry buffer is shown.") (defvar ediff-show-session-group-hook nil "*Hooks run just after a session group buffer is shown.") -(defvar ediff-meta-buffer-keymap-setup-hook nil - "*Hooks run just after setting up the ediff-meta-buffer-map. -This keymap controls key bindings in the meta buffer and is a local variable. -This means that you can set different bindings for different kinds of meta -buffers.") ;; buffer holding the multi-file patch. local to the meta buffer (ediff-defvar-local ediff-meta-patchbufer nil "") @@ -188,7 +168,6 @@ ;; group buffer/regexp (defun ediff-get-group-buffer (meta-list) (nth 0 (car meta-list))) - (defun ediff-get-group-regexp (meta-list) (nth 1 (car meta-list))) ;; group objects @@ -198,9 +177,6 @@ (nth 3 (car meta-list))) (defun ediff-get-group-objC (meta-list) (nth 4 (car meta-list))) -(defun ediff-get-group-merge-autostore-dir (meta-list) - (nth 5 (car meta-list))) - ;; session buffer (defun ediff-get-session-buffer (elt) (nth 0 elt)) @@ -248,9 +224,7 @@ (define-key ediff-meta-buffer-map [mouse-2] ediff-meta-action-function) (define-key ediff-meta-buffer-map [button2] ediff-meta-action-function)) - (use-local-map ediff-meta-buffer-map) - ;; modify ediff-meta-buffer-map here - (run-hooks 'ediff-meta-buffer-keymap-setup-hook)) + (use-local-map ediff-meta-buffer-map)) (defun ediff-meta-mode () "This mode controls all operations on Ediff session groups. @@ -339,16 +313,11 @@ (backward-char 1))) )) -(defsubst ediff-add-slash-if-directory (dir file) - (if (file-directory-p (concat dir file)) - (file-name-as-directory file) - file)) -;; 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 a regexp used to filter out files in the directories. +;; DIR1, DIR2, DIR3 are directories. +;; REGEXP is a regexp used to filter +;; files in the directories. ;; 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. @@ -356,53 +325,44 @@ ;; ((dir1 dir2 dir3) (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: +;; DIFF-VAR is contains the name of the variable in which to return the +;; difference list. The diff list is of the form: ;; ((dir1 dir2 dir3) (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. (defun ediff-intersect-directories (jobname diff-var regexp dir1 dir2 - &optional - dir3 merge-autostore-dir comparison-func) + &optional dir3 comparison-func) (setq comparison-func (or comparison-func 'string=)) (let (lis1 lis2 lis3 common auxdir1 auxdir2 auxdir3 difflist) (setq auxdir1 (file-name-as-directory dir1) lis1 (directory-files auxdir1 nil regexp) - lis1 (delete "." lis1) - lis1 (delete ".." lis1) - lis1 (mapcar - (function - (lambda (elt) - (ediff-add-slash-if-directory auxdir1 elt))) - lis1) auxdir2 (file-name-as-directory dir2) - lis2 (mapcar - (function - (lambda (elt) - (ediff-add-slash-if-directory auxdir2 elt))) - (directory-files auxdir2 nil regexp))) + lis2 (directory-files auxdir2 nil regexp)) (if (stringp dir3) (setq auxdir3 (file-name-as-directory dir3) - lis3 (mapcar - (function - (lambda (elt) - (ediff-add-slash-if-directory auxdir3 elt))) - (directory-files auxdir3 nil regexp)))) + lis3 (directory-files auxdir3 nil regexp))) + + (setq lis1 (delete "." lis1) + lis1 (delete ".." lis1)) - (if (stringp merge-autostore-dir) - (setq merge-autostore-dir - (file-name-as-directory merge-autostore-dir))) (setq common (ediff-intersection lis1 lis2 comparison-func)) - - ;; 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 (ediff-intersection common lis3 comparison-func))) + ;; get rid of files that are directories in dir1 but not dir2 + (mapcar (function (lambda (elt) + (if (Xor (file-directory-p (concat auxdir1 elt)) + (file-directory-p (concat auxdir2 elt))) + (setq common (delq elt common))))) + common) + ;; intersect with the third dir + (if lis3 (setq common (ediff-intersection common lis3 comparison-func))) + (if (ediff-comparison-metajob3 jobname) + (mapcar (function (lambda (elt) + (if (Xor (file-directory-p (concat auxdir1 elt)) + (file-directory-p (concat auxdir3 elt))) + (setq common (delq elt common))))) + common)) ;; copying is needed because sort sorts via side effects (setq common (sort (ediff-copy-list common) 'string-lessp)) @@ -433,47 +393,25 @@ difflist) (setq difflist (cons (list regexp auxdir1 auxdir2 auxdir3) difflist)) - ;; return the difference list back to the calling function (set diff-var difflist) ;; return result - (cons (list regexp auxdir1 auxdir2 auxdir3 merge-autostore-dir) - (mapcar - (function - (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 (list regexp auxdir1 auxdir2 auxdir3) + (mapcar (function (lambda (elt) + (list (concat auxdir1 elt) + (concat auxdir2 elt) + (if lis3 + (concat auxdir3 elt))))) + common)) )) ;; find directory files that are under revision. -;; Include subdirectories, since we may visit them recursively. -;; DIR1 is the directory to inspect. -;; OUTPUT-DIR is the directory where to auto-store the results of merges. Can -;; be nil. -(defun ediff-get-directory-files-under-revision (jobname - regexp dir1 - &optional merge-autostore-dir) +;; display subdirectories, too, since we may visit them recursively. +(defun ediff-get-directory-files-under-revision (jobname regexp dir1) (let (lis1 elt common auxdir1) (setq auxdir1 (file-name-as-directory dir1) lis1 (directory-files auxdir1 nil regexp)) - (if (stringp merge-autostore-dir) - (setq merge-autostore-dir - (file-name-as-directory merge-autostore-dir))) - (while lis1 (setq elt (car lis1) lis1 (cdr lis1)) @@ -488,14 +426,13 @@ ) ; while (setq common (delete "." common) - common (delete ".." common) - common (delete "RCS" common)) + common (delete ".." common)) ;; copying is needed because sort sorts via side effects (setq common (sort (ediff-copy-list common) 'string-lessp)) ;; return result - (cons (list regexp auxdir1 nil nil merge-autostore-dir) + (cons (list regexp auxdir1 nil nil) (mapcar (function (lambda (elt) (list (concat auxdir1 elt) nil nil))) @@ -562,32 +499,28 @@ ;; 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. - ;; + ;; 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 `='. + ;; Also, session objA/B/C are turned into lists (obj eq-indicator) ;; For now, the eq-indicator is used only for 2 and 3-file jobs. (setq ediff-meta-list (cons (cons meta-buffer (car meta-list)) - (mapcar - (function - (lambda (elt) - (cons nil - (cons nil - ;; convert each obj to (obj nil), - ;; where nil is the initial value - ;; for eq-indicator -- see above - (mapcar - (function (lambda (obj) (list obj nil))) - elt))))) - (cdr meta-list))))) + (mapcar (function + (lambda (elt) + (cons nil + (cons nil + ;; convert each obj to (obj nil), + ;; where nil may later be replaced + ;; by =, if this file equals some + ;; other file in the same session + (mapcar (function + (lambda (obj) + (list obj nil))) + elt))))) + (cdr meta-list))))) (or (eq meta-buffer ediff-registry-buffer) (setq ediff-session-registry @@ -601,9 +534,8 @@ (set-buffer-modified-p nil) (run-hooks 'startup-hooks) - - ;; Arrange to show directory contents differences - ;; Must be after run startup-hooks, since ediff-dir-difference-list is + ;; arrange for showing directory contents differences + ;; must be after run startup-hooks, since ediff-dir-difference-list is ;; set inside these hooks (if (eq action-func 'ediff-filegroup-action) (progn @@ -642,7 +574,6 @@ (empty t) (sessionNum 0) regexp elt session-buf f1 f2 f3 pt - merge-autostore-dir point tmp-list buffer-read-only) (ediff-eval-in-buffer meta-buf (setq point (point)) @@ -650,8 +581,7 @@ (insert (format ediff-meta-buffer-message (ediff-abbrev-jobname ediff-metajob-name))) - (setq regexp (ediff-get-group-regexp meta-list) - merge-autostore-dir (ediff-get-group-merge-autostore-dir meta-list)) + (setq regexp (ediff-get-group-regexp meta-list)) (cond ((ediff-collect-diffs-metajob) (insert @@ -667,13 +597,8 @@ " `=':\tmark identical files in each session\n\n")) (if (and (stringp regexp) (> (length regexp) 0)) - (insert - (format "\n*** Filter-through regular expression: %s\n" regexp))) - (if (and ediff-autostore-merges (ediff-merge-metajob) - (stringp merge-autostore-dir)) - (insert (format - "\nMerges are automatically stored in directory: %s\n" - merge-autostore-dir))) + (insert (format "Filter-through regular expression: %s\n" regexp))) + (insert "\n Size Last modified Name ----------------------------------------------------------------------- @@ -696,6 +621,7 @@ ;; now organize file names like this: ;; use-mark sizeA dateA sizeB dateB filename ;; make sure directories are displayed with a trailing slash. + ;; If one is a directory and another isn't, indicate this with a `?' (while meta-list (setq elt (car meta-list) meta-list (cdr meta-list) @@ -726,63 +652,50 @@ ;; Check if this is a problematic session. ;; Return nil if not. Otherwise, return symbol representing the problem ;; At present, problematic sessions occur only in -with-ancestor comparisons -;; when the ancestor is a directory rather than a file, or when there is no -;; suitable ancestor file in the ancestor directory +;; when the ancestor is a directory rather than a file. (defun ediff-problematic-session-p (session) (let ((f1 (ediff-get-session-objA-name session)) (f2 (ediff-get-session-objB-name session)) (f3 (ediff-get-session-objC-name session))) (cond ((and (stringp f1) (not (file-directory-p f1)) (stringp f2) (not (file-directory-p f2)) - ;; either invalid file name or a directory - (or (not (stringp f3)) (file-directory-p f3)) + (stringp f3) (file-directory-p f3) (ediff-ancestor-metajob)) ;; more may be added later 'ancestor-is-dir) (t nil)))) (defun ediff-meta-insert-file-info (fileinfo) - (let ((fname (car fileinfo)) + (let ((file-size -1) + (fname (car fileinfo)) (feq (ediff-get-file-eqstatus fileinfo)) - file-modtime file-size) + (file-modtime "*file doesn't exist*")) - (cond ((not (stringp fname)) (setq file-size -2)) ; file doesn't exits - ((not (ediff-file-remote-p fname)) - (if (file-exists-p fname) - ;; set real size and modtime - (setq file-size (ediff-file-size fname) - file-modtime (ediff-file-modtime fname)) - (setq file-size -2))) ; file doesn't exist - ( t (setq file-size -1))) ; remote file + (if (and (stringp fname) (file-exists-p fname)) + (setq file-size (ediff-file-size fname) + file-modtime (ediff-file-modtime fname))) (if (stringp fname) (insert (format "%s %s %-20s %s\n" (if feq "=" " ") ; equality indicator - (format "%10s" (cond ((= file-size -1) "--") - ((< file-size -1) "--") - (t file-size))) - (cond ((= file-size -1) "*remote file*") - ((< file-size -1) "*file doesn't exist*") - (t (ediff-format-date (decode-time file-modtime)))) - - ;; dir names in meta lists have training slashes, so we just - ;; abbreviate the file name, if file exists - (if (and (not (stringp fname)) (< file-size -1)) - "-------" ; file doesn't exist - (ediff-abbreviate-file-name fname))))))) + (format "%10s" (if (< file-size 0) + "remote" + file-size)) + (if (< file-size 0) + "file" + (ediff-format-date (decode-time file-modtime))) + ;; dir names in meta lists have no trailing `/' so insert it + (cond ((file-directory-p fname) + (file-name-as-directory (ediff-abbreviate-file-name fname))) + (t (ediff-abbreviate-file-name fname))))) + ))) (defconst ediff-months '((1 . "Jan") (2 . "Feb") (3 . "Mar") (4 . "Apr") (5 . "May") (6 . "Jun") (7 . "Jul") (8 . "Aug") (9 . "Sep") (10 . "Oct") (11 . "Nov") (12 . "Dec")) "Months' associative array.") -;; returns 2char string -(defsubst ediff-fill-leading-zero (num) - (if (< num 10) - (format "0%d" num) - (number-to-string num))) - ;; TIME is like the output of decode-time (defun ediff-format-date (time) (format "%s %2d %4d %s:%s:%s" @@ -794,6 +707,12 @@ (ediff-fill-leading-zero (nth 0 time)) ; sec )) +;; returns 2char string +(defsubst ediff-fill-leading-zero (num) + (if (< num 10) + (format "0%d" num) + (number-to-string num))) + (defun ediff-draw-dir-diffs (diff-list) (if (null diff-list) (error "Lost difference info on these directories")) (let* ((buf-name (ediff-unique-buffer-name @@ -822,8 +741,7 @@ DEL: previous line\n\n") (if (and (stringp regexp) (> (length regexp) 0)) - (insert - (format "\n*** Filter-through regular expression: %s\n" regexp))) + (insert (format "Filter-through regular expression: %s\n" regexp))) (insert "\n") (insert (format "\n%-27s%-26s" (ediff-truncate-string-left @@ -1212,7 +1130,6 @@ (meta-buf (ediff-event-buffer last-command-event)) ;; ediff-get-meta-info gives error if meta-buf or pos are invalid (info (ediff-get-meta-info meta-buf pos)) - merge-autostore-dir session-buf file1 file2 file3 regexp) (setq session-buf (ediff-get-session-buffer info) @@ -1232,8 +1149,6 @@ (error "Aborted")))) (ediff-eval-in-buffer meta-buf - (setq merge-autostore-dir - (ediff-get-group-merge-autostore-dir ediff-meta-list)) (goto-char pos) ; if the user clicked on session--move point there ;; First handle sessions involving directories (which are themselves ;; session groups) @@ -1288,20 +1203,13 @@ ((ediff-problematic-session-p info) (beep) (if (y-or-n-p - "This session has no ancestor. Merge without the ancestor? ") + "This session's ancestor is a directory, merge without the ancestor? ") (ediff-merge-files file1 file2 ;; provide startup hooks (` (list (lambda () (setq ediff-meta-buffer (, (current-buffer))) - (setq ediff-merge-store-file - (, (concat - merge-autostore-dir - "mrg_" - (file-name-nondirectory file1)))) - ;; make ediff-startup pass - ;; ediff-control-buffer back to the meta - ;; level; see below + ;; see below for the explanation of what this does (setcar (quote (, info)) ediff-control-buffer))))) (error "Aborted"))) @@ -1311,14 +1219,7 @@ ;; provide startup hooks (` (list (lambda () (setq ediff-meta-buffer (, (current-buffer))) - (setq ediff-merge-store-file - (, (concat - merge-autostore-dir - "mrg_" - (file-name-nondirectory file1)))) - ;; make ediff-startup pass - ;; ediff-control-buffer back to the meta - ;; level; see below + ;; see below for explanation of what this does (setcar (quote (, info)) ediff-control-buffer)))))) ((not (ediff-metajob3)) ; need 2 file args @@ -1327,14 +1228,12 @@ ;; provide startup hooks (` (list (lambda () (setq ediff-meta-buffer (, (current-buffer))) - (setq ediff-merge-store-file - (, (concat - merge-autostore-dir - "mrg_" - (file-name-nondirectory file1)))) - ;; make ediff-startup pass + ;; this makes ediff-startup pass the value of ;; ediff-control-buffer back to the meta - ;; level; see below + ;; level, to the record in the meta list + ;; containing the information about the + ;; session associated with that + ;; ediff-control-buffer (setcar (quote (, info)) ediff-control-buffer)))))) ((ediff-metajob3) ; need 3 file args @@ -1342,18 +1241,7 @@ file1 file2 file3 ;; arrange startup hooks (` (list (lambda () - (setq ediff-merge-store-file - (, (concat - merge-autostore-dir - "mrg_" - (file-name-nondirectory file1)))) (setq ediff-meta-buffer (, (current-buffer))) - ;; this arranges that ediff-startup will pass - ;; the value of ediff-control-buffer back to - ;; the meta level, to the record in the meta - ;; list containing the information about the - ;; session associated with that - ;; ediff-control-buffer (setcar (quote (, info)) ediff-control-buffer)))))) ) ; cond @@ -1516,8 +1404,8 @@ 'ediff-registry)) )) -;; If meta-buf exists, it is redrawn along with parent. -;; Otherwise, nothing happens. +;; if meta-buf exists, it is redrawn along with parent. Otherwise, nothing +;; happens (defun ediff-cleanup-meta-buffer (meta-buffer) (if (ediff-buffer-live-p meta-buffer) (ediff-eval-in-buffer meta-buffer @@ -1542,7 +1430,7 @@ cont)))) (defun ediff-quit-meta-buffer () - "If the group has no active session, delete the meta buffer. + "If no unprocessed sessions in the group, delete the meta buffer. If no session is in progress, ask to confirm before deleting meta buffer. Otherwise, bury the meta buffer. If this is a session registry buffer then just bury it." @@ -1557,7 +1445,6 @@ (ediff-cleanup-meta-buffer buf) (cond ((and (ediff-safe-to-quit buf) (y-or-n-p "Quit this session group? ")) - (run-hooks 'ediff-quit-session-group-hook) (message "") (ediff-dispose-of-meta-buffer buf)) ((ediff-safe-to-quit buf) @@ -1730,7 +1617,9 @@ ;;; Local Variables: ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) -;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) ;;; End: +(provide 'ediff-mult) +(require 'ediff-util) + ;;; ediff-mult.el ends here