;;; ediff.el --- a comprehensive visual interface to diff & patch
-;; Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 Free Software Foundation, Inc.
;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
;; Created: February 2, 1994
;; Keywords: comparing, merging, patching, tools, unix
-(defconst ediff-version "2.77" "The current version of Ediff")
-(defconst ediff-date "March 5, 2002" "Date of last update")
+(defconst ediff-version "2.78" "The current version of Ediff")
+(defconst ediff-date "January 25, 2003" "Date of last update")
;; This file is part of GNU Emacs.
dir-B f)
(list (setq f (ediff-read-file-name
"File A to compare"
- dir-A
+ dir-A
(ediff-get-default-file-name)
'no-dirs))
- (ediff-read-file-name "File B to compare"
+ (ediff-read-file-name "File B to compare"
(setq dir-B
(if ediff-use-last-dir
- ediff-last-dir-B
+ ediff-last-dir-B
(file-name-directory f)))
(progn
(setq file-name-history
file-name-history))
(ediff-get-default-file-name f 1)))
)))
- (ediff-files-internal file-A
+ (ediff-files-internal file-A
(if (file-directory-p file-B)
(expand-file-name
(file-name-nondirectory file-A) file-B)
nil ; file-C
startup-hooks
'ediff-files))
-
+
;;;###autoload
(defun ediff-files3 (file-A file-B file-C &optional startup-hooks)
"Run Ediff on three files, FILE-A, FILE-B, and FILE-C."
dir-A
(ediff-get-default-file-name)
'no-dirs))
- (setq ff (ediff-read-file-name "File B to compare"
+ (setq ff (ediff-read-file-name "File B to compare"
(setq dir-B
(if ediff-use-last-dir
ediff-last-dir-B
dir-B))
file-name-history))
(ediff-get-default-file-name f 1))))
- (ediff-read-file-name "File C to compare"
+ (ediff-read-file-name "File C to compare"
(setq dir-C (if ediff-use-last-dir
ediff-last-dir-C
(file-name-directory ff)))
file-name-history))
(ediff-get-default-file-name ff 2)))
)))
- (ediff-files-internal file-A
+ (ediff-files-internal file-A
(if (file-directory-p file-B)
(expand-file-name
(file-name-nondirectory file-A) file-B)
(defalias 'ediff3 'ediff-files3)
-;; Visit FILE and arrange its buffer to Ediff's liking.
+;; Visit FILE and arrange its buffer to Ediff's liking.
;; FILE is actually a variable symbol that must contain a true file name.
;; BUFFER-NAME is a variable symbol, which will get the buffer object into
;; which FILE is read.
(error "File `%s' does not exist or is not readable" file))
((file-directory-p file)
(error "File `%s' is a directory" file)))
-
+
;; some of the commands, below, require full file name
(setq file (expand-file-name file))
-
+
;; Record the directory of the file
(if last-dir
(set last-dir (expand-file-name (file-name-directory file))))
-
+
;; Setup the buffer
(set buffer-name (find-file-noselect file))
-
+
(ediff-with-current-buffer (symbol-value buffer-name)
(widen) ; Make sure the entire file is seen
(cond (file-magic ; file has a handler, such as jka-compr-handler or
startup-hooks
(list (cons 'ediff-job-name job-name))
merge-buffer-file)))
-
+
;;;###autoload
(defalias 'ediff 'ediff-files)
;;;###autoload
(defun ediff-buffers (buffer-A buffer-B &optional startup-hooks job-name)
"Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B."
- (interactive
+ (interactive
(let (bf)
(list (setq bf (read-buffer "Buffer A to compare: "
(ediff-other-buffer "") t))
;;;###autoload
(defalias 'ebuffers 'ediff-buffers)
-
+
;;;###autoload
(defun ediff-buffers3 (buffer-A buffer-B buffer-C
&optional startup-hooks job-name)
"Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C."
- (interactive
+ (interactive
(let (bf bff)
(list (setq bf (read-buffer "Buffer A to compare: "
(ediff-other-buffer "") t))
;;;###autoload
(defalias 'ebuffers3 'ediff-buffers3)
-
-
+
+
;; MERGE-BUFFER-FILE is the file to be associated with the merge buffer
(defun ediff-buffers-internal (buf-A buf-B buf-C startup-hooks job-name
&optional merge-buffer-file)
(setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
(if (stringp buf-C-file-name)
(setq buf-C-file-name (file-name-nondirectory buf-C-file-name)))
-
+
(setq file-A (ediff-make-temp-file buf-A buf-A-file-name)
file-B (ediff-make-temp-file buf-B buf-B-file-name))
(if buf-C-is-alive
(setq file-C (ediff-make-temp-file buf-C buf-C-file-name)))
-
+
(ediff-setup (get-buffer buf-A) file-A
(get-buffer buf-B) file-B
(if buf-C-is-alive (get-buffer buf-C))
(let ((dir-A (ediff-get-default-directory-name))
f)
(list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
- (ediff-read-file-name "Directory B to compare:"
+ (ediff-read-file-name "Directory B to compare:"
(if ediff-use-last-dir
- ediff-last-dir-B
+ ediff-last-dir-B
(ediff-strip-last-dir f))
nil)
(read-string "Filter through regular expression: "
(let ((dir-A (ediff-get-default-directory-name))
f)
(list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
- (setq f (ediff-read-file-name "Directory B to compare:"
+ (setq f (ediff-read-file-name "Directory B to compare:"
(if ediff-use-last-dir
- ediff-last-dir-B
+ ediff-last-dir-B
(ediff-strip-last-dir f))
nil))
- (ediff-read-file-name "Directory C to compare:"
+ (ediff-read-file-name "Directory C to compare:"
(if ediff-use-last-dir
- ediff-last-dir-C
+ ediff-last-dir-C
(ediff-strip-last-dir f))
nil)
(read-string "Filter through regular expression: "
(let ((dir-A (ediff-get-default-directory-name))
f)
(list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
- (ediff-read-file-name "Directory B to merge:"
+ (ediff-read-file-name "Directory B to merge:"
(if ediff-use-last-dir
- ediff-last-dir-B
+ ediff-last-dir-B
(ediff-strip-last-dir f))
nil)
(read-string "Filter through regular expression: "
(let ((dir-A (ediff-get-default-directory-name))
f)
(list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
- (setq f (ediff-read-file-name "Directory B to merge:"
+ (setq f (ediff-read-file-name "Directory B to merge:"
(if ediff-use-last-dir
- ediff-last-dir-B
+ ediff-last-dir-B
(ediff-strip-last-dir f))
nil))
(ediff-read-file-name "Ancestor directory:"
(if ediff-use-last-dir
- ediff-last-dir-C
+ ediff-last-dir-C
(ediff-strip-last-dir f))
nil)
(read-string "Filter through regular expression: "
;;;###autoload
(defalias
'edir-merge-revisions-with-ancestor
- 'ediff-merge-directory-revisions-with-ancestor)
+ 'ediff-merge-directory-revisions-with-ancestor)
;;;###autoload
(defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor)
;; only file names that match the regexp are considered.
;; JOBNAME is the symbol indicating the meta-job to be performed.
;; MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
-(defun ediff-directories-internal (dir1 dir2 dir3 regexp action jobname
+(defun ediff-directories-internal (dir1 dir2 dir3 regexp action jobname
&optional startup-hooks
merge-autostore-dir)
;; ediff-read-file-name is set to attach a previously entered file name if
(or (stringp merge-autostore-dir)
(error "%s: Directory for storing merged files must be a string"
jobname)))
- (let (;; dir-diff-struct is of the form (common-list diff-list)
+ (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
(if (and ediff-autostore-merges
(ediff-merge-metajob jobname)
(not merge-autostore-dir))
- (setq merge-autostore-dir
+ (setq merge-autostore-dir
(read-file-name "Save merged files in directory: "
(if ediff-use-last-dir
ediff-last-merge-autostore-dir
(or (y-or-n-p
"Directory for saving merged files = Ancestor Directory. Sure? ")
(error "Directory merge aborted")))))
-
- (setq dir-diff-struct (ediff-intersect-directories
+
+ (setq dir-diff-struct (ediff-intersect-directories
jobname
regexp dir1 dir2 dir3 merge-autostore-dir))
(setq startup-hooks
(cons `(lambda ()
;; tell what to do if the user clicks on a session record
(setq ediff-session-action-function (quote ,action))
- ;; set ediff-dir-difference-list
+ ;; set ediff-dir-difference-list
(setq ediff-dir-difference-list
(cdr (quote ,dir-diff-struct))))
startup-hooks))
- (setq meta-buf (ediff-prepare-meta-buffer
+ (setq meta-buf (ediff-prepare-meta-buffer
'ediff-filegroup-action
(car dir-diff-struct)
"*Ediff Session Group Panel"
;; MERGE-AUTOSTORE-DIR can be given to tell ediff where to store the merged
;; files
-(defun ediff-directory-revisions-internal (dir1 regexp action jobname
+(defun ediff-directory-revisions-internal (dir1 regexp action jobname
&optional startup-hooks
merge-autostore-dir)
(setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1)))
(error "%S: Directory for storing merged files must be a string"
jobname)))
(let (file-list meta-buf)
- (if (and ediff-autostore-merges
+ (if (and ediff-autostore-merges
(ediff-merge-metajob jobname)
(not merge-autostore-dir))
- (setq merge-autostore-dir
+ (setq merge-autostore-dir
(read-file-name "Save merged files in directory: "
(if ediff-use-last-dir
ediff-last-merge-autostore-dir
(or (y-or-n-p
"Directory for saving merged file = directory A. Sure? ")
(error "Merge of directory revisions aborted")))
-
+
(setq file-list
(ediff-get-directory-files-under-revision
jobname regexp dir1 merge-autostore-dir))
;; tell what to do if the user clicks on a session record
(setq ediff-session-action-function (quote ,action)))
startup-hooks))
- (setq meta-buf (ediff-prepare-meta-buffer
+ (setq meta-buf (ediff-prepare-meta-buffer
'ediff-filegroup-action
file-list
"*Ediff Session Group Panel"
(interactive "P")
(ediff-windows dumb-mode wind-A wind-B
startup-hooks 'ediff-windows-wordwise 'word-mode))
-
+
;;;###autoload
(defun ediff-windows-linewise (dumb-mode &optional wind-A wind-B startup-hooks)
"Compare WIND-A and WIND-B, which are selected by clicking, linewise.
(interactive "P")
(ediff-windows dumb-mode wind-A wind-B
startup-hooks 'ediff-windows-linewise nil))
-
+
;; Compare WIND-A and WIND-B, which are selected by clicking.
;; With prefix argument, DUMB-MODE, or on a non-windowing display,
;; works as follows:
wind-B (ediff-get-next-window wind-B wind-A))
(setq wind-A (ediff-get-window-by-clicking wind-A nil 1)
wind-B (ediff-get-window-by-clicking wind-B wind-A 2)))
-
+
(let ((buffer-A (window-buffer wind-A))
(buffer-B (window-buffer wind-B))
beg-A end-A beg-B end-B)
-
+
(save-excursion
(save-window-excursion
(sit-for 0) ; sync before using window-start/end -- a precaution
(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)
region.
This function is effective only for relatively small regions, up to 200
lines. For large regions, use `ediff-regions-linewise'."
- (interactive
+ (interactive
(let (bf)
(list (setq bf (read-buffer "Region's A buffer: "
(ediff-other-buffer "") t))
(error "Buffer %S doesn't exist" buffer-A))
(if (not (ediff-buffer-live-p buffer-B))
(error "Buffer %S doesn't exist" buffer-B))
-
-
+
+
(let ((buffer-A
(ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
(buffer-B
(set-buffer buffer-B)
(setq reg-B-beg (region-beginning)
reg-B-end (region-end)))
-
+
(ediff-regions-internal
(get-buffer buffer-A) reg-A-beg reg-A-end
(get-buffer buffer-B) reg-B-beg reg-B-end
startup-hooks 'ediff-regions-wordwise 'word-mode nil)))
-
+
;;;###autoload
(defun ediff-regions-linewise (buffer-A buffer-B &optional startup-hooks)
"Run Ediff on a pair of regions in specified buffers.
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'."
- (interactive
+ (interactive
(let (bf)
(list (setq bf (read-buffer "Region A's buffer: "
(ediff-other-buffer "") t))
(error "Buffer %S doesn't exist" buffer-A))
(if (not (ediff-buffer-live-p buffer-B))
(error "Buffer %S doesn't exist" buffer-B))
-
+
(let ((buffer-A
(ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
(buffer-B
(setq reg-A-beg (region-beginning)
reg-A-end (region-end))
;; enlarge the region to hold full lines
- (goto-char reg-A-beg)
+ (goto-char reg-A-beg)
(beginning-of-line)
(setq reg-A-beg (point))
- (goto-char reg-A-end)
+ (goto-char reg-A-end)
(end-of-line)
(or (eobp) (forward-char)) ; include the newline char
(setq reg-A-end (point))
-
+
(set-buffer buffer-B)
(setq reg-B-beg (region-beginning)
reg-B-end (region-end))
;; enlarge the region to hold full lines
- (goto-char reg-B-beg)
+ (goto-char reg-B-beg)
(beginning-of-line)
(setq reg-B-beg (point))
- (goto-char reg-B-end)
+ (goto-char reg-B-end)
(end-of-line)
(or (eobp) (forward-char)) ; include the newline char
(setq reg-B-end (point))
) ; save excursion
-
+
(ediff-regions-internal
(get-buffer buffer-A) reg-A-beg reg-A-end
(get-buffer buffer-B) reg-B-beg reg-B-end
startup-hooks 'ediff-regions-linewise nil nil))) ; no word mode
-
+
;; compare region beg-A to end-A of buffer-A
-;; to regions beg-B -- end-B in buffer-B.
+;; to regions beg-B -- end-B in buffer-B.
(defun ediff-regions-internal (buffer-A beg-A end-A buffer-B beg-B end-B
startup-hooks job-name word-mode
setup-parameters)
(let ((tmp-buffer (get-buffer-create ediff-tmp-buffer))
overl-A overl-B
file-A file-B)
-
+
;; in case beg/end-A/B aren't markers--make them into markers
(ediff-with-current-buffer buffer-A
(setq beg-A (move-marker (make-marker) beg-A)
(ediff-with-current-buffer buffer-B
(setq beg-B (move-marker (make-marker) beg-B)
end-B (move-marker (make-marker) end-B)))
-
+
;; make file-A
(if word-mode
(ediff-wordify beg-A end-A buffer-A tmp-buffer)
(ediff-copy-to-buffer beg-A end-A buffer-A tmp-buffer))
(setq file-A (ediff-make-temp-file tmp-buffer "regA"))
-
+
;; make file-B
(if word-mode
(ediff-wordify beg-B end-B buffer-B tmp-buffer)
(ediff-copy-to-buffer beg-B end-B buffer-B tmp-buffer))
(setq file-B (ediff-make-temp-file tmp-buffer "regB"))
-
+
(setq overl-A (ediff-make-bullet-proof-overlay beg-A end-A buffer-A))
(setq overl-B (ediff-make-bullet-proof-overlay beg-B end-B buffer-B))
(ediff-setup buffer-A file-A
(cons 'ediff-job-name job-name))
setup-parameters))
))
-
-
+
+
;;; Merge files and buffers
-
+
;;;###autoload
(defalias 'ediff-merge 'ediff-merge-files)
-
+
(defsubst ediff-merge-on-startup ()
(ediff-do-merge 0)
(ediff-with-current-buffer ediff-buffer-C
;;;###autoload
(defun ediff-merge-files (file-A file-B
;; MERGE-BUFFER-FILE is the file to be
- ;; associated with the merge buffer
+ ;; associated with the merge buffer
&optional startup-hooks merge-buffer-file)
"Merge two files without ancestor."
(interactive
dir-A
(ediff-get-default-file-name)
'no-dirs))
- (ediff-read-file-name "File B to merge"
+ (ediff-read-file-name "File B to merge"
(setq dir-B
(if ediff-use-last-dir
- ediff-last-dir-B
+ ediff-last-dir-B
(file-name-directory f)))
(progn
(setq file-name-history
(ediff-get-default-file-name f 1)))
)))
(setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
- (ediff-files-internal file-A
+ (ediff-files-internal file-A
(if (file-directory-p file-B)
(expand-file-name
(file-name-nondirectory file-A) file-B)
startup-hooks
'ediff-merge-files
merge-buffer-file))
-
+
;;;###autoload
(defun ediff-merge-files-with-ancestor (file-A file-B file-ancestor
&optional
dir-A
(ediff-get-default-file-name)
'no-dirs))
- (setq ff (ediff-read-file-name "File B to merge"
+ (setq ff (ediff-read-file-name "File B to merge"
(setq dir-B
(if ediff-use-last-dir
- ediff-last-dir-B
+ ediff-last-dir-B
(file-name-directory f)))
(progn
(setq file-name-history
dir-B))
file-name-history))
(ediff-get-default-file-name f 1))))
- (ediff-read-file-name "Ancestor file"
+ (ediff-read-file-name "Ancestor file"
(setq dir-ancestor
(if ediff-use-last-dir
ediff-last-dir-ancestor
(ediff-get-default-file-name ff 2)))
)))
(setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
- (ediff-files-internal file-A
+ (ediff-files-internal file-A
(if (file-directory-p file-B)
(expand-file-name
(file-name-nondirectory file-A) file-B)
startup-hooks
'ediff-merge-files-with-ancestor
merge-buffer-file))
-
+
;;;###autoload
(defalias 'ediff-merge-with-ancestor 'ediff-merge-files-with-ancestor)
-
+
;;;###autoload
(defun ediff-merge-buffers (buffer-A buffer-B
&optional
;; associated with the merge buffer
startup-hooks job-name merge-buffer-file)
"Merge buffers without ancestor."
- (interactive
+ (interactive
(let (bf)
(list (setq bf (read-buffer "Buffer A to merge: "
(ediff-other-buffer "") t))
(save-window-excursion (other-window 1))
(ediff-other-buffer bf))
t))))
-
+
(setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
(or job-name (setq job-name 'ediff-merge-buffers))
(ediff-buffers-internal
buffer-A buffer-B nil startup-hooks job-name merge-buffer-file))
-
+
;;;###autoload
(defun ediff-merge-buffers-with-ancestor (buffer-A buffer-B buffer-ancestor
&optional
;; with the merge buffer
merge-buffer-file)
"Merge buffers with ancestor."
- (interactive
+ (interactive
(let (bf bff)
(list (setq bf (read-buffer "Buffer A to merge: "
(ediff-other-buffer "") t))
(ediff-other-buffer (list bf bff)))
t)
)))
-
+
(setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
(or job-name (setq job-name 'ediff-merge-buffers-with-ancestor))
(ediff-buffers-internal
buffer-A buffer-B buffer-ancestor startup-hooks job-name merge-buffer-file))
-
+
;;;###autoload
(defun ediff-merge-revisions (&optional file startup-hooks merge-buffer-file)
(funcall
(intern (format "ediff-%S-merge-internal" ediff-version-control-package))
rev1 rev2 nil startup-hooks merge-buffer-file)))
-
+
;;;###autoload
(defun ediff-merge-revisions-with-ancestor (&optional
(if tin
(cvs-run-ediff-on-file-descriptor tin)
(error "There is no file to merge"))))
-
-
+
+
;;; Apply patch
;;;###autoload
(buffer-file-name patch-buf))))
(t default-directory)))
(setq source-file
- (read-file-name
+ (read-file-name
"File to patch (directory, if multifile patch): "
;; use an explicit initial file
source-dir nil nil (ediff-get-default-file-name)))
(read-buffer
"Which buffer to patch? "
(current-buffer))))
-
+
;;;###autoload
(defalias 'epatch 'ediff-patch-file)
\f
-;;; Versions Control functions
-
+;;; Versions Control functions
+
;;;###autoload
(defun ediff-revision (&optional file startup-hooks)
"Run Ediff by comparing versions of a file.
ediff-last-dir-A
default-directory)
(ediff-get-default-file-name)
- 'no-dirs)))
+ 'no-dirs)))
(find-file file)
(if (and (buffer-modified-p)
(y-or-n-p (message "Buffer %s is modified. Save buffer? "
(let (rev1 rev2)
(setq rev1
(read-string
- (format "Version 1 to compare (default: %s's working version): "
+ (format "Revision 1 to compare (default: %s's latest revision): "
(file-name-nondirectory file)))
rev2
- (read-string
- (format "Version 2 to compare (default: %s): "
+ (read-string
+ (format "Revision 2 to compare (default: %s's current state): "
(file-name-nondirectory file))))
(ediff-load-version-control)
(funcall
;;;###autoload
(defalias 'erevision 'ediff-revision)
-
-
+
+
;; Test if version control package is loaded and load if not
;; Is SILENT is non-nil, don't report error if package is not found.
(defun ediff-load-version-control (&optional silent)
(progn
(select-window ctl-window)
(set-window-buffer ctl-window ctl-buf)))))))
-
+