(toplevel): Provide `descr-text'.
[bpt/emacs.git] / lisp / ediff.el
index 140a80c..2db82f8 100644 (file)
@@ -1,13 +1,13 @@
 ;;; ediff.el --- a comprehensive visual interface to diff & patch
 
-;; Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02 Free Software Foundation, Inc.
 
-;; Author: Michael Kifer <kifer@cs.sunysb.edu>
+;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
 ;; Created: February 2, 1994
-;; Keywords: comparing, merging, patching, version control.
+;; Keywords: comparing, merging, patching, tools, unix
 
-(defconst ediff-version "2.75" "The current version of Ediff")
-(defconst ediff-date "October 29, 2000" "Date of last update")  
+(defconst ediff-version "2.77" "The current version of Ediff")
+(defconst ediff-date "March 5, 2002" "Date of last update")  
 
 
 ;; This file is part of GNU Emacs.
 ;; Last directory used by an Ediff command for the ancestor file.
 (defvar ediff-last-dir-ancestor nil)
 ;; Last directory used by an Ediff command as the output directory for merge.
-(defvar ediff-last-merge-autostore-dir)
+(defvar ediff-last-merge-autostore-dir nil)
 
 
 ;; Used as a startup hook to set `_orig' patch file read-only.
         (let ((current (dired-get-filename nil 'no-error))
               (marked (condition-case nil
                           (dired-get-marked-files 'no-dir)
-                        (error)))
+                        (error nil)))
               aux-list choices result)
           (or (integerp fileno) (setq fileno 0))
           (if (stringp default)
                  default-directory))
         dir-B f)
      (list (setq f (ediff-read-file-name
-                   "File A to compare" dir-A 
-                   (ediff-get-default-file-name)))
+                   "File A to compare"
+                   dir-A 
+                   (ediff-get-default-file-name)
+                   'no-dirs))
           (ediff-read-file-name "File B to compare" 
                                 (setq dir-B
                                       (if ediff-use-last-dir
                  default-directory))
         dir-B dir-C f ff)
      (list (setq f (ediff-read-file-name
-                   "File A to compare" dir-A
-                   (ediff-get-default-file-name)))
+                   "File A to compare"
+                   dir-A
+                   (ediff-get-default-file-name)
+                   'no-dirs))
           (setq ff (ediff-read-file-name "File B to compare" 
                                          (setq dir-B
                                                (if ediff-use-last-dir
 (defun ediff-files-internal (file-A file-B file-C startup-hooks job-name
                                    &optional merge-buffer-file)
   (let (buf-A buf-B buf-C)
+    (if (string= file-A file-B)
+       (error "Files A and B are the same"))
+    (if (stringp file-C)
+       (or (and (string= file-A file-C) (error "Files A and C are the same"))
+           (and (string= file-B file-C) (error "Files B and C are the same"))))
     (message "Reading file %s ... " file-A)
     ;;(sit-for 0)
     (ediff-find-file 'file-A 'buf-A 'ediff-last-dir-A 'startup-hooks)
@@ -679,8 +688,11 @@ names.  Only the files that are under revision control are taken into account."
       (or (stringp merge-autostore-dir)
          (error "%s: Directory for storing merged files must be a string"
                 jobname)))
-  (let (diffs ; var where ediff-intersect-directories returns the diff list
-       file-list meta-buf)
+  (let (;; dir-diff-struct is of the form (common-list diff-list) 
+       ;; It is a structure where ediff-intersect-directories returns
+       ;; commonalities and differences among directories
+       dir-diff-struct
+       meta-buf)
     (if (and ediff-autostore-merges
             (ediff-merge-metajob jobname)
             (not merge-autostore-dir))
@@ -706,9 +718,9 @@ names.  Only the files that are under revision control are taken into account."
                    "Directory for saving merged files = Ancestor Directory.  Sure? ")
                   (error "Directory merge aborted")))))
     
-    (setq file-list (ediff-intersect-directories 
-                    jobname 'diffs
-                    regexp dir1 dir2 dir3 merge-autostore-dir))
+    (setq dir-diff-struct (ediff-intersect-directories 
+                          jobname
+                          regexp dir1 dir2 dir3 merge-autostore-dir))
     (setq startup-hooks
          ;; this sets various vars in the meta buffer inside
          ;; ediff-prepare-meta-buffer
@@ -716,11 +728,12 @@ names.  Only the files that are under revision control are taken into account."
                   ;; tell what to do if the user clicks on a session record
                   (setq ediff-session-action-function (quote ,action))
                   ;; set ediff-dir-difference-list 
-                  (setq ediff-dir-difference-list (quote ,diffs)))
+                  (setq ediff-dir-difference-list
+                        (cdr (quote ,dir-diff-struct))))
                startup-hooks))
     (setq meta-buf (ediff-prepare-meta-buffer 
                    'ediff-filegroup-action
-                   file-list
+                   (car dir-diff-struct)
                    "*Ediff Session Group Panel"
                    'ediff-redraw-directory-group-buffer
                    jobname
@@ -828,14 +841,24 @@ If WIND-B is nil, use window next to WIND-A."
        (select-window wind-B)
        (setq beg-B (window-start)
              end-B (window-end))))
+    (setq buffer-A
+         (ediff-clone-buffer-for-window-comparison
+          buffer-A wind-A "-Window.A-")
+         buffer-B
+         (ediff-clone-buffer-for-window-comparison
+          buffer-B wind-B "-Window.B-"))
     (ediff-regions-internal
      buffer-A beg-A end-A buffer-B beg-B end-B
      startup-hooks job-name word-mode nil)))
      
+
 ;;;###autoload
 (defun ediff-regions-wordwise (buffer-A buffer-B &optional startup-hooks)
-  "Run Ediff on a pair of regions in two different buffers.
-Regions \(i.e., point and mark\) are assumed to be set in advance.
+  "Run Ediff on a pair of regions in specified buffers.
+Regions \(i.e., point and mark\) are assumed to be set in advance except
+for the second region in the case both regions are from the same buffer.
+In such a case the user is asked to interactively establish the second
+region.
 This function is effective only for relatively small regions, up to 200
 lines.  For large regions, use `ediff-regions-linewise'."
   (interactive 
@@ -855,7 +878,11 @@ lines.  For large regions, use `ediff-regions-linewise'."
       (error "Buffer %S doesn't exist" buffer-B))
   
   
-  (let (reg-A-beg reg-A-end reg-B-beg reg-B-end)
+  (let ((buffer-A
+         (ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
+       (buffer-B
+         (ediff-clone-buffer-for-region-comparison buffer-B "-Region.B-"))
+        reg-A-beg reg-A-end reg-B-beg reg-B-end)
     (save-excursion
       (set-buffer buffer-A)
       (setq reg-A-beg (region-beginning)
@@ -871,8 +898,11 @@ lines.  For large regions, use `ediff-regions-linewise'."
      
 ;;;###autoload
 (defun ediff-regions-linewise (buffer-A buffer-B &optional startup-hooks)
-  "Run Ediff on a pair of regions in two different buffers.
-Regions \(i.e., point and mark\) are assumed to be set in advance.
+  "Run Ediff on a pair of regions in specified buffers.
+Regions \(i.e., point and mark\) are assumed to be set in advance except
+for the second region in the case both regions are from the same buffer.
+In such a case the user is asked to interactively establish the second
+region.
 Each region is enlarged to contain full lines.
 This function is effective for large regions, over 100-200
 lines.  For small regions, use `ediff-regions-wordwise'."
@@ -892,7 +922,11 @@ lines.  For small regions, use `ediff-regions-wordwise'."
   (if (not (ediff-buffer-live-p buffer-B))
       (error "Buffer %S doesn't exist" buffer-B))
   
-  (let (reg-A-beg reg-A-end reg-B-beg reg-B-end)
+  (let ((buffer-A
+         (ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
+       (buffer-B
+         (ediff-clone-buffer-for-region-comparison buffer-B "-Region.B-"))
+        reg-A-beg reg-A-end reg-B-beg reg-B-end)
     (save-excursion
       (set-buffer buffer-A)
       (setq reg-A-beg (region-beginning)
@@ -941,23 +975,6 @@ lines.  For small regions, use `ediff-regions-wordwise'."
       (setq beg-B (move-marker (make-marker) beg-B)
            end-B (move-marker (make-marker) end-B)))
        
-    (if (and (eq buffer-A buffer-B)
-            (or (and (< beg-A end-B) (<= beg-B beg-A))   ; b-B b-A e-B
-                (and (< beg-B end-A) (<= end-A end-B)))) ; b-B e-A e-B
-       (progn
-         (with-output-to-temp-buffer ediff-msg-buffer
-           (princ "
-You have requested to compare overlapping regions of the same buffer.
-
-In this case, Ediff's highlighting may be confusing---in the same window,
-you may see highlighted regions that belong to different regions.
-
-Continue anyway? (y/n) "))
-
-         (if (y-or-n-p "Continue anyway? ")
-             ()
-           (error "%S aborted" job-name))))
-           
     ;; make file-A
     (if word-mode
        (ediff-wordify beg-A end-A buffer-A tmp-buffer)
@@ -1009,8 +1026,10 @@ Continue anyway? (y/n) "))
                  default-directory))
         dir-B f)
      (list (setq f (ediff-read-file-name
-                   "File A to merge" dir-A
-                   (ediff-get-default-file-name)))
+                   "File A to merge"
+                   dir-A
+                   (ediff-get-default-file-name)
+                   'no-dirs))
           (ediff-read-file-name "File B to merge" 
                                 (setq dir-B
                                       (if ediff-use-last-dir
@@ -1051,8 +1070,10 @@ Continue anyway? (y/n) "))
                  default-directory))
         dir-B dir-ancestor f ff)
      (list (setq f (ediff-read-file-name
-                   "File A to merge" dir-A
-                   (ediff-get-default-file-name)))
+                   "File A to merge"
+                   dir-A
+                   (ediff-get-default-file-name)
+                   'no-dirs))
           (setq ff (ediff-read-file-name "File B to merge" 
                                          (setq dir-B
                                                (if ediff-use-last-dir
@@ -1167,7 +1188,7 @@ buffer."
     (setq rev1
          (read-string
           (format
-           "Version 1 to merge (default: %s's latest version): "
+           "Version 1 to merge (default: %s's working version): "
            (if (stringp file)
                (file-name-nondirectory file) "current buffer")))
          rev2
@@ -1191,7 +1212,7 @@ buffer."
                                            ;; buffer
                                            merge-buffer-file)
   "Run Ediff by merging two revisions of a file with a common ancestor.
-The file is the the optional FILE argument or the file visited by the current
+The file is the optional FILE argument or the file visited by the current
 buffer."
   (interactive)
   (if (stringp file) (find-file file))
@@ -1199,7 +1220,7 @@ buffer."
     (setq rev1
          (read-string
           (format
-           "Version 1 to merge (default: %s's latest version): "
+           "Version 1 to merge (default: %s's working version): "
            (if (stringp file)
                (file-name-nondirectory file) "current buffer")))
          rev2
@@ -1219,6 +1240,7 @@ buffer."
      (intern (format "ediff-%S-merge-internal" ediff-version-control-package))
      rev1 rev2 ancestor-rev startup-hooks merge-buffer-file)))
 
+;; MK: Check. This function doesn't seem to be used any more by pcvs or pcl-cvs
 ;;;###autoload
 (defun run-ediff-from-cvs-buffer (pos)
   "Run Ediff-merge on appropriate revisions of the selected file.
@@ -1255,15 +1277,19 @@ buffer. If odd -- assume it is in a file."
                              (buffer-file-name patch-buf))))
                           (t default-directory)))
     (setq source-file
-         ;; the default is the directory, not the visited file name
          (read-file-name 
           "File to patch (directory, if multifile patch): "
-          source-dir (ediff-get-default-file-name)))
+          ;; use an explicit initial file
+          source-dir nil nil (ediff-get-default-file-name)))
     (ediff-dispatch-file-patching-job patch-buf source-file)))
 
 ;;;###autoload
 (defun ediff-patch-buffer (&optional arg patch-buf)
-  "Run Ediff by patching BUFFER-NAME."
+  "Run Ediff by patching BUFFER-NAME.
+Without prefix argument: asks if the patch is in some buffer and prompts for
+the buffer or a file, depending on the answer.
+With prefix arg=1: assumes the patch is in a file and prompts for the file.
+With prefix arg=2: assumes the patch is in a buffer and prompts for the buffer."
   (interactive "P")
   (require 'ediff-ptch)
   (setq patch-buf
@@ -1273,7 +1299,7 @@ buffer. If odd -- assume it is in a file."
    patch-buf
    (read-buffer
     "Which buffer to patch? "
-    (ediff-prompt-for-patch-buffer))))
+    (current-buffer))))
   
 
 ;;;###autoload
@@ -1289,22 +1315,33 @@ buffer. If odd -- assume it is in a file."
 ;;;###autoload
 (defun ediff-revision (&optional file startup-hooks)
   "Run Ediff by comparing versions of a file.
-The file is an optional FILE argument or the file visited by the current
-buffer.  Use `vc.el' or `rcs.el' depending on `ediff-version-control-package'."
+The file is an optional FILE argument or the file entered at the prompt.
+Default: the file visited by the current buffer.
+Uses `vc.el' or `rcs.el' depending on `ediff-version-control-package'."
   ;; if buffer is non-nil, use that buffer instead of the current buffer
   (interactive "P")
-  (if (stringp file) (find-file file))
+  (if (not (stringp file))
+    (setq file
+         (ediff-read-file-name "Compare revisions for file"
+                               (if ediff-use-last-dir
+                                   ediff-last-dir-A
+                                 default-directory)
+                               (ediff-get-default-file-name)
+                               'no-dirs))) 
+  (find-file file)
+  (if (and (buffer-modified-p)
+          (y-or-n-p (message "Buffer %s is modified. Save buffer? "
+                             (buffer-name))))
+      (save-buffer (current-buffer)))
   (let (rev1 rev2)
     (setq rev1
          (read-string
-          (format "Version 1 to compare (default: %s's latest version): "
-                  (if (stringp file)
-                      (file-name-nondirectory file) "current buffer")))
+          (format "Version 1 to compare (default: %s's working version): "
+                  (file-name-nondirectory file)))
          rev2
          (read-string 
           (format "Version 2 to compare (default: %s): "
-                  (if (stringp file)
-                      (file-name-nondirectory file) "current buffer"))))
+                  (file-name-nondirectory file))))
     (ediff-load-version-control)
     (funcall
      (intern (format "ediff-%S-internal" ediff-version-control-package))
@@ -1359,6 +1396,8 @@ With optional NODE, goes to that node."
          (raise-frame (selected-frame)))
       (error (beep 1)
             (with-output-to-temp-buffer ediff-msg-buffer
+              (ediff-with-current-buffer standard-output
+                (fundamental-mode))
               (princ ediff-BAD-INFO))
             (if (window-live-p ctl-window)
                 (progn