*** empty log message ***
[bpt/emacs.git] / lisp / ediff-util.el
index bf15d5d..76eaadd 100644 (file)
@@ -1,5 +1,6 @@
 ;;; ediff-util.el --- the core commands and utilities of ediff
-;;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+
+;; Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
 
 ;; Author: Michael Kifer <kifer@cs.sunysb.edu>
 
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Code:
 
 (require 'ediff-init)
-(require 'ediff-meta)
+(require 'ediff-mult)
+
+;; Pacify compiler and avoid the need in checking for boundp
+(defvar ediff-patch-diagnostics nil)
+(defvar ediff-patchbufer nil)
+;; end pacifier
 
 \f
 ;;; Functions
@@ -34,9 +40,11 @@ This mode is entered through one of the following commands:
        `ediff'
        `ediff-files'
        `ediff-buffers'
+       `ebuffers'
        `ediff3'
        `ediff-files3'
        `ediff-buffers3'
+       `ebuffers3'
        `ediff-merge'
        `ediff-merge-files'
        `ediff-merge-files-with-ancestor'
@@ -61,14 +69,6 @@ Commands:
   (setq mode-name "Ediff")
   (run-hooks 'ediff-mode-hook))
 
-(defun ediff-version ()
-  "Return string describing the version of Ediff.
-When called interactively, displays the version."
-  (interactive)
-  (if (interactive-p)
-      (message (ediff-version))
-    (format "Ediff %s of %s" ediff-version ediff-date)))
-    
     
 (require 'ediff-diff)
 (require 'ediff-merg)
@@ -145,43 +145,28 @@ to invocation.")
         ;; Will barf if no ancestor
         (define-key ediff-mode-map "/" 'ediff-show-ancestor)
         ;; In merging, we allow only A->C and B->C copying.
-        (define-key ediff-mode-map "a" (function
-                                        (lambda (arg)
-                                          (interactive "P")
-                                          (ediff-diff-to-diff arg "ac"))))
-        (define-key ediff-mode-map "b" (function
-                                        (lambda (arg)
-                                          (interactive "P")
-                                          (ediff-diff-to-diff arg "bc"))))
-        (define-key ediff-mode-map "r" (function
-                                        (lambda (arg)
-                                          (interactive "P")
-                                          (ediff-restore-diff arg ?c))))
+        (define-key ediff-mode-map "a" 'ediff-copy-A-to-C)
+        (define-key ediff-mode-map "b" 'ediff-copy-B-to-C)
+        (define-key ediff-mode-map "r" 'ediff-restore-diff-in-merge-buffer)
         (define-key ediff-mode-map "s" 'ediff-shrink-window-C)
         (define-key ediff-mode-map "+" 'ediff-combine-diffs)
         (define-key ediff-mode-map "$" 'ediff-toggle-show-clashes-only)
         (define-key ediff-mode-map "&" 'ediff-re-merge))
        (ediff-3way-comparison-job
-        (define-key ediff-mode-map "ab" 'ediff-diff-to-diff)
-        (define-key ediff-mode-map "ba" 'ediff-diff-to-diff)
-        (define-key ediff-mode-map "ac" 'ediff-diff-to-diff)
-        (define-key ediff-mode-map "bc" 'ediff-diff-to-diff)
+        (define-key ediff-mode-map "ab" 'ediff-copy-A-to-B)
+        (define-key ediff-mode-map "ba" 'ediff-copy-B-to-A)
+        (define-key ediff-mode-map "ac" 'ediff-copy-A-to-C)
+        (define-key ediff-mode-map "bc" 'ediff-copy-B-to-C)
         (define-key ediff-mode-map "c" nil)
-        (define-key ediff-mode-map "ca" 'ediff-diff-to-diff)
-        (define-key ediff-mode-map "cb" 'ediff-diff-to-diff)
+        (define-key ediff-mode-map "ca" 'ediff-copy-C-to-A)
+        (define-key ediff-mode-map "cb" 'ediff-copy-C-to-B)
         (define-key ediff-mode-map "ra" 'ediff-restore-diff)
         (define-key ediff-mode-map "rb" 'ediff-restore-diff)
         (define-key ediff-mode-map "rc" 'ediff-restore-diff)
         (define-key ediff-mode-map "C"  'ediff-toggle-read-only))
        (t ; 2-way comparison
-        (define-key ediff-mode-map "a" (function
-                                        (lambda (arg)
-                                          (interactive "P")
-                                          (ediff-diff-to-diff arg "ab"))))
-        (define-key ediff-mode-map "b" (function
-                                        (lambda (arg)
-                                          (interactive "P")
-                                          (ediff-diff-to-diff arg "ba"))))
+        (define-key ediff-mode-map "a"  'ediff-copy-A-to-B)
+        (define-key ediff-mode-map "b"  'ediff-copy-B-to-A)
         (define-key ediff-mode-map "ra" 'ediff-restore-diff)
         (define-key ediff-mode-map "rb" 'ediff-restore-diff))
        ) ; cond
@@ -198,6 +183,8 @@ to invocation.")
   (define-key ediff-mode-map "wa"  'ediff-save-buffer)
   (define-key ediff-mode-map "wb"  'ediff-save-buffer)
   (define-key ediff-mode-map "wd"  'ediff-save-buffer)
+  (if (fboundp 'ediff-show-patch-diagnostics)
+      (define-key ediff-mode-map "P"  'ediff-show-patch-diagnostics))
   (if ediff-3way-job
       (progn
        (define-key ediff-mode-map "wc" 'ediff-save-buffer)
@@ -215,8 +202,9 @@ to invocation.")
 
 (require 'ediff-wind)
 
-(or (boundp 'synchronize-minibuffers)
-    (defvar synchronize-minibuffers nil))
+;; No longer needed: XEmacs has surrogate minibuffers now.
+;;(or (boundp 'synchronize-minibuffers)
+;;    (defvar synchronize-minibuffers nil))
 
 ;; Common startup entry for all Ediff functions
 ;; It now returns control buffer so other functions can do post-processing
@@ -248,7 +236,7 @@ to invocation.")
            ediff-windows-job (ediff-windows-job)
            ediff-word-mode-job (ediff-word-mode-job))
        
-      (make-local-variable 'ediff-prefer-long-help-message)
+      (make-local-variable 'ediff-use-long-help-message)
       (make-local-variable 'ediff-prefer-iconified-control-frame)
       (make-local-variable 'ediff-split-window-function)
       (make-local-variable 'ediff-default-variant)
@@ -261,13 +249,9 @@ to invocation.")
       (if (string-match "buffer" (symbol-name ediff-job-name))
          (setq ediff-keep-variants t))
 
-      ;; XEmacs has local-pre-command-hook
-      (if ediff-emacs-p
-         (make-local-variable 'pre-command-hook))
-
-      (if ediff-emacs-p
-         (add-hook 'pre-command-hook 'ediff-spy-after-mouse)
-       (add-hook 'local-pre-command-hook 'ediff-spy-after-mouse))
+      (make-local-hook 'pre-command-hook)
+      (if (ediff-window-display-p)
+         (add-hook 'pre-command-hook 'ediff-spy-after-mouse nil t))
       (setq ediff-mouse-pixel-position (mouse-pixel-position))
       
       ;; adjust for merge jobs
@@ -298,7 +282,7 @@ to invocation.")
              (insert-buffer buf)
              (funcall (ediff-eval-in-buffer buf major-mode))
              ;; after Stig@hackvan.com
-             (add-hook 'local-write-file-hooks 'ediff-set-merge-mode)
+             (add-hook 'local-write-file-hooks 'ediff-set-merge-mode nil t)
              )))
       (setq buffer-read-only nil    
            ediff-buffer-A buffer-A
@@ -497,7 +481,7 @@ to invocation.")
 (defun ediff-help-message-line-length ()
   (save-excursion
     (goto-char (point-min))
-    (if ediff-prefer-long-help-message
+    (if ediff-use-long-help-message
        (next-line 1))
     (end-of-line)
     (current-column)))
@@ -553,7 +537,7 @@ to invocation.")
              (t ; long brief msg, not multiframe --- put in the middle
               ediff-brief-message-string)
              ))
-  (setq ediff-help-message (if ediff-prefer-long-help-message
+  (setq ediff-help-message (if ediff-use-long-help-message
                               ediff-long-help-message
                             ediff-brief-help-message))
   (run-hooks 'ediff-display-help-hook))
@@ -710,11 +694,9 @@ Reestablish the default three-window display."
   (interactive)
   (ediff-barf-if-not-control-buffer)
   
-  ;; force all minibuffer to display ediff's messages.
-  ;; when xemacs implements minibufferless frames, this won't be necessary
-  (if ediff-xemacs-p (setq synchronize-minibuffers t))
+;;  ;; No longer needed: XEmacs has surrogate minibuffers now.
+;;  (if ediff-xemacs-p (setq synchronize-minibuffers t))
   
-  (setq ediff-disturbed-overlays nil) ; clear after use
   (let (buffer-read-only)
     (if (and (ediff-buffer-live-p ediff-buffer-A)
             (ediff-buffer-live-p ediff-buffer-B)
@@ -723,9 +705,8 @@ Reestablish the default three-window display."
        (ediff-setup-windows
         ediff-buffer-A ediff-buffer-B ediff-buffer-C ediff-control-buffer)
       (or (eq this-command 'ediff-quit)
-         (message
-          "You've killed an essential Ediff buffer---Please quit Ediff"
-          (beep 1)))
+         (message ediff-KILLED-VITAL-BUFFER
+                  (beep 1)))
       ))
   
   ;; set visibility range appropriate to this invocation of Ediff.
@@ -741,7 +722,7 @@ Reestablish the default three-window display."
                       ediff-patch-action
                       ediff-toggle-wide-display ediff-toggle-multiframe))
               ;; Or one of the movement cmds and prev cmd was an Ediff cmd
-              ;; This avoids rasing frames unnecessarily.
+              ;; This avoids raising frames unnecessarily.
               (and (memq this-command
                          '(ediff-next-difference
                            ediff-previous-difference
@@ -758,7 +739,7 @@ Reestablish the default three-window display."
            (raise-frame (window-frame ediff-window-C)))))
   (if (and (ediff-window-display-p)
           (frame-live-p ediff-control-frame)
-          (not ediff-prefer-long-help-message)
+          (not ediff-use-long-help-message)
           (not (ediff-frame-iconified-p ediff-control-frame)))
       (raise-frame ediff-control-frame))
   
@@ -768,8 +749,7 @@ Reestablish the default three-window display."
     (if (and (ediff-buffer-live-p ediff-buffer-A)
             (ediff-buffer-live-p ediff-buffer-B)
             (or (not ediff-3way-job)
-                (ediff-buffer-live-p ediff-buffer-C))
-            )
+                (ediff-buffer-live-p ediff-buffer-C)))
        (progn
          (or no-rehighlight
              (ediff-select-difference ediff-current-difference))
@@ -780,10 +760,10 @@ Reestablish the default three-window display."
              (ediff-recenter-one-window 'C))
          
          (ediff-eval-in-buffer control-buf
-           (ediff-recenter-ancestor) ; it checks if ancestor is alive
+           (ediff-recenter-ancestor) ; check if ancestor is alive
            
            (if (and (ediff-multiframe-setup-p)
-                    (not ediff-prefer-long-help-message)
+                    (not ediff-use-long-help-message)
                     (not (ediff-frame-iconified-p ediff-control-frame)))
                ;; never grab mouse on quit in this place
                (ediff-reset-mouse
@@ -877,7 +857,7 @@ Does nothing if file-A and file-B are in different frames."
 On a dumb terminal, switches between ASCII highlighting and no highlighting." 
   (interactive)
   (ediff-barf-if-not-control-buffer)
-  (if (not (ediff-window-display-p))
+  (if (not (ediff-has-face-support-p))
       (if (eq ediff-highlighting-style 'ascii)
          (progn
            (message "ASCII highlighting flags removed")
@@ -958,11 +938,11 @@ In both cases, operates on the currrent difference region."
   (ediff-barf-if-not-control-buffer)
   (let (buffer-read-only)
     (erase-buffer)
-    (setq ediff-prefer-long-help-message (not ediff-prefer-long-help-message))
+    (setq ediff-use-long-help-message (not ediff-use-long-help-message))
     (ediff-set-help-message))
   ;; remember the icon status of the control frame when the user requested
   ;; full control message
-  (if (and ediff-prefer-long-help-message (ediff-multiframe-setup-p))
+  (if (and ediff-use-long-help-message (ediff-multiframe-setup-p))
       (setq ediff-prefer-iconified-control-frame
            (ediff-frame-iconified-p ediff-control-frame)))
            
@@ -978,11 +958,11 @@ If optional argument BUF is specified, toggle read-only in that buffer instead
 of the current buffer."
   (interactive)
   (ediff-barf-if-not-control-buffer)
-  (let ((ctl-buf (if (null buf) (current-buffer))))
+  (let ((ctl-buf (if (null buf) (current-buffer)))
+       (buf-type (ediff-char-to-buftype last-command-char)))
     (or buf (ediff-recenter))
     (or buf
-       (setq buf
-             (ediff-get-buffer (ediff-char-to-buftype last-command-char))))
+       (setq buf (ediff-get-buffer buf-type)))
              
     (ediff-eval-in-buffer buf     ; eval in buf A/B/C
       (let* ((file (buffer-file-name buf))
@@ -1016,8 +996,7 @@ of the current buffer."
                   ;; is checked in.
                   (ediff-eval-in-buffer ctl-buf
                     (ediff-change-saved-variable
-                     'buffer-read-only nil
-                     (ediff-char-to-buftype last-command-char))))
+                     'buffer-read-only nil buf-type)))
                  (t
                   (setq toggle-ro-cmd 'toggle-read-only)
                   (beep 1) (beep 1)
@@ -1048,16 +1027,22 @@ of the current buffer."
 ;; in and not checked out for the purpose of patching (since patch won't be
 ;; able to read such a file anyway).
 ;; FILE is a string representing file name
-(defsubst ediff-file-checked-out-p (file)
+(defun ediff-file-checked-out-p (file)
   (and (stringp file)
        (file-exists-p file)
        (file-writable-p file)
-       (file-exists-p (concat file ",v"))))
-(defsubst ediff-file-checked-in-p (file)
+       (or
+       (file-exists-p (concat file ",v"))
+       (file-exists-p (concat "RCS/" file ",v")))
+       ))
+(defun ediff-file-checked-in-p (file)
   (and (stringp file)
        (file-exists-p file)
        (not (file-writable-p file))
-       (file-exists-p (concat file ",v"))))
+       (or
+       (file-exists-p (concat file ",v"))
+       (file-exists-p (concat "RCS/" file ",v")))
+       ))
       
 (defun ediff-swap-buffers ()
   "Rotate the display of buffers A, B, and C."
@@ -1070,7 +1055,7 @@ of the current buffer."
            (hide-regexp ediff-regexp-hide-A)
            (focus-regexp ediff-regexp-focus-A)
            (wide-visibility-p (eq ediff-visible-bounds ediff-wide-bounds))
-           (overlay (if (ediff-window-display-p)
+           (overlay (if (ediff-has-face-support-p)
                         ediff-current-diff-overlay-A)))
        (if ediff-3way-comparison-job
            (progn
@@ -1119,7 +1104,7 @@ of the current buffer."
        
        ;; The following is needed for XEmacs, since there one can't move
        ;; overlay to another buffer. In Emacs, this swap is redundant.
-       (if (ediff-window-display-p)
+       (if (ediff-has-face-support-p)
            (if ediff-3way-comparison-job
                (setq ediff-current-diff-overlay-A ediff-current-diff-overlay-C
                      ediff-current-diff-overlay-C ediff-current-diff-overlay-B
@@ -1193,7 +1178,8 @@ This is especially useful when comparing buffers side-by-side."
        
 (defun ediff-toggle-multiframe ()
   "Switch from the multiframe display to single-frame display and back.
-This is primarily for debugging, but one can use it for fun, too."
+For a permanent change, set the variable `ediff-window-setup-function',
+which see."
   (interactive)
   (ediff-barf-if-not-control-buffer)
   (or (ediff-window-display-p)
@@ -1226,8 +1212,7 @@ This is primarily for debugging, but one can use it for fun, too."
 Used in ediff-windows/regions only."
   (interactive)
   (if (eq ediff-buffer-A ediff-buffer-B)
-      (error
-       "Buffers A and B are the same. Can't narrow to two different regions"))
+      (error ediff-NO-DIFFERENCES))
   (if (eq ediff-visible-bounds ediff-wide-bounds)
       (setq ediff-visible-bounds ediff-narrow-bounds)
     (setq ediff-visible-bounds ediff-wide-bounds))
@@ -1262,7 +1247,7 @@ Used in ediff-windows/regions only."
        (narrow-to-region
         (ediff-overlay-start overl-B) (ediff-overlay-end overl-B)))
       
-      (if ediff-3way-job
+      (if ediff-3way-comparison-job
          (ediff-eval-in-buffer ediff-buffer-C
            (narrow-to-region
             (ediff-overlay-start overl-C) (ediff-overlay-end overl-C))))
@@ -1284,7 +1269,7 @@ Used in ediff-windows/regions only."
                (ediff-buffer-live-p ediff-buffer-B)
                (or (not ediff-3way-job) ediff-buffer-C)
                ))
-      (error "You've killed an essential Ediff buffer---Please quit Ediff"))
+      (error ediff-KILLED-VITAL-BUFFER))
        
   (let* ((wind (selected-window))
         (wind-A ediff-window-A)
@@ -1315,7 +1300,7 @@ Used in ediff-windows/regions only."
 (defun ediff-scroll-vertically (&optional arg)
   "Vertically scroll buffers A, B \(and C if appropriate\).
 With optional argument ARG, scroll ARG lines; otherwise scroll by nearly
-the height of window-A."
+the one half of the height of window-A."
   (interactive "P")
   (ediff-barf-if-not-control-buffer)
   
@@ -1327,7 +1312,7 @@ the height of window-A."
                (or (not ediff-3way-job)
                    (ediff-buffer-live-p ediff-buffer-C))
                ))
-      (error "You've killed an essential Ediff buffer---Please quit Ediff"))
+      (error ediff-KILLED-VITAL-BUFFER))
       
   (ediff-operate-on-windows
    (if (memq last-command-char '(?v ?\C-v))
@@ -1371,7 +1356,7 @@ the width of the A/B/C windows."
                (or (not ediff-3way-job)
                    (ediff-buffer-live-p ediff-buffer-C))
                ))
-      (error "You've killed an essential Ediff buffer---Please quit Ediff"))
+      (error ediff-KILLED-VITAL-BUFFER))
     
   (ediff-operate-on-windows
    (if (= last-command-char ?<)
@@ -1405,7 +1390,7 @@ the width of the A/B/C windows."
 
 
 ;;BEG, END show the region to be positioned.
-;;JOB-NAME holds ediff-job-name. Ediff-windows job positions regions
+;;JOB-NAME holds ediff-job-name. The ediff-windows job positions regions
 ;;differently. 
 (defun ediff-position-region (beg end pos job-name)
   (if (> end (point-max))
@@ -1428,7 +1413,7 @@ the width of the A/B/C windows."
                                (move-to-window-line lines)
                                (point)))
                       ;; `end' may be beyond the window bottom, so check
-                      ;; that we are making progres
+                      ;; that we are making progress
                       (< prev-point (point)))
            (setq prev-point (point))
            (setq lines (1+ lines)))
@@ -1473,33 +1458,43 @@ the width of the A/B/C windows."
       )))
 
 
+;; region size coefficient is a coefficient by which to adjust scrolling
+;; up/down of the window displaying buffer of type BUFTYPE.
+;; The purpose of this coefficient is to make the windows scroll in sync, so
+;; that it won't happen that one diff region is scrolled off while the other is
+;; still seen.
+;;
+;; If the difference region is invalid, the coefficient is 1
 (defun ediff-get-region-size-coefficient (buf-type op &optional n ctl-buf)
   (ediff-eval-in-buffer (or ctl-buf ediff-control-buffer)
-    (let* ((func (cond ((eq op 'scroll-down) 'ediff-get-lines-to-region-start)
-                      ((eq op 'scroll-up) 'ediff-get-lines-to-region-end)
-                      (t '(lambda (a b c) 0))))
-          (max-lines (max (funcall func 'A n ctl-buf)
-                          (funcall func 'B n ctl-buf)
-                          (if (ediff-buffer-live-p ediff-buffer-C)
-                              (funcall func 'C n ctl-buf)
-                            0))))
-      ;; this covers the horizontal coefficient as well:
-      ;; if max-lines = 0 then coef = 1
-      (if (> max-lines 0)
-         (/ (+ (funcall func buf-type n ctl-buf) 0.0)
-            (+ max-lines 0.0))
-       1)
-      )))
+    (if (ediff-valid-difference-p n)
+       (let* ((func (cond ((eq op 'scroll-down)
+                           'ediff-get-lines-to-region-start)
+                          ((eq op 'scroll-up)
+                           'ediff-get-lines-to-region-end)
+                          (t '(lambda (a b c) 0))))
+              (max-lines (max (funcall func 'A n ctl-buf)
+                              (funcall func 'B n ctl-buf)
+                              (if (ediff-buffer-live-p ediff-buffer-C)
+                                  (funcall func 'C n ctl-buf)
+                                0))))
+         ;; this covers the horizontal coefficient as well:
+         ;; if max-lines = 0 then coef = 1
+         (if (> max-lines 0)
+             (/ (+ (funcall func buf-type n ctl-buf) 0.0)
+                (+ max-lines 0.0))
+           1))
+      1)))
 
 
 (defun ediff-next-difference (&optional arg)
   "Advance to the next difference. 
-With a prefix argument, go back that many differences."
-  (interactive "P")
+With a prefix argument, go forward that many differences."
+  (interactive "p")
   (ediff-barf-if-not-control-buffer)
   (if (< ediff-current-difference ediff-number-of-differences)
       (let ((n (min ediff-number-of-differences
-                   (+ ediff-current-difference (if arg arg 1))))
+                   (+ ediff-current-difference arg)))
            regexp-skip)
            
        (or (>= n ediff-number-of-differences)
@@ -1532,10 +1527,10 @@ With a prefix argument, go back that many differences."
 (defun ediff-previous-difference (&optional arg)
   "Go to the previous difference. 
 With a prefix argument, go back that many differences."
-  (interactive "P")
+  (interactive "p")
   (ediff-barf-if-not-control-buffer)
   (if (> ediff-current-difference -1)
-      (let ((n (max -1 (- ediff-current-difference (if arg arg 1))))
+      (let ((n (max -1 (- ediff-current-difference arg)))
            regexp-skip)
            
        (or (< n 0)
@@ -1565,28 +1560,89 @@ With a prefix argument, go back that many differences."
     (ediff-visible-region)
     (error "At beginning of the difference list")))
 
+;; The diff number is as perceived by the user (i.e., 1+ the internal
+;; representation)
 (defun ediff-jump-to-difference (difference-number)
-  "Go to the difference specified as a prefix argument."
+  "Go to the difference specified as a prefix argument.
+If the prefix is negative, count differences from the end."
   (interactive "p")
   (ediff-barf-if-not-control-buffer)
-  (setq difference-number (1- difference-number))
+  (setq difference-number
+       (cond ((< difference-number 0)
+              (+ ediff-number-of-differences difference-number))
+             ((> difference-number 0) (1- difference-number))
+             (t -1)))
+  ;; -1 is allowed by ediff-unselect-and-select-difference --- it is the
+  ;; position before the first one.
   (if (and (>= difference-number -1)
-          (< difference-number (1+ ediff-number-of-differences)))
+          (<= difference-number ediff-number-of-differences))
       (ediff-unselect-and-select-difference difference-number)
-    (error "Bad difference number, %d" difference-number)))
+    (error ediff-BAD-DIFF-NUMBER
+          this-command (1+ difference-number) ediff-number-of-differences)))
       
-(defun ediff-jump-to-difference-at-point ()
+(defun ediff-jump-to-difference-at-point (arg)
   "Go to difference closest to the point in buffer A, B, or C.
-The type of buffer depends on last command character \(a, b, or c\) that
-invoked this command."
-  (interactive)
+The buffer depends on last command character \(a, b, or c\) that invoked this
+command. For instance, if the command was `ga' then the point value in buffer A
+is used.
+With a prefix argument, synchronize all files around the current point position
+in the specified buffer."
+  (interactive "P")
   (ediff-barf-if-not-control-buffer)
-  (let ((buf-type (ediff-char-to-buftype last-command-char)))
-    (ediff-jump-to-difference (ediff-diff-at-point buf-type))))
+  (let* ((buf-type (ediff-char-to-buftype last-command-char))
+        (buffer (ediff-get-buffer buf-type))
+        (pt (ediff-eval-in-buffer buffer (point)))
+        (diff-no (ediff-diff-at-point buf-type nil (if arg 'after)))
+        (past-last-diff (< ediff-number-of-differences diff-no))
+        (beg (if past-last-diff
+                 (ediff-eval-in-buffer buffer (point-max))
+               (ediff-get-diff-posn buf-type 'beg (1- diff-no))))
+        ctl-wind wind-A wind-B wind-C
+        shift)
+    (if past-last-diff
+       (ediff-jump-to-difference -1)
+      (ediff-jump-to-difference diff-no))
+    (setq ctl-wind (selected-window)
+         wind-A ediff-window-A
+         wind-B ediff-window-B
+         wind-C ediff-window-C)
+    (if arg
+       (progn
+         (ediff-eval-in-buffer buffer
+           (setq shift (- beg pt)))
+         (select-window wind-A)
+         (if past-last-diff (goto-char (point-max)))
+         (condition-case nil
+             (backward-char shift) ; noerror, if beginning of buffer
+           (error))
+         (recenter)
+         (select-window wind-B)
+         (if past-last-diff (goto-char (point-max)))
+         (condition-case nil
+             (backward-char shift) ; noerror, if beginning of buffer
+           (error))
+         (recenter)
+         (if (window-live-p wind-C)
+             (progn
+               (select-window wind-C)
+               (if past-last-diff (goto-char (point-max)))
+               (condition-case nil
+                   (backward-char shift) ; noerror, if beginning of buffer
+                 (error))
+               (recenter)
+               ))
+         (select-window ctl-wind)
+         ))
+    ))
        
       
 ;; find region most related to the current point position (or POS, if given)
-(defun ediff-diff-at-point (buf-type &optional pos)
+;; returns diff number as seen by the user (i.e., 1+ the internal
+;; representation) 
+;; The optional argument WHICH-DIFF can be `after' or `before'. If `after',
+;; find the diff after the point. If `before', find the diff before the
+;; point. If the point is inside a diff, return that diff.
+(defun ediff-diff-at-point (buf-type &optional pos which-diff)
   (let ((buffer (ediff-get-buffer buf-type))
        (ctl-buffer ediff-control-buffer)
        (max-dif-num (1- ediff-number-of-differences))
@@ -1607,18 +1663,26 @@ invoked this command."
              end (ediff-get-diff-posn buf-type 'end diff-no ctl-buffer))
        )
       
-     (if (< (abs (- pos prev-end))
-           (abs (- pos beg)))
-        diff-no
-       (1+ diff-no)) ; jump-to-diff works with diff nums higher by 1
+      ;; boost diff-no by 1, if past the last diff region
+      (if (and (memq which-diff '(after before))
+              (> pos beg) (= diff-no max-dif-num))
+         (setq diff-no (1+ diff-no)))
+
+      (cond ((eq which-diff 'after) (1+ diff-no))
+           ((eq which-diff 'before) diff-no)
+           ((< (abs (count-lines pos (max 1 prev-end)))
+               (abs (count-lines pos (max 1 beg))))
+            diff-no)       ; choose prev difference
+           (t
+            (1+ diff-no))) ; choose next difference
      )))
 
 \f
 ;;; Copying diffs.
 
 (defun ediff-diff-to-diff (arg &optional keys)
-  "Copy buffer-X'th diff to buffer Y \(X,Y are A, B, or C\).
-If numerical prefix argument, copy this diff specified in the arg.
+  "Copy buffer-X'th difference region to buffer Y \(X,Y are A, B, or C\).
+If numerical prefix argument, copy the difference specified in the arg.
 Otherwise, copy the difference given by `ediff-current-difference'.
 This command assumes it is bound to a 2-character key sequence, `ab', `ba',
 `ac', etc., which is used to determine the types of buffers to be used for
@@ -1630,8 +1694,9 @@ determine the source and the target buffers instead of the command keys."
   (interactive "P")
   (ediff-barf-if-not-control-buffer)
   (or keys (setq keys (this-command-keys)))
-  (if arg
-      (ediff-jump-to-difference arg))
+  (if (eq arg '-) (setq arg -1)) ; translate neg arg to -1
+  (if (numberp arg) (ediff-jump-to-difference arg))
+
   (let* ((key1 (aref keys 0))
         (key2 (aref keys 1))
         (char1 (if (and ediff-xemacs-p (eventp key1)) (event-key key1) key1))
@@ -1643,6 +1708,43 @@ determine the source and the target buffers instead of the command keys."
     ;; recenter with rehighlighting, but no messages
     (ediff-recenter)))
 
+(defun ediff-copy-A-to-B (arg)
+  "Copy ARGth difference region from buffer A to B.
+ARG is a prefix argument. If nil, copy the current difference region."
+  (interactive "P")
+  (ediff-diff-to-diff arg "ab"))
+
+(defun ediff-copy-B-to-A (arg)
+  "Copy ARGth difference region from buffer B to A.
+ARG is a prefix argument. If nil, copy the current difference region."
+  (interactive "P")
+  (ediff-diff-to-diff arg "ba"))
+
+(defun ediff-copy-A-to-C (arg)
+  "Copy ARGth difference region from buffer A to buffer C.
+ARG is a prefix argument. If nil, copy the current difference region."
+  (interactive "P")
+  (ediff-diff-to-diff arg "ac"))
+
+(defun ediff-copy-B-to-C (arg)
+  "Copy ARGth difference region from buffer B to buffer C.
+ARG is a prefix argument. If nil, copy the current difference region."
+  (interactive "P")
+  (ediff-diff-to-diff arg "bc"))
+
+(defun ediff-copy-C-to-B (arg)
+  "Copy ARGth difference region from buffer C to B.
+ARG is a prefix argument. If nil, copy the current difference region."
+  (interactive "P")
+  (ediff-diff-to-diff arg "cb"))
+
+(defun ediff-copy-C-to-A (arg)
+  "Copy ARGth difference region from buffer C to A.
+ARG is a prefix argument. If nil, copy the current difference region."
+  (interactive "P")
+  (ediff-diff-to-diff arg "ca"))
+
+
 
 ;; Copy diff N from FROM-BUF-TYPE \(given as A, B or C\) to TO-BUF-TYPE.
 ;; If optional DO-NOT-SAVE is non-nil, do not save the old value of the
@@ -1672,10 +1774,8 @@ determine the source and the target buffers instead of the command keys."
                         n to-buf-type ctrl-buf
                         reg-to-delete-beg reg-to-delete-end))
     
-    (setq ediff-disturbed-overlays nil) ; clear before use
-    
     (if (string= reg-to-delete reg-to-copy)
-       (setq saved-p nil)     ; refuse to copy identical buffers
+       (setq saved-p nil) ; don't copy identical buffers
       ;; seems ok to copy
       (if (or batch-invocation (ediff-test-save-region n to-buf-type))
          (condition-case conds
@@ -1683,30 +1783,12 @@ determine the source and the target buffers instead of the command keys."
                (ediff-eval-in-buffer to-buf
                  ;; to prevent flags from interfering if buffer is writable
                  (let ((inhibit-read-only (null buffer-read-only)))
-                   ;; these two insert a dummy char to overcome a bug in
-                   ;; XEmacs, which sometimes prevents 0-length extents
-                   ;; from sensing insertion at its end-points.
-                   ;; (need to check if 19.12 still has the bug)
-                   (if ediff-xemacs-p
-                       (progn
-                         (goto-char reg-to-delete-end)
-                         (insert-before-markers "@")))
                    
                    (goto-char reg-to-delete-end)
-                   (insert-before-markers reg-to-copy)
+                   (insert reg-to-copy)
                    
-                   ;; delete the dummy char "@"
-                   (if ediff-xemacs-p
-                       (delete-char 1))
-                   
-                   (if ediff-xemacs-p
-                       (if (> reg-to-delete-end reg-to-delete-beg)
-                           (kill-region reg-to-delete-beg
-                                        reg-to-delete-end))
-                     (if (> reg-to-delete-end reg-to-delete-beg)
-                         (kill-region reg-to-delete-beg reg-to-delete-end)
-                       (ediff-move-disturbed-overlays reg-to-delete-beg)
-                       ))
+                   (if (> reg-to-delete-end reg-to-delete-beg)
+                       (kill-region reg-to-delete-beg reg-to-delete-end))
                    ))
                (or batch-invocation
                    (setq 
@@ -1796,38 +1878,20 @@ determine the source and the target buffers instead of the command keys."
        (setq saved-diff (cdr saved-rec))
       (if (> ediff-number-of-differences 0)
          (error "Nothing saved for diff %d in buffer %S" (1+ n) buf-type)
-       (error "No differences found")))
+       (error ediff-NO-DIFFERENCES)))
     
     (setq reg-beg (ediff-get-diff-posn buf-type 'beg n ediff-control-buffer))
     (setq reg-end (ediff-get-diff-posn buf-type 'end n ediff-control-buffer))
-    (setq ediff-disturbed-overlays nil) ; clear before use
     
     (condition-case conds
        (ediff-eval-in-buffer buf
          (let ((inhibit-read-only (null buffer-read-only)))
-           ;; these two insert a dummy char to overcome a bug in XEmacs,
-           ;; which sometimes prevents 0-length extents from sensing
-           ;; insertion at its end-points.
-           ;; (need to check if 19.12 still has the bug)
-           (if ediff-xemacs-p
-               (progn
-                 (goto-char reg-end)
-                 (insert-before-markers "@")))
            
            (goto-char reg-end)
-           (insert-before-markers saved-diff)
+           (insert saved-diff)
            
-           ;; delete dummy char
-           (if ediff-xemacs-p
-               (delete-char 1))
-           
-           (if ediff-xemacs-p
-               (if (> reg-end reg-beg)
-                   (kill-region reg-beg reg-end))
-             (if (> reg-end reg-beg)
-                 (kill-region reg-beg reg-end)
-               (ediff-move-disturbed-overlays reg-beg)
-               ))
+           (if (> reg-end reg-beg)
+               (kill-region reg-beg reg-end))
            
            (setq recovered t)
            ))
@@ -1859,19 +1923,25 @@ determine the source and the target buffers instead of the command keys."
       
 (defun ediff-restore-diff  (arg &optional key)
   "Restore ARGth diff from `ediff-killed-diffs-alist'.
-ARG is a prefix argument.  If ARG is nil, restore current-difference.
-
+ARG is a prefix argument.  If ARG is nil, restore the current-difference.
 If the second optional argument, a character, is given, use it to
 determine the target buffer instead of last-command-char"
   (interactive "P")
   (ediff-barf-if-not-control-buffer)
-  (if arg
+  (if (numberp arg)
       (ediff-jump-to-difference arg))
   (ediff-pop-diff ediff-current-difference 
                  (ediff-char-to-buftype (or key last-command-char)))
   ;; recenter with rehighlighting, but no messages
   (let (ediff-verbose-p)
     (ediff-recenter)))
+
+(defun ediff-restore-diff-in-merge-buffer (arg)
+  "Restore ARGth diff in the merge buffer.
+ARG is a prefix argument. If nil, restore the current diff."
+  (interactive "P")
+  (ediff-restore-diff arg ?c))
+  
   
 (defun ediff-toggle-regexp-match ()
   "Toggle between focusing and hiding of difference regions that match
@@ -1884,7 +1954,7 @@ a regular expression typed in by the user."
        msg-connective alt-msg-connective alt-connective)
     (cond
      ((or (and (eq ediff-skip-diff-region-function
-                  'ediff-focus-on-regexp-matches-function)
+                  ediff-focus-on-regexp-matches-function)
               (eq last-command-char ?f))
          (and (eq ediff-skip-diff-region-function
                   ediff-hide-regexp-matches-function)
@@ -1997,25 +2067,25 @@ the number seen by the user."
             (regex-B ediff-regexp-focus-B)
             (regex-C ediff-regexp-focus-C)
             (reg-A-match (ediff-eval-in-buffer ediff-buffer-A
-                           (goto-char (ediff-get-diff-posn 'A 'beg n ctl-buf))
-                           (re-search-forward
-                            regex-A
-                            (ediff-get-diff-posn 'A 'end n ctl-buf)
-                            t)))
+                           (save-restriction
+                             (narrow-to-region
+                              (ediff-get-diff-posn 'A 'beg n ctl-buf)
+                              (ediff-get-diff-posn 'A 'end n ctl-buf))
+                             (goto-char (point-min))
+                             (re-search-forward regex-A nil t))))
             (reg-B-match (ediff-eval-in-buffer ediff-buffer-B
-                           (goto-char (ediff-get-diff-posn 'B 'beg n ctl-buf))
-                           (re-search-forward
-                            regex-B
-                            (ediff-get-diff-posn 'B 'end n ctl-buf)
-                            t)))
+                           (save-restriction
+                             (narrow-to-region
+                              (ediff-get-diff-posn 'B 'beg n ctl-buf)
+                              (ediff-get-diff-posn 'B 'end n ctl-buf))
+                             (re-search-forward regex-B nil t))))
             (reg-C-match (if ediff-3way-comparison-job
                              (ediff-eval-in-buffer ediff-buffer-C
-                               (goto-char
-                                (ediff-get-diff-posn 'C 'beg n ctl-buf))
-                               (re-search-forward
-                                regex-C
-                                (ediff-get-diff-posn 'C 'end n ctl-buf)
-                                t)))))
+                               (save-restriction
+                                 (narrow-to-region
+                                  (ediff-get-diff-posn 'C 'beg n ctl-buf)
+                                  (ediff-get-diff-posn 'C 'end n ctl-buf))
+                                 (re-search-forward regex-C nil t))))))
        (not (eval (if ediff-3way-comparison-job
                       (list ediff-focus-regexp-connective
                             reg-A-match reg-B-match reg-C-match)
@@ -2038,25 +2108,27 @@ the number seen by the user."
             (regex-B ediff-regexp-hide-B)
             (regex-C ediff-regexp-hide-C)
             (reg-A-match (ediff-eval-in-buffer ediff-buffer-A
-                           (goto-char (ediff-get-diff-posn 'A 'beg n ctl-buf))
-                           (re-search-forward
-                            regex-A
-                            (ediff-get-diff-posn 'A 'end n ctl-buf)
-                            t)))
+                           (save-restriction
+                             (narrow-to-region
+                              (ediff-get-diff-posn 'A 'beg n ctl-buf)
+                              (ediff-get-diff-posn 'A 'end n ctl-buf))
+                             (goto-char (point-min))
+                             (re-search-forward regex-A nil t))))
             (reg-B-match (ediff-eval-in-buffer ediff-buffer-B
-                           (goto-char (ediff-get-diff-posn 'B 'beg n ctl-buf))
-                           (re-search-forward
-                            regex-B
-                            (ediff-get-diff-posn 'B 'end n ctl-buf)
-                            t)))
+                           (save-restriction
+                             (narrow-to-region
+                              (ediff-get-diff-posn 'B 'beg n ctl-buf)
+                              (ediff-get-diff-posn 'B 'end n ctl-buf))
+                             (goto-char (point-min))
+                             (re-search-forward regex-B nil t))))
             (reg-C-match (if ediff-3way-comparison-job
                              (ediff-eval-in-buffer ediff-buffer-C
-                               (goto-char
-                                (ediff-get-diff-posn 'C 'beg n ctl-buf))
-                               (re-search-forward
-                                regex-C
-                                (ediff-get-diff-posn 'C 'end n ctl-buf)
-                                t)))))
+                               (save-restriction
+                                 (narrow-to-region
+                                  (ediff-get-diff-posn 'C 'beg n ctl-buf)
+                                  (ediff-get-diff-posn 'C 'end n ctl-buf))
+                                 (goto-char (point-min))
+                                 (re-search-forward regex-C nil t))))))
        (eval (if ediff-3way-comparison-job
                  (list ediff-hide-regexp-connective
                        reg-A-match reg-B-match reg-C-match)
@@ -2079,13 +2151,13 @@ If it is t, they will be preserved unconditionally. A prefix argument,
 temporarily reverses the meaning of this variable."
   (interactive "P")
   (ediff-barf-if-not-control-buffer)
-  (if (prog1
-         (y-or-n-p
-          (format "Quit this Ediff session%s? "
-                  (if (ediff-buffer-live-p ediff-meta-buffer)
-                      " & show containing session group" "")))
-       (message ""))
-      (ediff-really-quit reverse-default-keep-variants)))
+  (if (y-or-n-p (format "Quit this Ediff session%s? "
+                       (if (ediff-buffer-live-p ediff-meta-buffer)
+                           " & show containing session group" "")))
+      (progn
+       (message "")
+       (ediff-really-quit reverse-default-keep-variants))
+    (message "")))
 
 
 ;; Perform the quit operations.
@@ -2203,7 +2275,6 @@ temporarily reverses the meaning of this variable."
     (ediff-kill-buffer-carefully ediff-msg-buffer)
     (ediff-kill-buffer-carefully ediff-debug-buffer)
 
-    ;;(redraw-display)
     (if (and (ediff-window-display-p) (frame-live-p ctl-frame))
        (delete-frame ctl-frame))
     (ediff-kill-buffer-carefully ctl-buf)
@@ -2275,7 +2346,7 @@ buffer in another session as well."
         (buf-A-wind (ediff-get-visible-buffer-window buf-A))
         (buf-B-wind (ediff-get-visible-buffer-window buf-B))
         (buf-C-wind (ediff-get-visible-buffer-window buf-C))
-        (buf-patch ediff-patch-buf)
+        (buf-patch  ediff-patchbufer)
         (buf-patch-diag ediff-patch-diagnostics)
         (buf-err  ediff-error-buffer)
         (buf-diff ediff-diff-buffer)
@@ -2333,7 +2404,8 @@ Hit \\[ediff-recenter] to reset the windows afterward."
   (ediff-barf-if-not-control-buffer)
   (save-excursion
     (ediff-skip-unsuitable-frames))
-  (with-output-to-temp-buffer " *ediff-info*"
+  (with-output-to-temp-buffer ediff-msg-buffer
+    (raise-frame (selected-frame))
     (princ (ediff-version))
     (princ "\n\n")
     (ediff-eval-in-buffer ediff-buffer-A
@@ -2385,13 +2457,16 @@ Hit \\[ediff-recenter] to reset the windows afterward."
                              ediff-number-of-differences) 'end)
                         (t (1+ ediff-current-difference)))))
 
-    (cond (ediff-ignore-similar-regions
-          (princ "\nSkipping regions that differ only in white space & line breaks"))
-         (t 
-          (princ "\nNot skipping regions that differ in white space & line breaks")))
+    (princ
+     (format "\n%s regions that differ only in white space & line breaks"
+            (if ediff-ignore-similar-regions
+                "Skipping" "Not skipping")))
+    (if (and ediff-merge-job ediff-show-clashes-only)
+       (princ
+        "\nFocusing on regions where both buffers differ from the ancestor"))
     
     (cond ((eq ediff-skip-diff-region-function 'ediff-show-all-diffs)
-          (princ "\nSelective browsing by regexp is off.\n"))
+          (princ "\nSelective browsing by regexp is off\n"))
          ((eq ediff-skip-diff-region-function
               ediff-hide-regexp-matches-function)
           (princ
@@ -2421,31 +2496,6 @@ Hit \\[ediff-recenter] to reset the windows afterward."
   (if (window-live-p ediff-control-window)
       (select-window ediff-control-window)))
     
-(defun ediff-documentation ()
-  "Jump to Ediff's Info file."
-  (interactive)
-  (let ((ctl-window ediff-control-window)
-       (ctl-buf ediff-control-buffer))
-
-    (ediff-skip-unsuitable-frames)
-    (condition-case nil
-       (progn
-         (pop-to-buffer (get-buffer-create "*info*"))
-         (info "ediff.info")
-         (message "Type `i' to search for a specific topic"))
-      (error (beep 1)
-            (with-output-to-temp-buffer " *ediff-info*"
-              (princ (format "
-The Info file for Ediff does not seem to be installed.
-
-This file is part of the distribution of %sEmacs.
-Please contact your system administrator. "
-                             (if ediff-xemacs-p "X" ""))))
-            (if (window-live-p ctl-window)
-                (progn
-                  (select-window ctl-window)
-                  (set-window-buffer ctl-window ctl-buf)))))))
-    
 
 
 \f
@@ -2459,7 +2509,7 @@ Please contact your system administrator. "
           (ediff-buffer-live-p ediff-buffer-B)
           (ediff-valid-difference-p n))
       (progn
-       (if (and (ediff-window-display-p) ediff-use-faces)
+       (if (and (ediff-has-face-support-p) ediff-use-faces)
            (progn
              (ediff-highlight-diff n)
              (setq ediff-highlighting-style 'face))
@@ -2486,7 +2536,7 @@ Please contact your system administrator. "
 (defun ediff-unselect-difference (n)
   (if (ediff-valid-difference-p n)
       (progn 
-       (cond ((and (ediff-window-display-p) ediff-use-faces)
+       (cond ((and (ediff-has-face-support-p) ediff-use-faces)
               (ediff-unhighlight-diff))
              ((eq ediff-highlighting-style 'ascii)
               (ediff-remove-flags-from-buffer
@@ -2564,13 +2614,14 @@ Please contact your system administrator. "
   (let (f)
     (setq f (expand-file-name
             (read-file-name
-             (format "%s%s: "
+             (format "%s%s "
                      prompt
-                     (if default-file
-                         (concat " (default " default-file ")")
-                       ""))
+                     (cond (default-file
+                             (concat " (default " default-file "):"))
+                           ;;((string-match "[?:!,;][ \t]*$" prompt) "")
+                           (t (concat " (default " default-dir "):"))))
              default-dir
-             default-file
+             (or default-file default-dir)
              t  ; must match, no-confirm
              (if default-file (file-name-directory default-file))
              )
@@ -2585,18 +2636,35 @@ Please contact your system administrator. "
                 (file-name-nondirectory default-file) f)))
     f)) 
   
-;; If `prefix' is given, then it is used as a prefix for the temp file
-;; name. Otherwise, `ediff_' is used. If `file' is given, use this
+;; If PREFIX is given, then it is used as a prefix for the temp file
+;; name. Otherwise, `ediff_' is used. If FILE is given, use this
 ;; file and don't create a new one.
+;; On MS-DOS, make sure the prefix isn't longer than 7 characters, or
+;; else `make-temp-name' isn't guaranteed to return a unique filename.
 ;; Also, save buffer from START to END in the file.
 ;; START defaults to (point-min), END to (point-max)
 (defun ediff-make-temp-file (buff &optional prefix given-file start end)
-  (let ((f (or given-file
-              (make-temp-name (concat
-                               ediff-temp-file-prefix
-                               (if prefix
-                                   (concat prefix "_")
-                                   "ediff_"))))))
+  (let ((p (or prefix "ediff"))
+       f)
+    (if (and (eq system-type 'ms-dos) (> (length p) 7))
+       (setq p (substring p 0 7)))
+
+    (setq f (concat ediff-temp-file-prefix p)
+         f (cond (given-file)
+                 ((find-file-name-handler f 'find-file-noselect)
+                  ;; to thwart file handlers in write-region, e.g., if file
+                  ;; name ends with .Z or .gz
+                  ;; This is needed so that patches produced by ediff will
+                  ;; have more meaningful names
+                  (make-temp-name f))
+                 ;; Prefix is most often the same as the file name for the
+                 ;; variant. Here we are trying to use the original file name
+                 ;; but in the temp directory.
+                 ((and prefix (not (file-exists-p f))) f)
+                 ;; If a file with the orig name exists, add some random stuff
+                 ;; to it.
+                 (t (make-temp-name f))))
+    
     ;; create the file
     (ediff-eval-in-buffer buff
       (write-region (if start start (point-min))
@@ -2623,9 +2691,7 @@ Please contact your system administrator. "
 ;; file on disk, and attempt to remedy the situation if not.
 ;; Signal an error if we can't make them the same, or the user doesn't want
 ;; to do what is necessary to make them the same.
-;; If file has file handlers (indicated by the optional arg), then we
-;; offer to instead of saving. This is one difference with Emerge. 
-;; Another is that we always offer to revert obsolete files, whether they
+;; Also, Ediff always offers to revert obsolete buffers, whether they
 ;; are modified or not.
 (defun ediff-verify-file-buffer (&optional file-magic)
   ;; First check if the file has been modified since the buffer visited it.
@@ -2633,21 +2699,19 @@ Please contact your system administrator. "
       (if (buffer-modified-p)
          ;; If buffer is not obsolete and is modified, offer to save
          (if (yes-or-no-p 
-              (format "Buffer out of sync with visited file. %s file %s? "
-                      (if file-magic "Revert" "Save")
+              (format "Buffer out of sync with visited file. Save file %s? "
                       buffer-file-name))
-             (if (not file-magic)
+             (condition-case nil
                  (save-buffer)
-               ;; for some reason, file-name-handlers append instead of
-               ;; replacing, so we have to erase first.
-               (erase-buffer)
-               (revert-buffer t t))
-           (error "Buffer out of sync for file %s" buffer-file-name))
+               (error
+                (beep)
+                (message "Couldn't save %s" buffer-file-name)))
+           (error "Buffer is out of sync for file %s" buffer-file-name))
        ;; If buffer is not obsolete and is not modified, do nothing
        nil)
     ;; If buffer is obsolete, offer to revert
     (if (yes-or-no-p
-        (format "Buffer out of sync with visited file. Revert file %s? "
+        (format "Buffer is out of sync with visited file. REVERT file %s? "
                 buffer-file-name))
        (progn
          (if file-magic
@@ -2656,49 +2720,6 @@ Please contact your system administrator. "
       (error "Buffer out of sync for file %s" buffer-file-name))))
 
 
-
-;; It would be nice to use these two functions as hooks instead of
-;; ediff-insert-in-front and ediff-move-disturbed-overlays.
-;; However, Emacs has a bug that causes BEG and END, below, to be
-;; the same, i.e., the end of inserted text is not passed correctly.
-;; Since the overlay doesn't move when these hooks run, 
-;; there is no way to correctly determine the new (desired) position of
-;; the overlay end.
-;; Either this bug is fixed, or (better) use sticky overlays when they will
-;; be implemented in Emacs, like they are in XEmacs.
-;;(defun ediff-capture-inserts-in-front (overl flag beg end &optional len)
-;;  (if (and flag (ediff-overlay-get overl 'ediff-diff-num))
-;;      (ediff-move-overlay overl beg (ediff-overlay-end overl))
-;;    ))
-;;
-;;(defun ediff-capture-inserts-behind (overl flag beg end &optional len)
-;;  (if (and flag (ediff-overlay-get overl 'ediff-diff-num))
-;;      (ediff-move-overlay overl (ediff-overlay-start overl) (point))
-;;  ))
-  
-;; to be deleted in due time
-;; Capture overlays that had insertions in the front.
-;; Called when overlay OVERL gets insertion in front.
-(defun ediff-insert-in-front (overl &optional flag beg end length)
-  (if (ediff-overlay-get overl 'ediff-diff-num)
-      (setq ediff-disturbed-overlays
-           (cons overl ediff-disturbed-overlays))))
-  
-  
-;; to be deleted in due time
-;; We can't move overlays directly in insert-in-front-hooks
-;; because when diff is highlighted  with ascii flags, they will  disturb
-;; overlays and so they will be included in them, which we don't want.
-(defun  ediff-move-disturbed-overlays (posn)  
-  (mapcar (function (lambda (overl)
-                      (ediff-move-overlay overl
-                                          posn
-                                          (ediff-overlay-end overl))
-                      ))
-         ediff-disturbed-overlays)
-  (setq ediff-disturbed-overlays nil))
-  
-  
 (defun ediff-save-buffer (arg)
   "Safe way of saving buffers A, B, C, and the diff output.
 `wa' saves buffer A, `wb' saves buffer B, `wc' saves buffer C,
@@ -2728,16 +2749,26 @@ Without an argument, it saves customized diff argument, if available
     (save-buffer)))
 
 (defun ediff-compute-custom-diffs-maybe ()
-  (or ediff-3way-job
-      (let ((file-A (ediff-make-temp-file ediff-buffer-A))
-           (file-B (ediff-make-temp-file ediff-buffer-B)))
-       (or (ediff-buffer-live-p ediff-custom-diff-buffer)
-           (setq ediff-custom-diff-buffer
-                 (get-buffer-create
-                  (ediff-unique-buffer-name "*ediff-custom-diff" "*"))))
-       (ediff-exec-process
-        ediff-custom-diff-program ediff-custom-diff-buffer 'synchronize
-        ediff-custom-diff-options file-A file-B))))
+  (let ((buf-A-file-name (buffer-file-name ediff-buffer-A))
+       (buf-B-file-name (buffer-file-name ediff-buffer-B))
+       file-A file-B)
+    (if (stringp buf-A-file-name)
+       (setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
+    (if (stringp buf-B-file-name)
+       (setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
+    (setq file-A (ediff-make-temp-file ediff-buffer-A buf-A-file-name)
+         file-B (ediff-make-temp-file ediff-buffer-B buf-B-file-name))
+                        
+    (or (ediff-buffer-live-p ediff-custom-diff-buffer)
+       (setq ediff-custom-diff-buffer
+             (get-buffer-create
+              (ediff-unique-buffer-name "*ediff-custom-diff" "*"))))
+    (ediff-exec-process
+     ediff-custom-diff-program ediff-custom-diff-buffer 'synchronize
+     ediff-custom-diff-options file-A file-B)
+    (delete-file file-A)
+    (delete-file file-B)
+    ))
 
 (defun ediff-show-diff-output (arg)
   (interactive "P")
@@ -2831,16 +2862,17 @@ Without an argument, it saves customized diff argument, if available
     ))
 
   
+;; Returns positions of difference sectors in the BUF-TYPE buffer.
+;; BUF-TYPE should be a symbol -- `A', `B', or `C'. 
+;; POS is either `beg' or `end'--it specifies whether you want the position at
+;; the beginning of a difference or at the end.
+;; 
+;; The optional argument N says which difference (default:
+;; `ediff-current-difference'). N is the internal difference number (1- what
+;; the user sees).  The optional argument CONTROL-BUF says
+;; which control buffer is in effect in case it is not the current
+;; buffer.
 (defun ediff-get-diff-posn (buf-type pos &optional n control-buf)
-  "Returns positions of difference sectors in the BUF-TYPE buffer.
-BUF-TYPE should be a symbol--either `A' or `B'. 
-POS is either `beg' or `end'--it specifies whether you want the position at the
-beginning of a difference or at the end.
-
-The optional argument N says which difference \(default:
-`ediff-current-difference'\).  The optional argument CONTROL-BUF says
-which control buffer is in effect in case it is not the current
-buffer."
   (let (diff-overlay)
     (or control-buf
        (setq control-buf (current-buffer)))
@@ -2849,13 +2881,12 @@ buffer."
       (or n  (setq n ediff-current-difference))
       (if (or (< n 0) (>= n ediff-number-of-differences))
          (if (> ediff-number-of-differences 0)
-             (error "There is no diff %d. Valid diffs are 1 to %d"
-                    (1+ n) ediff-number-of-differences)
-           (error "No differences found")))
+             (error ediff-BAD-DIFF-NUMBER
+                    this-command (1+ n) ediff-number-of-differences)
+           (error ediff-NO-DIFFERENCES)))
       (setq diff-overlay (ediff-get-diff-overlay n buf-type)))
     (if (not (ediff-buffer-live-p (ediff-overlay-buffer diff-overlay)))
-       (error
-        "You have killed an essential Ediff buffer---Please exit Ediff"))
+       (error ediff-KILLED-VITAL-BUFFER))
     (if (eq pos 'beg)
        (ediff-overlay-start diff-overlay)
       (ediff-overlay-end diff-overlay))
@@ -2907,14 +2938,14 @@ buffer."
        ;; current difference region
        (ediff-set-overlay-face
         overlay
-        (if (and (ediff-window-display-p)
+        (if (and (ediff-has-face-support-p)
                  ediff-use-faces ediff-highlight-all-diffs)
             (ediff-background-face buf-type ediff-current-difference)))
        )))
 
 (defun ediff-unhighlight-diffs-totally-in-one-buffer (buf-type)
   (ediff-unselect-and-select-difference -1)
-  (if (and (ediff-window-display-p) ediff-use-faces)
+  (if (and (ediff-has-face-support-p) ediff-use-faces)
       (let* ((inhibit-quit t)
             (current-diff-overlay-var
              (intern (format "ediff-current-diff-overlay-%S" buf-type)))
@@ -3010,27 +3041,21 @@ Checks if overlay's buffer exists."
              (setq beg (eval beg)))
          (or (number-or-marker-p end)
              (setq end (eval end)))
-         (setq overl (ediff-make-overlay beg end buff))
+         (setq overl 
+               (if ediff-xemacs-p
+                   (make-extent beg end buff)
+                 ;; advance front and rear of the overlay
+                 (make-overlay beg end buff nil 'rear-advance)))
          
+         ;; never detach
+         (ediff-overlay-put
+          overl (if ediff-emacs-p 'evaporate 'detachable) nil)
+         ;; make vip-minibuffer-overlay open-ended
+         ;; In emacs, it is made open ended at creation time
          (if ediff-xemacs-p
              (progn
-               ;; take precautions against detached extents
-               (ediff-overlay-put overl 'detachable nil) 
-               ;; chars inserted at both ends will be inside extent
-               (ediff-overlay-put overl 'start-open nil)
-               (ediff-overlay-put overl 'end-open nil))
-           (ediff-overlay-put overl 'evaporate nil)  ; don't detach
-           ;; doesn't work since emacs buggily doesn't call these functions
-           ;; after the change
-           ;;(ediff-overlay-put overl 'insert-in-front-hooks
-           ;;                   '(ediff-capture-inserts-in-front))
-           ;;(ediff-overlay-put overl 'insert-behind-hooks
-           ;;                   '(ediff-capture-inserts-behind))
-
-           ;; These two are not yet implemented in Emacs
-           (ediff-overlay-put overl 'rear-sticky t)
-           (ediff-overlay-put overl 'front-sticky t)
-           )
+               (ediff-overlay-put overl 'start-open nil) 
+               (ediff-overlay-put overl 'end-open nil)))
          (ediff-overlay-put overl 'ediff-diff-num 0)
          overl))))
          
@@ -3292,6 +3317,11 @@ Mail anyway? (y or n) ")
          (ediff-restore-variables ediff-protected-variables values-Ancestor)))
     ))
 
+;; save BUFFER in FILE. used in hooks.
+(defun ediff-save-buffer-in-file (buffer file)
+  (ediff-eval-in-buffer buffer
+    (write-file file)))
+
 
 ;;; Debug
 
@@ -3316,18 +3346,16 @@ Mail anyway? (y or n) ")
   "Toggle profiling Ediff commands."
   (interactive)
   (ediff-barf-if-not-control-buffer)
-  (if ediff-emacs-p
-      (make-local-variable 'post-command-hook))
-  (let ((pre-hook (if ediff-emacs-p 'pre-command-hook 'local-pre-command-hook))
-       (post-hook
-        (if ediff-emacs-p 'post-command-hook 'local-post-command-hook)))
+  (make-local-hook 'post-command-hook)
+  (let ((pre-hook 'pre-command-hook)
+       (post-hook 'post-command-hook))
     (if (not (equal ediff-command-begin-time '(0 0 0)))
        (progn (remove-hook pre-hook 'ediff-save-time)
               (remove-hook post-hook 'ediff-calc-command-time)
               (setq ediff-command-begin-time '(0 0 0))
               (message "Ediff profiling disabled"))
-      (add-hook pre-hook 'ediff-save-time t)
-      (add-hook post-hook 'ediff-calc-command-time)
+      (add-hook pre-hook 'ediff-save-time t t)
+      (add-hook post-hook 'ediff-calc-command-time nil t)
       (message "Ediff profiling enabled"))))
     
 (defun ediff-print-diff-vector (diff-vector-var)
@@ -3368,6 +3396,63 @@ Mail anyway? (y or n) ")
     (ediff-print-diff-vector (intern "ediff-difference-vector-Ancestor"))
     ))
 
+
+;;; General utilities
+
+;; this uses comparison-func to decide who is a member
+(defun ediff-member (elt lis comparison-func)
+  (while (and lis (not (funcall comparison-func (car lis) elt)))
+    (setq lis (cdr lis)))
+  lis)
+
+;; this uses comparison-func to decide who is a member, and this determines how
+;; intersection looks like
+(defun ediff-intersection (lis1 lis2 comparison-func)
+  (let ((result (list 'a)))
+    (while lis1
+      (if (ediff-member (car lis1) lis2 comparison-func)
+         (nconc result (list (car lis1))))
+      (setq lis1 (cdr lis1)))
+    (cdr result)))
+    
+
+;; eliminates duplicates using comparison-func
+(defun ediff-union (lis1 lis2 comparison-func)
+  (let ((result (list 'a)))
+    (while lis1
+      (or (ediff-member (car lis1) (cdr result) comparison-func)
+         (nconc result (list (car lis1))))
+      (setq lis1 (cdr lis1)))
+    (while lis2
+      (or (ediff-member (car lis2) (cdr result) comparison-func)
+         (nconc result (list (car lis2))))
+      (setq lis2 (cdr lis2)))
+    (cdr result)))
+
+;; eliminates duplicates using comparison-func
+(defun ediff-set-difference (lis1 lis2 comparison-func)
+  (let ((result (list 'a)))
+    (while lis1
+      (or (ediff-member (car lis1) (cdr result) comparison-func)
+         (ediff-member (car lis1) lis2 comparison-func)
+         (nconc result (list (car lis1))))
+      (setq lis1 (cdr lis1)))
+    (cdr result)))
+
+(defun ediff-copy-list (list)
+  (if (consp list)
+      ;;;(let ((res nil))
+      ;;;  (while (consp list) (push (pop list) res))
+      ;;;  (prog1 (nreverse res) (setcdr res list)))
+      (let (res elt)
+       (while (consp list)
+         (setq elt (car list)
+               res (cons elt res)
+               list (cdr list)))
+       (nreverse res))
+    (car list)))
+    
+
 ;; don't report error if version control package wasn't found
 ;;(ediff-load-version-control 'silent)