diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 59a852f2057..899d1a9fffa 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,27 @@ +2002-03-05 Michael Kifer + + * 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 * emacs-lisp/easy-mmode.el (define-minor-mode): diff --git a/lisp/ediff-init.el b/lisp/ediff-init.el index ae6d05ab40a..cfa1ce9da7d 100644 --- a/lisp/ediff-init.el +++ b/lisp/ediff-init.el @@ -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 diff --git a/lisp/ediff-mult.el b/lisp/ediff-mult.el index b8e576d72b7..83dde656a15 100644 --- a/lisp/ediff-mult.el +++ b/lisp/ediff-mult.el @@ -40,19 +40,20 @@ ;; 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 diff --git a/lisp/ediff-util.el b/lisp/ediff-util.el index e1dbdc7f336..be9fbb424d3 100644 --- a/lisp/ediff-util.el +++ b/lisp/ediff-util.el @@ -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 diff --git a/lisp/ediff.el b/lisp/ediff.el index d07075bbac8..05f0fcbabfa 100644 --- a/lisp/ediff.el +++ b/lisp/ediff.el @@ -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. @@ -154,7 +154,7 @@ ;; 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)