diff lisp/ediff-mult.el @ 20206:f44ff2c52fac

new version
author Michael Kifer <kifer@cs.stonybrook.edu>
date Sat, 01 Nov 1997 01:46:51 +0000
parents 1ecc4a79d048
children 4327dd36b71b
line wrap: on
line diff
--- a/lisp/ediff-mult.el	Fri Oct 31 23:17:17 1997 +0000
+++ b/lisp/ediff-mult.el	Sat Nov 01 01:46:51 1997 +0000
@@ -120,16 +120,17 @@
 (defconst ediff-meta-buffer-message "This is an Ediff Session Group Panel: %s
 
 Useful commands:
-     button2, `v', RET over a session line:   start that Ediff session
-     `M':\tin any session invoked from here, brings back this group panel
-     `R':\tdisplay the registry of active Ediff sessions
-     `h':\tmark session for hiding (toggle)
-     `x':\thide marked sessions; with prefix arg--unhide hidden sessions
-     `m':\tmark session for a non-hiding operation (toggle)
-     SPC:\tnext session
-     DEL:\tprevious session
-     `E':\tbrowse Ediff on-line manual
-     `q':\tquit this session group
+     button2, v, or RET over session record:   start that Ediff session
+     M:\tin sessions invoked from here, brings back this group panel
+     R:\tdisplay the registry of active Ediff sessions
+     h:\tmark session for hiding (toggle)
+     x:\thide marked sessions; with prefix arg: unhide
+     m:\tmark session for a non-hiding operation (toggle)
+ n,SPC:\tnext session
+ p,DEL:\tprevious session
+     E:\tbrowse Ediff on-line manual
+     T:\ttoggle truncation of long file names
+     q:\tquit this session group
 ")
 
 (ediff-defvar-local ediff-meta-buffer-map nil
@@ -166,6 +167,8 @@
 ;; group.
 (ediff-defvar-local ediff-meta-list nil "")
 
+(ediff-defvar-local ediff-meta-session-number nil "")
+
 
 ;; the difference list between directories in a directory session group
 (ediff-defvar-local ediff-dir-difference-list nil "")
@@ -174,6 +177,11 @@
 ;; The registry of Ediff sessions. A list of control buffers.
 (defvar ediff-session-registry nil)
 
+(defcustom ediff-meta-truncate-filenames t
+  "*If non-nil, truncate long file names in the session group buffers.
+This can be toggled with `ediff-toggle-filename-truncation'."
+  :type 'hook
+  :group 'ediff-mult)
 (defcustom ediff-registry-setup-hook nil
   "*Hooks run just after the registry control panel is set up."
   :type 'hook
@@ -250,6 +258,15 @@
 (defsubst ediff-set-file-eqstatus (elt value)
   (setcar (cdr elt) value))
 
+;; 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
+(defun ediff-get-session-activity-marker (session)
+  (let ((session-buf (ediff-get-session-buffer session)))
+    (cond ((null session-buf) nil) ; virgin session
+	  ((ediff-buffer-live-p session-buf) ?+) ;active session
+	  (t ?-))))
+
 ;; checks if the session is a meta session
 (defun ediff-meta-session-p (session-info)
   (and (stringp (ediff-get-session-objA-name session-info))
@@ -264,12 +281,15 @@
   (setq ediff-meta-buffer-map (make-sparse-keymap))
   (suppress-keymap ediff-meta-buffer-map)
   (define-key ediff-meta-buffer-map "q" 'ediff-quit-meta-buffer)
+  (define-key ediff-meta-buffer-map "T" 'ediff-toggle-filename-truncation)
   (define-key ediff-meta-buffer-map "R" 'ediff-show-registry)
   (define-key ediff-meta-buffer-map "E" 'ediff-documentation)
   (define-key ediff-meta-buffer-map "v" ediff-meta-action-function)
   (define-key ediff-meta-buffer-map "\C-m" ediff-meta-action-function)
   (define-key ediff-meta-buffer-map  " "  'ediff-next-meta-item)
+  (define-key ediff-meta-buffer-map  "n"  'ediff-next-meta-item)
   (define-key ediff-meta-buffer-map  "\C-?"  'ediff-previous-meta-item)
+  (define-key ediff-meta-buffer-map  "p"  'ediff-previous-meta-item)
   (define-key ediff-meta-buffer-map  [delete]  'ediff-previous-meta-item)
   (define-key ediff-meta-buffer-map  [backspace]  'ediff-previous-meta-item)
   (or (ediff-one-filegroup-metajob)
@@ -313,7 +333,9 @@
 (suppress-keymap ediff-dir-diffs-buffer-map)
 (define-key ediff-dir-diffs-buffer-map "q" 'ediff-bury-dir-diffs-buffer)
 (define-key ediff-dir-diffs-buffer-map " " 'next-line)
+(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 [delete] 'previous-line)
 (define-key ediff-dir-diffs-buffer-map [backspace] 'previous-line)
 
@@ -322,20 +344,20 @@
 Moves in circular fashion. With numeric prefix arg, skip this many items."
   (interactive "p")
   (or count (setq count 1))
-  (while (< 0 count)
-    (setq count (1- count))
-    (ediff-next-meta-item1)))
+  (let (overl)
+    (while (< 0 count)
+      (setq count (1- count))
+      (ediff-next-meta-item1)
+      (setq overl (ediff-get-meta-overlay-at-pos (point)))
+      ;; skip invisible ones
+      (while (and overl (ediff-overlay-get overl 'invisible))
+	(ediff-next-meta-item1)
+	(setq overl (ediff-get-meta-overlay-at-pos (point)))))))
 
 ;; Move to the next meta item
 (defun ediff-next-meta-item1 ()
   (let (pos)
     (setq pos (ediff-next-meta-overlay-start (point)))
-;;;	;; skip deleted
-;;;    (while (memq (ediff-get-session-status
-;;;	          (ediff-get-meta-info (current-buffer) pos 'noerror))
-;;;		 '(?H ?I))
-;;;      (setq pos (ediff-next-meta-overlay-start pos)))
-    
     (if pos (goto-char pos))
     (if (eq ediff-metajob-name 'ediff-registry)
 	(if (and (ediff-get-meta-info (current-buffer) pos 'noerror)
@@ -350,9 +372,15 @@
 Moves in circular fashion. With numeric prefix arg, skip this many items."
   (interactive "p")
   (or count (setq count 1))
-  (while (< 0 count)
-    (setq count (1- count))
-    (ediff-previous-meta-item1)))
+  (let (overl)
+    (while (< 0 count)
+      (setq count (1- count))
+      (ediff-previous-meta-item1)
+      (setq overl (ediff-get-meta-overlay-at-pos (point)))
+      ;; skip invisible ones
+      (while (and overl (ediff-overlay-get overl 'invisible))
+	(ediff-previous-meta-item1)
+	(setq overl (ediff-get-meta-overlay-at-pos (point)))))))
 
 (defun ediff-previous-meta-item1 ()
   (let (pos)
@@ -376,6 +404,14 @@
       (file-name-as-directory file)
     file))
 
+(defun ediff-toggle-filename-truncation ()
+  "Toggle truncation of long file names in session group buffers.
+Set `ediff-meta-truncate-filenames' variable if you want to change the default
+behavior."
+  (interactive)
+  (setq ediff-meta-truncate-filenames (not ediff-meta-truncate-filenames))
+  (ediff-update-meta-buffer (current-buffer) 'must-redraw))
+
 
 ;; DIR1, DIR2, DIR3 are directories. DIR3 can be nil.
 ;; OUTPUT-DIR is a directory for auto-storing the results of merge jobs.
@@ -490,11 +526,10 @@
 	   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.
+;; find directory files that are under revision.  Include subdirectories, since
+;; we may visit them recursively.  DIR1 is the directory to inspect.
+;; MERGE-AUTOSTORE-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)
@@ -511,7 +546,8 @@
 	    lis1 (cdr lis1))
       ;; take files under revision control
       (cond ((file-directory-p (concat auxdir1 elt))
-	     (setq common (cons elt common)))
+	     (setq common
+		   (cons (ediff-add-slash-if-directory auxdir1 elt) common)))
 	    ((file-exists-p (concat auxdir1 elt ",v"))
 	     (setq common (cons elt common)))
 	    ((file-exists-p (concat auxdir1 "RCS/" elt ",v"))
@@ -519,8 +555,8 @@
 	    ) ; cond
       ) ; while
 
-    (setq common (delete "."  common)
-	  common (delete ".." common)
+    (setq common (delete "./"  common)
+	  common (delete "../" common)
 	  common (delete "RCS" common))
 
     ;; copying is needed because sort sorts via side effects
@@ -665,6 +701,74 @@
       ) ; eval in meta-buffer
     meta-buffer))
 
+;; Insert the activity marker for session SESSION in the meta buffer at point
+;; The activity marker is either SPC (untouched session), 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)
+(defun ediff-insert-session-activity-marker-in-meta-buffer (session)
+  (insert
+   (cond ((ediff-get-session-activity-marker session))
+	 ;; virgin session
+	 (t " "))))
+
+;; Insert session status at point. Status is either ?H (marked for hiding), or
+;; ?I (hidden or invalid), or ?* (meaning marked for an operation; currently,
+;; such op can only be checking for equality)), or SPC (meaning neither marked
+;; nor invalid) 
+(defun ediff-insert-session-status-in-meta-buffer (session)
+  (insert
+   (cond ((ediff-get-session-status session)) ; session has status: ?H, ?I, ?*
+	 ;; normal session, no marks or hidings
+	 (t " "))))
+
+;; If NEW-MARKER is non-nil, use it to substitute the current activity marker
+;; in the meta buffer. If nil, use SPC
+(defun ediff-replace-session-activity-marker-in-meta-buffer (point new-marker)
+  (let* ((overl (ediff-get-meta-overlay-at-pos point))
+	 (session-info (ediff-overlay-get overl 'ediff-meta-info))
+	 (activity-marker (ediff-get-session-activity-marker session-info))
+	 buffer-read-only)
+    (or new-marker activity-marker (setq new-marker ?\ ))
+    (goto-char (ediff-overlay-start overl))
+    (if (eq (char-after (point)) new-marker)
+	() ; if marker shown in buffer is the same as new-marker, do nothing
+      (insert new-marker)
+      (delete-char 1)
+      (set-buffer-modified-p nil))))
+
+;; If NEW-STATUS is non-nil, use it to substitute the current status marker in
+;; the meta buffer. If nil, use SPC
+(defun ediff-replace-session-status-in-meta-buffer (point new-status)
+  (let* ((overl (ediff-get-meta-overlay-at-pos point))
+	 (session-info (ediff-overlay-get overl 'ediff-meta-info))
+	 (status (ediff-get-session-status session-info))
+	 buffer-read-only)
+    (setq new-status (or new-status status ?\ ))
+    (goto-char (ediff-overlay-start overl))
+    (forward-char 1) ; status is the second char in session record
+    (if (eq (char-after (point)) new-status)
+	() ; if marker shown in buffer is the same as new-marker, do nothing
+      (insert new-status)
+      (delete-char 1)
+      (set-buffer-modified-p nil))))
+
+;; insert all file info in meta buffer for a given session
+(defun ediff-insert-session-info-in-meta-buffer (session-info sessionNum)
+  (let ((f1 (ediff-get-session-objA session-info))
+	(f2 (ediff-get-session-objB session-info))
+	(f3 (ediff-get-session-objC session-info))
+	(pt (point))
+	(hidden (eq (ediff-get-session-status session-info) ?I)))
+    ;; insert activity marker, i.e., SPC, - or +
+    (ediff-insert-session-activity-marker-in-meta-buffer session-info)
+    ;; insert session status, i.e., *, H
+    (ediff-insert-session-status-in-meta-buffer session-info)
+    (insert "  Session " (int-to-string sessionNum) ":\n")
+    (ediff-meta-insert-file-info1 f1)
+    (ediff-meta-insert-file-info1 f2)
+    (ediff-meta-insert-file-info1 f3)
+    (ediff-set-meta-overlay pt (point) session-info sessionNum hidden)))
+
 
 ;; this is a setup function for ediff-directories
 ;; must return meta-buffer
@@ -673,42 +777,50 @@
   (let ((meta-buf (ediff-get-group-buffer meta-list))
 	(empty t)
 	(sessionNum 0)
-	regexp elt session-buf f1 f2 f3 pt 
-	merge-autostore-dir
+	regexp elt merge-autostore-dir
 	point tmp-list buffer-read-only)
     (ediff-with-current-buffer meta-buf
       (setq point (point))
       (erase-buffer)
+      ;; delete phony overlays that used to represent sessions before the buff
+      ;; was redrawn
+      (if ediff-emacs-p
+	  (mapcar 'delete-overlay (overlays-in 1 1))
+	(map-extents 'delete-extent))
+      
       (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))
+	    merge-autostore-dir
+	    (ediff-get-group-merge-autostore-dir meta-list))
       
       (cond ((ediff-collect-diffs-metajob)
 	     (insert
-	      "     `P':\tcollect custom diffs of all marked sessions\n"))
+	      "     P:\tcollect custom diffs of all marked sessions\n"))
 	    ((ediff-patch-metajob)
 	     (insert
-	      "     `P':\tshow patch appropriately for the context (session or group)\n")))
+	      "     P:\tshow patch appropriately for the context (session or group)\n")))
       (insert
-       "     `u':\tshow parent session group\n")
+       "     u:\tshow parent session group\n")
       (or (ediff-one-filegroup-metajob)
 	  (insert
-	   "     `D':\tshow differences among directories\n"
-	   "     `=':\tmark identical files in each session\n\n"))
+	   "     D:\tshow differences among directories\n"
+	   "     =:\tmark identical files in each session\n\n"))
 
+      (insert "\n")
       (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)))
+      (ediff-insert-dirs-in-meta-buffer meta-list)
       (if (and ediff-autostore-merges (ediff-merge-metajob)
 	       (stringp merge-autostore-dir))
 	  (insert (format
-		   "\nMerges are automatically stored in directory: %s\n"
+		   "\nMerge results are automatically stored in:\n\t%s\n"
 		   merge-autostore-dir)))
       (insert "\n
         Size   Last modified           Name
-    -----------------------------------------------------------------------
+    ----------------------------------------------
 
 ")
       
@@ -734,27 +846,87 @@
 	      sessionNum (1+ sessionNum))
 	(if (eq (ediff-get-session-status elt) ?I)
 	    ()
-	  (setq session-buf (ediff-get-session-buffer elt)
-		f1 (ediff-get-session-objA elt)
-		f2 (ediff-get-session-objB elt)
-		f3 (ediff-get-session-objC elt))
-	  (setq pt (point))
-	  ;; insert markers
-	  (insert (cond ((null session-buf) " ") ; virgin session
-			((ediff-buffer-live-p session-buf) "+") ;active session
-			(t "-"))) ; finished session
-	  (insert (cond ((ediff-get-session-status elt)) ; session has status,
-						       ;;; e.g., ?H, ?I
-			(t " "))) ; normal session
-	  (insert "  Session " (int-to-string sessionNum) ":\n")
-	  (ediff-meta-insert-file-info f1)
-	  (ediff-meta-insert-file-info f2)
-	  (ediff-meta-insert-file-info f3)
-	  (ediff-set-meta-overlay pt (point) elt)))
+	  (ediff-insert-session-info-in-meta-buffer elt sessionNum)))
       (set-buffer-modified-p nil)
       (goto-char point)
       meta-buf)))
 
+(defun ediff-update-markers-in-dir-meta-buffer (meta-list)
+  (let ((meta-buf (ediff-get-group-buffer meta-list))
+	session-info point overl buffer-read-only)
+    (ediff-with-current-buffer meta-buf
+      (setq point (point))
+      (goto-char (point-min))
+      (ediff-next-meta-item1)
+      (while (not (bobp))
+	(setq session-info (ediff-get-meta-info meta-buf (point) 'no-error)
+	      overl (ediff-get-meta-overlay-at-pos (point)))
+	(if session-info
+	    (progn
+	      (cond ((eq (ediff-get-session-status session-info) ?I)
+		     ;; Do hiding
+		     (if overl (ediff-overlay-put overl 'invisible t)))
+		    ((and (eq (ediff-get-session-status session-info) ?H)
+			  overl (ediff-overlay-get overl 'invisible))
+		     ;; Do unhiding
+		     (ediff-overlay-put overl 'invisible nil))
+		    (t (ediff-replace-session-activity-marker-in-meta-buffer
+			(point)
+			(ediff-get-session-activity-marker session-info))
+		       (ediff-replace-session-status-in-meta-buffer
+			(point)
+			(ediff-get-session-status session-info))))))
+	(ediff-next-meta-item1) ; advance to the next item
+	) ; end while
+      (set-buffer-modified-p nil)
+      (goto-char point))
+    meta-buf))
+
+(defun ediff-update-session-marker-in-dir-meta-buffer (session-num)
+  (let (buffer-meta-overlays session-info overl buffer-read-only)
+    (setq overl
+	  (if ediff-xemacs-p
+	      (map-extents
+	       (function
+		(lambda (ext maparg)
+		  (if (and
+		       (ediff-overlay-get ext 'ediff-meta-info)
+		       (eq (ediff-overlay-get ext 'ediff-meta-session-number)
+			   session-num))
+		      ext))))
+	    ;; Emacs doesn't have map-extents, so try harder
+	    ;; Splice overlay lists to get all buffer overlays
+	    (setq buffer-meta-overlays (overlay-lists)
+		  buffer-meta-overlays (append (car buffer-meta-overlays)
+					       (cdr buffer-meta-overlays)))
+	    (car
+	     (delq nil
+		   (mapcar
+		    (function
+		     (lambda (overl)
+		       (if (and
+			    (ediff-overlay-get overl 'ediff-meta-info)
+			    (eq (ediff-overlay-get
+				 overl 'ediff-meta-session-number)
+				session-num))
+			   overl)))
+		    buffer-meta-overlays)))))
+    (or overl
+	(error
+	 "Bug in ediff-update-session-marker-in-dir-meta-buffer: no overlay with given number %S"
+	 session-num))
+    (setq session-info (ediff-overlay-get overl 'ediff-meta-info))
+    (goto-char (ediff-overlay-start overl))
+    (ediff-replace-session-activity-marker-in-meta-buffer
+     (point)
+     (ediff-get-session-activity-marker session-info))
+    (ediff-replace-session-status-in-meta-buffer
+     (point)
+     (ediff-get-session-status session-info)))
+  (ediff-next-meta-item1))
+
+
+
 ;; 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
@@ -773,11 +945,13 @@
 	   'ancestor-is-dir)
 	  (t nil))))
 
-(defun ediff-meta-insert-file-info (fileinfo)
+(defun ediff-meta-insert-file-info1 (fileinfo)
   (let ((fname (car fileinfo))
 	(feq (ediff-get-file-eqstatus fileinfo))
+	(max-filename-width (if ediff-meta-truncate-filenames
+				(- (window-width) 41)
+			      500))
 	file-modtime file-size)
-
     (cond ((not (stringp fname)) (setq file-size -2)) ; file doesn't exits
 	  ((not (ediff-file-remote-p fname))
 	   (if (file-exists-p fname)
@@ -802,7 +976,9 @@
 	  ;; abbreviate the file name, if file exists
 	  (if (and (not (stringp fname)) (< file-size -1))
 	      "-------"		; file doesn't exist
-	    (ediff-abbreviate-file-name fname)))))))
+	    (ediff-truncate-string-left
+	     (ediff-abbreviate-file-name fname)
+	     max-filename-width)))))))
 
 (defconst ediff-months '((1 . "Jan") (2 . "Feb") (3 . "Mar") (4 . "Apr")
 			(5 . "May") (6 . "Jun") (7 . "Jul") (8 . "Aug")
@@ -826,6 +1002,18 @@
 	  (ediff-fill-leading-zero (nth 0 time)) ; sec
 	  ))
 
+;; Draw the directories
+(defun ediff-insert-dirs-in-meta-buffer (meta-list)
+  (let* ((dir1 (ediff-abbreviate-file-name (ediff-get-group-objA meta-list)))
+	 (dir2 (ediff-get-group-objB meta-list))
+	 (dir2 (if (stringp dir2) (ediff-abbreviate-file-name dir2)))
+	 (dir3 (ediff-get-group-objC meta-list))
+	 (dir3 (if (stringp dir3) (ediff-abbreviate-file-name dir3))))
+    (insert "*** Directory A: " dir1 "\n")
+    (if dir2 (insert "*** Directory B: " dir2 "\n"))
+    (if dir3 (insert "*** Directory C: " dir3 "\n"))
+    (insert "\n")))
+
 (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
@@ -850,8 +1038,8 @@
       (insert "
 Useful commands:
      `q': hide this buffer
-     SPC: next line
-     DEL: previous line\n\n")
+   n,SPC: next line
+   p,DEL: previous line\n\n")
 
       (if (and (stringp regexp) (> (length regexp) 0))
 	  (insert
@@ -946,7 +1134,8 @@
   "Go to the parent session group buffer."
   (interactive)
   (if (ediff-buffer-live-p ediff-parent-meta-buffer)
-      (ediff-show-meta-buffer ediff-parent-meta-buffer)
+      (ediff-show-meta-buffer
+       ediff-parent-meta-buffer ediff-meta-session-number)
     (error "This session group has no parent")))
   
 
@@ -957,16 +1146,22 @@
 	  elt bufAname bufBname bufCname cur-diff total-diffs pt
 	  job-name meta-list registry-list buffer-read-only)
       (erase-buffer)
+      ;; delete phony overlays that used to represent sessions before the buff
+      ;; was redrawn
+      (if ediff-emacs-p
+	  (mapcar 'delete-overlay (overlays-in 1 1))
+	(map-extents 'delete-extent))
+
       (insert "This is a registry of all active Ediff sessions.
 
 Useful commands:
      button2, `v', RET over a session record:  switch to that session
-     `M' over a session record:  display the associated session group
-     `R' in any Ediff session:   display session registry
-     SPC:\tnext session
-     DEL:\tprevious session
-     `E':\tbrowse Ediff on-line manual
-     `q':\tbury registry
+     M over a session record:  display the associated session group
+     R in any Ediff session:   display session registry
+     n,SPC: next session
+     p,DEL: previous session
+         E: browse Ediff on-line manual
+         q: bury registry
 
 
 \t\tActive Ediff Sessions:
@@ -1048,14 +1243,19 @@
       (goto-char point)
       )))
 
-;; sets overlay around a meta record with 'ediff-meta-info property PROP
-(defun ediff-set-meta-overlay (b e prop)
+;; Sets overlay around a meta record with 'ediff-meta-info property PROP
+;; If optional SESSION-NUMBER, make it a property of the overlay,
+;; ediff-meta-session-number
+(defun ediff-set-meta-overlay (b e prop &optional session-number hidden)
   (let (overl)
     (setq overl (ediff-make-overlay b e))
     (if ediff-emacs-p
 	(ediff-overlay-put overl 'mouse-face 'highlight)
       (ediff-overlay-put overl 'highlight t))
-    (ediff-overlay-put overl 'ediff-meta-info prop)))
+    (ediff-overlay-put overl 'ediff-meta-info prop)
+    (ediff-overlay-put overl 'invisible hidden)
+    (if (numberp session-number)
+	(ediff-overlay-put overl 'ediff-meta-session-number session-number))))
 
 (defun ediff-mark-for-hiding (unmark)
   "Mark session for hiding. With prefix arg, unmark."
@@ -1064,8 +1264,8 @@
 	 (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))
-	 (session-buf (ediff-get-session-buffer info)))
-
+	 (session-buf (ediff-get-session-buffer info))
+	 (session-number (ediff-get-session-number-at-pos pos)))
     (if (eq (ediff-get-session-status info) ?H)
 	(setq unmark t))
     (if unmark
@@ -1075,7 +1275,7 @@
       (ediff-set-session-status info ?H))
     (or unmark
 	(ediff-next-meta-item 1))
-    (ediff-update-meta-buffer meta-buf)
+    (ediff-update-meta-buffer meta-buf nil session-number)
     ))
 
 (defun ediff-mark-for-operation (unmark)
@@ -1084,8 +1284,8 @@
   (let* ((pos (ediff-event-point last-command-event))
 	 (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)))
-
+	 (info (ediff-get-meta-info meta-buf pos))
+	 (session-number (ediff-get-session-number-at-pos pos)))
     (if (eq (ediff-get-session-status info) ?*)
 	(setq unmark t))
     (if unmark
@@ -1093,7 +1293,7 @@
       (ediff-set-session-status info ?*))
     (or unmark
 	(ediff-next-meta-item 1))
-    (ediff-update-meta-buffer meta-buf)
+    (ediff-update-meta-buffer meta-buf nil session-number)
     ))
 
 (defun ediff-hide-marked-sessions (unhide)
@@ -1124,7 +1324,7 @@
 	  (message "Nothing to reveal...")
 	(message "Nothing to hide...")))
     (if active-sessions-exist
-	(message "Note: didn't hide active sessions!"))
+	(message "Note: Ediff didn't hide active sessions!"))
     ))
 
 ;; Apply OPERATION to marked sessions. Operation expects one argument of type
@@ -1156,7 +1356,7 @@
 			(setq ediff-meta-diff-buffer diff-buffer)
 			;; collect diffs in child group
 			(ediff-operate-on-marked-sessions operation)))))))
-    (ediff-update-meta-buffer grp-buf) ; just in case
+    (ediff-update-meta-buffer grp-buf 'must-redraw) ; just in case
     numMarked
     ))
 
@@ -1255,11 +1455,11 @@
 	 (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)
+	 (session-buf (ediff-get-session-buffer info))
+	 (session-number (ediff-get-session-number-at-pos pos))
+	 merge-autostore-dir file1 file2 file3 regexp)
 
-    (setq session-buf (ediff-get-session-buffer info)
-	  file1 (ediff-get-session-objA-name info)
+    (setq file1 (ediff-get-session-objA-name info)
 	  file2 (ediff-get-session-objB-name info)
 	  file3 (ediff-get-session-objC-name info))
 
@@ -1271,7 +1471,7 @@
 	  (if (y-or-n-p "This session is marked as hidden, unmark? ")
 	      (progn
 		(ediff-set-session-status info nil)
-		(ediff-update-meta-buffer meta-buf))
+		(ediff-update-meta-buffer meta-buf nil session-number))
 	    (error "Aborted"))))
 
     (ediff-with-current-buffer meta-buf
@@ -1295,7 +1495,9 @@
 		(` (list (lambda () 
 			   ;; child session group should know its parent
 			   (setq ediff-parent-meta-buffer
-				 (quote (, ediff-meta-buffer)))
+				 (quote (, ediff-meta-buffer))
+				 ediff-meta-session-number
+				 (, session-number))
 			   ;; and parent will know its child
 			   (setcar (quote (, info)) ediff-meta-buffer)))))))
 
@@ -1312,9 +1514,12 @@
 		ediff-session-action-function ediff-metajob-name
 		;; make it update car info after startup
 		(` (list (lambda () 
-			   ;; child session group should know its parent
+			   ;; child session group should know its parent and
+			   ;; its number
 			   (setq ediff-parent-meta-buffer
-				 (quote (, ediff-meta-buffer)))
+				 (quote (, ediff-meta-buffer))
+				 ediff-meta-session-number
+				 (, session-number))
 			   ;; and parent will know its child
 			   (setcar (quote (, info)) ediff-meta-buffer)))))))
 
@@ -1334,11 +1539,13 @@
 		  file1 file2
 		  ;; provide startup hooks 
 		  (` (list (lambda () 
-			     (setq ediff-meta-buffer (, (current-buffer)))
+			     (setq ediff-meta-buffer (, (current-buffer))
+				   ediff-meta-session-number
+				   (, session-number))
 			     (setq ediff-merge-store-file
 				   (, (concat
 				       merge-autostore-dir
-				       "mrg_"
+				       "merge_"
 				       (file-name-nondirectory file1))))
 			     ;; make ediff-startup pass
 			     ;; ediff-control-buffer back to the meta
@@ -1351,11 +1558,13 @@
 		      file1
 		      ;; provide startup hooks 
 		      (` (list (lambda () 
-				 (setq ediff-meta-buffer (, (current-buffer)))
+				 (setq ediff-meta-buffer (, (current-buffer))
+				       ediff-meta-session-number
+				       (, session-number))
 				 (setq ediff-merge-store-file
 				       (, (concat
 					   merge-autostore-dir
-					   "mrg_"
+					   "merge_"
 					   (file-name-nondirectory file1))))
 				 ;; make ediff-startup pass
 				 ;; ediff-control-buffer back to the meta
@@ -1367,11 +1576,13 @@
 		      file1 file2
 		      ;; provide startup hooks 
 		      (` (list (lambda () 
-				 (setq ediff-meta-buffer (, (current-buffer)))
+				 (setq ediff-meta-buffer (, (current-buffer))
+				       ediff-meta-session-number
+				       (, session-number))
 				 (setq ediff-merge-store-file
 				       (, (concat
 					   merge-autostore-dir
-					   "mrg_"
+					   "merge_"
 					   (file-name-nondirectory file1))))
 				 ;; make ediff-startup pass
 				 ;; ediff-control-buffer back to the meta
@@ -1386,9 +1597,11 @@
 				 (setq ediff-merge-store-file
 				       (, (concat
 					   merge-autostore-dir
-					   "mrg_"
+					   "merge_"
 					   (file-name-nondirectory file1))))
-				 (setq ediff-meta-buffer (, (current-buffer)))
+				 (setq ediff-meta-buffer (, (current-buffer))
+				       ediff-meta-session-number
+				       (, session-number))
 				 ;; this arranges that ediff-startup will pass
 				 ;; the value of ediff-control-buffer back to
 				 ;; the meta level, to the record in the meta
@@ -1413,7 +1626,7 @@
 	(if (ediff-with-current-buffer ctl-buf
 	      (eq (key-binding "q") 'ediff-quit-meta-buffer))
 	    ;; it's a meta-buffer -- last action should just display it
-	    (ediff-show-meta-buffer ctl-buf)
+	    (ediff-show-meta-buffer ctl-buf t)
 	  ;; it's a session buffer -- invoke go back to session
 	  (ediff-with-current-buffer ctl-buf
 	    (setq ediff-mouse-pixel-position (mouse-pixel-position))
@@ -1426,7 +1639,8 @@
     ))
 
 
-(defun ediff-show-meta-buffer (&optional meta-buf)
+;; If session number is t, means don't update meta buffer
+(defun ediff-show-meta-buffer (&optional meta-buf session-number)
   "Show the session group buffer."
   (interactive)
   (let (wind frame silent)
@@ -1439,7 +1653,12 @@
 	   (error
 	    "Can't find this session's group panel -- session itself is ok")))
 
-    (ediff-cleanup-meta-buffer meta-buf)
+    (cond ((numberp session-number)
+	   (ediff-update-meta-buffer meta-buf nil session-number))
+	  ;; if session-number is t, don't update
+	  (session-number)
+	  (t (ediff-cleanup-meta-buffer meta-buf)))
+
     (ediff-with-current-buffer meta-buf
       (save-excursion
 	(cond ((setq wind (ediff-get-visible-buffer-window meta-buf))
@@ -1477,6 +1696,10 @@
     (run-hooks 'ediff-show-session-group-hook)
     ))
 
+(defun ediff-show-current-session-meta-buffer ()
+  (interactive)
+  (ediff-show-meta-buffer nil ediff-meta-session-number))
+
 (defun ediff-show-meta-buff-from-registry ()
   "Display the session group buffer for a selected session group."
   (interactive)
@@ -1485,7 +1708,7 @@
 	 (info (ediff-get-meta-info meta-buf pos))
 	 (meta-or-session-buf info))
     (ediff-with-current-buffer meta-or-session-buf
-      (ediff-show-meta-buffer))))
+      (ediff-show-meta-buffer nil t))))
 
 ;;;###autoload
 (defun ediff-show-registry ()
@@ -1538,12 +1761,20 @@
 ;; If meta-buf doesn't exist, it is created. In that case, id doesn't have a
 ;; parent meta-buf
 ;; Check if META-BUF exists before calling this function
-(defun ediff-update-meta-buffer (meta-buf)
-  (ediff-with-current-buffer (current-buffer)
-    (if (ediff-buffer-live-p meta-buf)
-	(ediff-with-current-buffer meta-buf
-	  (funcall ediff-meta-redraw-function ediff-meta-list))
-      )))
+;; Optional MUST-REDRAW, if non-nil, would force redrawal of the whole meta
+;; buffer. Otherwise, it will just go over the buffer and update activity marks
+;; and session status.
+;; SESSION-NUMBER, if specified, says which session caused the update.
+(defun ediff-update-meta-buffer (meta-buf &optional must-redraw session-number)
+  (if (ediff-buffer-live-p meta-buf)
+      (ediff-with-current-buffer meta-buf
+	(cond (must-redraw ; completely redraw the meta buffer
+	       (funcall ediff-meta-redraw-function ediff-meta-list))
+	      ((numberp session-number) ; redraw only for the given session
+	       (ediff-update-session-marker-in-dir-meta-buffer session-number))
+	      (t ; update only what's changed, but scan the entire meta buffer
+	       (ediff-update-markers-in-dir-meta-buffer ediff-meta-list)))
+	)))
 
 (defun ediff-update-registry ()
   (ediff-with-current-buffer (current-buffer)
@@ -1564,15 +1795,16 @@
       (ediff-with-current-buffer meta-buffer
 	(ediff-update-meta-buffer meta-buffer)
 	(if (ediff-buffer-live-p ediff-parent-meta-buffer)
-	    (ediff-update-meta-buffer ediff-parent-meta-buffer)))))
+	    (ediff-update-meta-buffer
+	     ediff-parent-meta-buffer nil ediff-meta-session-number)))))
 
-;; t if no session in progress
+;; t if no session is in progress
 (defun ediff-safe-to-quit (meta-buffer)
   (if (ediff-buffer-live-p meta-buffer)
       (let ((lis ediff-meta-list)
 	    (cont t)
 	    buffer-read-only)
-	(ediff-update-meta-buffer meta-buffer)
+	;;(ediff-update-meta-buffer meta-buffer)
 	(ediff-with-current-buffer meta-buffer
 	  (setq lis (cdr lis)) ; discard the description part of meta-list
 	  (while (and cont lis)
@@ -1591,11 +1823,12 @@
   (let* ((buf (current-buffer))
 	 (dir-diffs-buffer ediff-dir-diffs-buffer)
 	 (meta-diff-buffer ediff-meta-diff-buffer)
+	 (session-number ediff-meta-session-number)
 	 (parent-buf ediff-parent-meta-buffer)
 	 (dont-show-registry (eq buf ediff-registry-buffer)))
     (if dont-show-registry
 	(bury-buffer)
-      (ediff-cleanup-meta-buffer buf)
+      ;;(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)
@@ -1606,13 +1839,13 @@
 	    (t
 	     (error
 	      "This session group has active sessions---cannot exit")))
-      (ediff-cleanup-meta-buffer parent-buf)
+      (ediff-update-meta-buffer parent-buf nil session-number)
       (ediff-kill-buffer-carefully dir-diffs-buffer)
       (ediff-kill-buffer-carefully meta-diff-buffer)
       (if (ediff-buffer-live-p parent-buf)
 	  (progn
 	    (setq dont-show-registry t)
-	    (ediff-show-meta-buffer parent-buf)))
+	    (ediff-show-meta-buffer parent-buf session-number)))
       )
     (or dont-show-registry
 	(ediff-show-registry))))
@@ -1653,46 +1886,58 @@
 	(ediff-update-registry)
 	(error "No session info in this line")))))
 
-;; return location of the next meta overlay after point
+
+(defun ediff-get-meta-overlay-at-pos (point)
+  (if ediff-xemacs-p
+      (extent-at point (current-buffer) 'ediff-meta-info)
+    (let* ((overl-list (overlays-at point))
+	   (overl (car overl-list)))
+      (while (and overl (null (overlay-get overl 'ediff-meta-info)))
+	(setq overl-list (cdr overl-list)
+	      overl (car overl-list)))
+      overl)))
+
+(defsubst ediff-get-session-number-at-pos (point)
+  (ediff-overlay-get
+   (ediff-get-meta-overlay-at-pos point) 'ediff-meta-session-number))
+
+
+;; Return location of the next meta overlay after point
 (defun ediff-next-meta-overlay-start (point)
   (if (eobp)
       (goto-char (point-min))
-    (let (overl)
+    (let ((overl (ediff-get-meta-overlay-at-pos point)))
       (if ediff-xemacs-p
 	  (progn
-	    (setq overl (extent-at point (current-buffer) 'ediff-meta-info))
 	    (if overl
 		(setq overl (next-extent overl))
 	      (setq overl (next-extent (current-buffer))))
 	    (if overl
 		(extent-start-position overl)
 	      (point-max)))
-	(setq overl (car (overlays-at point)))
-	(if (and overl (overlay-get overl 'ediff-meta-info))
+	(if overl
 	    ;; note: end of current overlay is the beginning of the next one
 	    (overlay-end overl)
 	  (next-overlay-change point))))
     ))
 
+
 (defun ediff-previous-meta-overlay-start (point)
   (if (bobp)
       (goto-char (point-max))
-    (let (overl)
+    (let ((overl (ediff-get-meta-overlay-at-pos point)))
       (if ediff-xemacs-p
 	  (progn
-	    (setq overl (extent-at point (current-buffer) 'ediff-meta-info))
 	    (if overl
 		(setq overl (previous-extent overl))
 	      (setq overl (previous-extent (current-buffer))))
 	    (if overl
 		(extent-start-position overl)
 	      (point-min)))
-	(setq overl (car (overlays-at point)))
-	(if (and overl (overlay-get overl 'ediff-meta-info))
-	    (setq point (overlay-start overl)))
+	(if overl (setq point (overlay-start overl)))
 	;; to get to the beginning of prev overlay
 	(if (not (bobp))
-	    ;; trickery to overcome an emacs bug--doesn't always find previous
+	    ;; trick to overcome an emacs bug--doesn't always find previous
 	    ;; overlay change correctly
 	    (setq point (1- point)))
 	(setq point (previous-overlay-change point))
@@ -1701,8 +1946,7 @@
 	;; goto the top of the registry buffer.
 	(or (car (overlays-at point))
 	    (setq point (point-min)))
-	point
-	))))
+	point))))
 
 ;; this is the action invoked when the user selects a patch from the meta
 ;; buffer.
@@ -1752,19 +1996,18 @@
 	    (ediff-mark-if-equal fileinfo1 fileinfo3)
 	    (ediff-mark-if-equal fileinfo2 fileinfo3)))
       (setq list (cdr list))))
-  (ediff-update-meta-buffer (current-buffer)))
+  (ediff-update-meta-buffer (current-buffer) 'must-redraw))
 
 ;; mark files 1 and 2 as equal, if they are.
 (defun ediff-mark-if-equal (fileinfo1 fileinfo2)
-  (get-buffer-create ediff-tmp-buffer)
-  (or (file-directory-p (car fileinfo1))
-      (file-directory-p (car fileinfo2))
-      (if (= (ediff-make-diff2-buffer
-	      ediff-tmp-buffer (car fileinfo1) (car fileinfo2))
-	     0)
-	  (progn
-	    (ediff-set-file-eqstatus fileinfo1 t)
-	    (ediff-set-file-eqstatus fileinfo2 t)))))
+  (let ((f1 (car fileinfo1))
+	(f2 (car fileinfo2)))
+    (or (file-directory-p f1)
+	(file-directory-p f2)
+	(if (ediff-same-file-contents f1 f2)
+	    (progn
+	      (ediff-set-file-eqstatus fileinfo1 t)
+	      (ediff-set-file-eqstatus fileinfo2 t))))))