(diary-header-line-flag, diary-header-line-format): New variables.
[bpt/emacs.git] / lisp / ediff.el
CommitLineData
0f0b0a86 1;;; ediff.el --- a comprehensive visual interface to diff & patch
b578f267 2
0831d50c 3;; Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 Free Software Foundation, Inc.
813f532d 4
50a07e18 5;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
813f532d 6;; Created: February 2, 1994
e4d2c130 7;; Keywords: comparing, merging, patching, tools, unix
813f532d 8
0831d50c 9(defconst ediff-version "2.78" "The current version of Ediff")
6e31f65f 10(defconst ediff-date "May 18, 2003" "Date of last update")
bbe6126c 11
eaccd4d8 12
813f532d
RS
13;; This file is part of GNU Emacs.
14
15;; GNU Emacs is free software; you can redistribute it and/or modify
16;; it under the terms of the GNU General Public License as published by
17;; the Free Software Foundation; either version 2, or (at your option)
18;; any later version.
19
20;; GNU Emacs is distributed in the hope that it will be useful,
21;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23;; GNU General Public License for more details.
24
25;; You should have received a copy of the GNU General Public License
b578f267
EN
26;; along with GNU Emacs; see the file COPYING. If not, write to the
27;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28;; Boston, MA 02111-1307, USA.
813f532d 29
813f532d 30;;; Commentary:
813f532d 31
0f0b0a86 32;; Never read that diff output again!
bbe6126c 33;; Apply patch interactively!
0f0b0a86 34;; Merge with ease!
813f532d 35
fcbadd58 36;; This package provides a convenient way of simultaneous browsing through
f1a5512a 37;; the differences between a pair (or a triple) of files or buffers. The
0f0b0a86
KH
38;; files being compared, file-A, file-B, and file-C (if applicable) are
39;; shown in separate windows (side by side, one above the another, or in
40;; separate frames), and the differences are highlighted as you step
41;; through them. You can also copy difference regions from one buffer to
42;; another (and recover old differences if you change your mind).
813f532d 43
87c668b4 44;; Ediff also supports merging operations on files and buffers, including
3af0304a 45;; merging using ancestor versions. Both comparison and merging operations can
87c668b4
MK
46;; be performed on directories, i.e., by pairwise comparison of files in those
47;; directories.
48
813f532d 49;; In addition, Ediff can apply a patch to a file and then let you step
fcbadd58 50;; though both files, the patched and the original one, simultaneously,
813f532d
RS
51;; difference-by-difference. You can even apply a patch right out of a
52;; mail buffer, i.e., patches received by mail don't even have to be saved.
53;; Since Ediff lets you copy differences between buffers, you can, in
54;; effect, apply patches selectively (i.e., you can copy a difference
0f0b0a86 55;; region from file_orig to file, thereby undoing any particular patch that
813f532d
RS
56;; you don't like).
57
f1a5512a 58;; Ediff is aware of version control, which lets the user compare
3af0304a
MK
59;; files with their older versions. Ediff can also work with remote and
60;; compressed files. Details are given below.
f1a5512a 61
bbe6126c 62;; Finally, Ediff supports directory-level comparison, merging and patching.
87c668b4 63;; See the on-line manual for details.
813f532d 64
87c668b4 65;; This package builds upon the ideas borrowed from emerge.el and several
3af0304a 66;; Ediff's functions are adaptations from emerge.el. Much of the functionality
87c668b4
MK
67;; Ediff provides is also influenced by emerge.el.
68
3af0304a
MK
69;; The present version of Ediff supersedes Emerge. It provides a superior user
70;; interface and has numerous major features not found in Emerge. In
87c668b4
MK
71;; particular, it can do patching, and 2-way and 3-way file comparison,
72;; merging, and directory operations.
fcbadd58 73
4ae69eac
MK
74
75
813f532d 76;;; Bugs:
813f532d 77
3af0304a 78;; 1. The undo command doesn't restore deleted regions well. That is, if
813f532d 79;; you delete all characters in a difference region and then invoke
0f0b0a86 80;; `undo', the reinstated text will most likely be inserted outside of
b3a26225 81;; what Ediff thinks is the current difference region. (This problem
0f0b0a86 82;; doesn't seem to exist with XEmacs.)
b3a26225
RS
83;;
84;; If at any point you feel that difference regions are no longer correct,
85;; you can hit '!' to recompute the differences.
86
f1a5512a 87;; 2. On a monochrome display, the repertoire of faces with which to
3af0304a
MK
88;; highlight fine differences is limited. By default, Ediff is using
89;; underlining. However, if the region is already underlined by some other
b3a26225 90;; overlays, there is no simple way to temporarily remove that residual
3af0304a
MK
91;; underlining. This problem occurs when a buffer is highlighted with
92;; hilit19.el or font-lock.el packages. If this residual highlighting gets
93;; in the way, you can do the following. Both font-lock.el and hilit19.el
94;; provide commands for unhighlighting buffers. You can either place these
87c668b4 95;; commands in `ediff-prepare-buffer-hook' (which will unhighlight every
b3a26225
RS
96;; buffer used by Ediff) or you can execute them interactively, at any time
97;; and on any buffer.
0f0b0a86 98
4ae69eac 99
0f0b0a86
KH
100;;; Acknowledgements:
101
87c668b4
MK
102;; Ediff was inspired by Dale R. Worley's <drw@math.mit.edu> emerge.el.
103;; Ediff would not have been possible without the help and encouragement of
3af0304a
MK
104;; its many users. See Ediff on-line Info for the full list of those who
105;; helped. Improved defaults in Ediff file-name reading commands.
0f0b0a86 106
0f0b0a86
KH
107;;; Code:
108
ddc90f39 109(provide 'ediff)
eaccd4d8 110
ddc90f39 111;; Compiler pacifier
1e70790f
MK
112(defvar cvs-cookie-handle)
113(defvar ediff-last-dir-patch)
114(defvar ediff-patch-default-directory)
115
92c51e07
MK
116(and noninteractive
117 (eval-when-compile
92c51e07 118 (load-library "dired")
ddc90f39
MK
119 (load-library "info")
120 (load "pcl-cvs" 'noerror)))
121(eval-when-compile
122 (let ((load-path (cons (expand-file-name ".") load-path)))
123 (or (featurep 'ediff-init)
124 (load "ediff-init.el" nil nil 'nosuffix))
125 (or (featurep 'ediff-mult)
126 (load "ediff-mult.el" nil nil 'nosuffix))
127 (or (featurep 'ediff-ptch)
128 (load "ediff-ptch.el" nil nil 'nosuffix))
129 (or (featurep 'ediff-vers)
130 (load "ediff-vers.el" nil nil 'nosuffix))
131 ))
132;; end pacifier
133
134(require 'ediff-init)
135(require 'ediff-mult) ; required because of the registry stuff
136
137(defgroup ediff nil
138 "A comprehensive visual interface to diff & patch"
34317da2 139 :tag "Ediff"
ddc90f39
MK
140 :group 'tools)
141
142
143(defcustom ediff-use-last-dir nil
1e70790f 144 "*If t, Ediff will use previous directory as default when reading file name."
ddc90f39
MK
145 :type 'boolean
146 :group 'ediff)
bbe6126c 147
1e70790f
MK
148;; Last directory used by an Ediff command for file-A.
149(defvar ediff-last-dir-A nil)
150;; Last directory used by an Ediff command for file-B.
151(defvar ediff-last-dir-B nil)
152;; Last directory used by an Ediff command for file-C.
153(defvar ediff-last-dir-C nil)
154;; Last directory used by an Ediff command for the ancestor file.
155(defvar ediff-last-dir-ancestor nil)
156;; Last directory used by an Ediff command as the output directory for merge.
c3912d54 157(defvar ediff-last-merge-autostore-dir nil)
813f532d 158
87c668b4 159
4ae69eac 160;; Used as a startup hook to set `_orig' patch file read-only.
f1a5512a 161(defun ediff-set-read-only-in-buf-A ()
e756eb9f 162 (ediff-with-current-buffer ediff-buffer-A
f1a5512a 163 (toggle-read-only 1)))
813f532d 164
87c668b4 165;; Return a plausible default for ediff's first file:
657f9cb8
MK
166;; In dired, return the file number FILENO (or 0) in the list
167;; (all-selected-files, filename under the cursor), where directories are
168;; ignored. Otherwise, return DEFAULT file name, if non-nil. Else,
169;; if the buffer is visiting a file, return that file name.
170(defun ediff-get-default-file-name (&optional default fileno)
87c668b4 171 (cond ((eq major-mode 'dired-mode)
657f9cb8
MK
172 (let ((current (dired-get-filename nil 'no-error))
173 (marked (condition-case nil
174 (dired-get-marked-files 'no-dir)
50a07e18 175 (error nil)))
657f9cb8
MK
176 aux-list choices result)
177 (or (integerp fileno) (setq fileno 0))
178 (if (stringp default)
179 (setq aux-list (cons default aux-list)))
180 (if (and (stringp current) (not (file-directory-p current)))
181 (setq aux-list (cons current aux-list)))
182 (setq choices (nconc marked aux-list))
183 (setq result (elt choices fileno))
184 (or result
185 default)))
186 ((stringp default) default)
87c668b4
MK
187 ((buffer-file-name (current-buffer))
188 (file-name-nondirectory (buffer-file-name (current-buffer))))
189 ))
190
0f0b0a86 191;;; Compare files/buffers
813f532d
RS
192
193;;;###autoload
194(defun ediff-files (file-A file-B &optional startup-hooks)
0f0b0a86 195 "Run Ediff on a pair of files, FILE-A and FILE-B."
813f532d 196 (interactive
0f0b0a86
KH
197 (let ((dir-A (if ediff-use-last-dir
198 ediff-last-dir-A
199 default-directory))
200 dir-B f)
87c668b4 201 (list (setq f (ediff-read-file-name
50a07e18 202 "File A to compare"
71296446 203 dir-A
50a07e18
MK
204 (ediff-get-default-file-name)
205 'no-dirs))
71296446 206 (ediff-read-file-name "File B to compare"
0f0b0a86
KH
207 (setq dir-B
208 (if ediff-use-last-dir
71296446 209 ediff-last-dir-B
0f0b0a86
KH
210 (file-name-directory f)))
211 (progn
212 (setq file-name-history
87c668b4 213 (cons (ediff-abbreviate-file-name
0f0b0a86
KH
214 (expand-file-name
215 (file-name-nondirectory f)
216 dir-B))
217 file-name-history))
657f9cb8 218 (ediff-get-default-file-name f 1)))
0f0b0a86 219 )))
71296446 220 (ediff-files-internal file-A
0f0b0a86
KH
221 (if (file-directory-p file-B)
222 (expand-file-name
223 (file-name-nondirectory file-A) file-B)
224 file-B)
225 nil ; file-C
226 startup-hooks
227 'ediff-files))
71296446 228
0f0b0a86
KH
229;;;###autoload
230(defun ediff-files3 (file-A file-B file-C &optional startup-hooks)
231 "Run Ediff on three files, FILE-A, FILE-B, and FILE-C."
232 (interactive
233 (let ((dir-A (if ediff-use-last-dir
234 ediff-last-dir-A
235 default-directory))
236 dir-B dir-C f ff)
87c668b4 237 (list (setq f (ediff-read-file-name
50a07e18
MK
238 "File A to compare"
239 dir-A
240 (ediff-get-default-file-name)
241 'no-dirs))
71296446 242 (setq ff (ediff-read-file-name "File B to compare"
0f0b0a86
KH
243 (setq dir-B
244 (if ediff-use-last-dir
245 ediff-last-dir-B
246 (file-name-directory f)))
247 (progn
248 (setq file-name-history
249 (cons
87c668b4 250 (ediff-abbreviate-file-name
0f0b0a86
KH
251 (expand-file-name
252 (file-name-nondirectory f)
253 dir-B))
254 file-name-history))
657f9cb8 255 (ediff-get-default-file-name f 1))))
71296446 256 (ediff-read-file-name "File C to compare"
0f0b0a86
KH
257 (setq dir-C (if ediff-use-last-dir
258 ediff-last-dir-C
259 (file-name-directory ff)))
260 (progn
261 (setq file-name-history
87c668b4 262 (cons (ediff-abbreviate-file-name
0f0b0a86
KH
263 (expand-file-name
264 (file-name-nondirectory ff)
265 dir-C))
266 file-name-history))
657f9cb8 267 (ediff-get-default-file-name ff 2)))
813f532d 268 )))
71296446 269 (ediff-files-internal file-A
b3a26225
RS
270 (if (file-directory-p file-B)
271 (expand-file-name
272 (file-name-nondirectory file-A) file-B)
273 file-B)
0f0b0a86
KH
274 (if (file-directory-p file-C)
275 (expand-file-name
276 (file-name-nondirectory file-A) file-C)
277 file-C)
278 startup-hooks
279 'ediff-files3))
813f532d 280
0f0b0a86
KH
281;;;###autoload
282(defalias 'ediff3 'ediff-files3)
813f532d 283
813f532d 284
71296446 285;; Visit FILE and arrange its buffer to Ediff's liking.
4ae69eac
MK
286;; FILE is actually a variable symbol that must contain a true file name.
287;; BUFFER-NAME is a variable symbol, which will get the buffer object into
288;; which FILE is read.
289;; LAST-DIR is the directory variable symbol where FILE's
3af0304a 290;; directory name should be returned. HOOKS-VAR is a variable symbol that will
4ae69eac
MK
291;; be assigned the hook to be executed after `ediff-startup' is finished.
292;; `ediff-find-file' arranges that the temp files it might create will be
293;; deleted.
0f0b0a86 294(defun ediff-find-file (file-var buffer-name &optional last-dir hooks-var)
0f0b0a86 295 (let* ((file (symbol-value file-var))
bd698e98 296 (file-magic (ediff-filename-magic-p file))
0f0b0a86 297 (temp-file-name-prefix (file-name-nondirectory file)))
87c668b4
MK
298 (cond ((not (file-readable-p file))
299 (error "File `%s' does not exist or is not readable" file))
300 ((file-directory-p file)
301 (error "File `%s' is a directory" file)))
71296446 302
4ae69eac 303 ;; some of the commands, below, require full file name
0f0b0a86 304 (setq file (expand-file-name file))
71296446 305
0f0b0a86
KH
306 ;; Record the directory of the file
307 (if last-dir
308 (set last-dir (expand-file-name (file-name-directory file))))
71296446 309
0f0b0a86
KH
310 ;; Setup the buffer
311 (set buffer-name (find-file-noselect file))
71296446 312
e756eb9f 313 (ediff-with-current-buffer (symbol-value buffer-name)
0f0b0a86 314 (widen) ; Make sure the entire file is seen
ddc90f39
MK
315 (cond (file-magic ; file has a handler, such as jka-compr-handler or
316 ;;; ange-ftp-hook-function--arrange for temp file
0f0b0a86 317 (ediff-verify-file-buffer 'magic)
87c668b4
MK
318 (setq file
319 (ediff-make-temp-file
320 (current-buffer) temp-file-name-prefix))
086171bf 321 (set hooks-var (cons `(lambda () (delete-file ,file))
0f0b0a86
KH
322 (symbol-value hooks-var))))
323 ;; file processed via auto-mode-alist, a la uncompress.el
324 ((not (equal (file-truename file)
325 (file-truename (buffer-file-name))))
87c668b4
MK
326 (setq file
327 (ediff-make-temp-file
328 (current-buffer) temp-file-name-prefix))
086171bf 329 (set hooks-var (cons `(lambda () (delete-file ,file))
0f0b0a86
KH
330 (symbol-value hooks-var))))
331 (t ;; plain file---just check that the file matches the buffer
332 (ediff-verify-file-buffer))))
333 (set file-var file)))
334
328b4b70
MK
335;; MERGE-BUFFER-FILE is the file to be associated with the merge buffer
336(defun ediff-files-internal (file-A file-B file-C startup-hooks job-name
337 &optional merge-buffer-file)
0f0b0a86 338 (let (buf-A buf-B buf-C)
50a07e18
MK
339 (if (string= file-A file-B)
340 (error "Files A and B are the same"))
341 (if (stringp file-C)
342 (or (and (string= file-A file-C) (error "Files A and C are the same"))
343 (and (string= file-B file-C) (error "Files B and C are the same"))))
87c668b4
MK
344 (message "Reading file %s ... " file-A)
345 ;;(sit-for 0)
0f0b0a86 346 (ediff-find-file 'file-A 'buf-A 'ediff-last-dir-A 'startup-hooks)
87c668b4
MK
347 (message "Reading file %s ... " file-B)
348 ;;(sit-for 0)
0f0b0a86 349 (ediff-find-file 'file-B 'buf-B 'ediff-last-dir-B 'startup-hooks)
87c668b4 350 (if (stringp file-C)
0f0b0a86 351 (progn
87c668b4
MK
352 (message "Reading file %s ... " file-C)
353 ;;(sit-for 0)
0f0b0a86
KH
354 (ediff-find-file
355 'file-C 'buf-C
356 (if (eq job-name 'ediff-merge-files-with-ancestor)
357 'ediff-last-dir-ancestor 'ediff-last-dir-C)
358 'startup-hooks)))
359 (ediff-setup buf-A file-A
360 buf-B file-B
361 buf-C file-C
362 startup-hooks
328b4b70
MK
363 (list (cons 'ediff-job-name job-name))
364 merge-buffer-file)))
71296446 365
0f0b0a86
KH
366
367;;;###autoload
368(defalias 'ediff 'ediff-files)
813f532d 369
3755bd32
MR
370;;;###autoload
371(defun ediff-backup (file)
372 "Run Ediff on FILE and its backup file.
373Uses the latest backup, if there are several numerical backups.
374If this file is a backup, `ediff' it with its original."
375 (interactive (list (read-file-name "Ediff (file with backup): ")))
376 ;; The code is taken from `diff-backup'.
377 (require 'diff)
378 (let (bak ori)
379 (if (backup-file-name-p file)
380 (setq bak file
381 ori (file-name-sans-versions file))
382 (setq bak (or (diff-latest-backup-file file)
383 (error "No backup found for %s" file))
384 ori file))
385 (ediff-files bak ori)))
813f532d
RS
386
387;;;###autoload
0f0b0a86 388(defun ediff-buffers (buffer-A buffer-B &optional startup-hooks job-name)
813f532d 389 "Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B."
71296446 390 (interactive
0f0b0a86
KH
391 (let (bf)
392 (list (setq bf (read-buffer "Buffer A to compare: "
393 (ediff-other-buffer "") t))
394 (read-buffer "Buffer B to compare: "
395 (progn
396 ;; realign buffers so that two visible bufs will be
397 ;; at the top
398 (save-window-excursion (other-window 1))
399 (ediff-other-buffer bf))
400 t))))
0f0b0a86
KH
401 (or job-name (setq job-name 'ediff-buffers))
402 (ediff-buffers-internal buffer-A buffer-B nil startup-hooks job-name))
bbe6126c
MK
403
404;;;###autoload
405(defalias 'ebuffers 'ediff-buffers)
406
71296446 407
0f0b0a86
KH
408;;;###autoload
409(defun ediff-buffers3 (buffer-A buffer-B buffer-C
410 &optional startup-hooks job-name)
411 "Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C."
71296446 412 (interactive
0f0b0a86
KH
413 (let (bf bff)
414 (list (setq bf (read-buffer "Buffer A to compare: "
415 (ediff-other-buffer "") t))
416 (setq bff (read-buffer "Buffer B to compare: "
417 (progn
418 ;; realign buffers so that two visible
419 ;; bufs will be at the top
420 (save-window-excursion (other-window 1))
421 (ediff-other-buffer bf))
422 t))
423 (read-buffer "Buffer C to compare: "
424 (progn
425 ;; realign buffers so that three visible
426 ;; bufs will be at the top
427 (save-window-excursion (other-window 1))
428 (ediff-other-buffer (list bf bff)))
429 t)
430 )))
0f0b0a86
KH
431 (or job-name (setq job-name 'ediff-buffers3))
432 (ediff-buffers-internal buffer-A buffer-B buffer-C startup-hooks job-name))
bbe6126c
MK
433
434;;;###autoload
435(defalias 'ebuffers3 'ediff-buffers3)
0f0b0a86 436
71296446
JB
437
438
328b4b70
MK
439;; MERGE-BUFFER-FILE is the file to be associated with the merge buffer
440(defun ediff-buffers-internal (buf-A buf-B buf-C startup-hooks job-name
441 &optional merge-buffer-file)
0f0b0a86
KH
442 (let* ((buf-A-file-name (buffer-file-name (get-buffer buf-A)))
443 (buf-B-file-name (buffer-file-name (get-buffer buf-B)))
444 (buf-C-is-alive (ediff-buffer-live-p buf-C))
445 (buf-C-file-name (if buf-C-is-alive
446 (buffer-file-name (get-buffer buf-B))))
447 file-A file-B file-C)
448 (if (not (ediff-buffer-live-p buf-A))
449 (error "Buffer %S doesn't exist" buf-A))
450 (if (not (ediff-buffer-live-p buf-B))
451 (error "Buffer %S doesn't exist" buf-B))
452 (let ((ediff-job-name job-name))
453 (if (and ediff-3way-comparison-job
454 (not buf-C-is-alive))
455 (error "Buffer %S doesn't exist" buf-C)))
456 (if (stringp buf-A-file-name)
457 (setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
458 (if (stringp buf-B-file-name)
459 (setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
460 (if (stringp buf-C-file-name)
461 (setq buf-C-file-name (file-name-nondirectory buf-C-file-name)))
71296446 462
4ae69eac
MK
463 (setq file-A (ediff-make-temp-file buf-A buf-A-file-name)
464 file-B (ediff-make-temp-file buf-B buf-B-file-name))
0f0b0a86 465 (if buf-C-is-alive
87c668b4 466 (setq file-C (ediff-make-temp-file buf-C buf-C-file-name)))
71296446 467
0f0b0a86
KH
468 (ediff-setup (get-buffer buf-A) file-A
469 (get-buffer buf-B) file-B
470 (if buf-C-is-alive (get-buffer buf-C))
471 file-C
086171bf
MK
472 (cons `(lambda ()
473 (delete-file ,file-A)
474 (delete-file ,file-B)
475 (if (stringp ,file-C) (delete-file ,file-C)))
0f0b0a86
KH
476 startup-hooks)
477 (list (cons 'ediff-job-name job-name))
328b4b70 478 merge-buffer-file)))
87c668b4
MK
479
480
481;;; Directory and file group operations
482
483;; Get appropriate default name for directory:
484;; If ediff-use-last-dir, use ediff-last-dir-A.
485;; In dired mode, use the directory that is under the point (if any);
486;; otherwise, use default-directory
487(defun ediff-get-default-directory-name ()
488 (cond (ediff-use-last-dir ediff-last-dir-A)
489 ((eq major-mode 'dired-mode)
490 (let ((f (dired-get-filename nil 'noerror)))
491 (if (and (stringp f) (file-directory-p f))
492 f
493 default-directory)))
494 (t default-directory)))
495
496
497;;;###autoload
498(defun ediff-directories (dir1 dir2 regexp)
499 "Run Ediff on a pair of directories, DIR1 and DIR2, comparing files that have
6dfd1bcc
MK
500the same name in both. The third argument, REGEXP, is nil or a regular
501expression; only file names that match the regexp are considered."
87c668b4
MK
502 (interactive
503 (let ((dir-A (ediff-get-default-directory-name))
504 f)
bbe6126c 505 (list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
71296446 506 (ediff-read-file-name "Directory B to compare:"
87c668b4 507 (if ediff-use-last-dir
71296446 508 ediff-last-dir-B
87c668b4
MK
509 (ediff-strip-last-dir f))
510 nil)
6e31f65f
MK
511 (read-string (format
512 "Filter through regular expression (default %S): "
513 (eval ediff-default-filtering-regexp))
514 (eval ediff-default-filtering-regexp)
515 'ediff-filtering-regexp-history)
87c668b4
MK
516 )))
517 (ediff-directories-internal
518 dir1 dir2 nil regexp 'ediff-files 'ediff-directories
519 ))
520
521;;;###autoload
522(defalias 'edirs 'ediff-directories)
523
524
525;;;###autoload
526(defun ediff-directory-revisions (dir1 regexp)
527 "Run Ediff on a directory, DIR1, comparing its files with their revisions.
528The second argument, REGEXP, is a regular expression that filters the file
3af0304a 529names. Only the files that are under revision control are taken into account."
87c668b4
MK
530 (interactive
531 (let ((dir-A (ediff-get-default-directory-name)))
532 (list (ediff-read-file-name
bbe6126c 533 "Directory to compare with revision:" dir-A nil)
6e31f65f
MK
534 (read-string (format
535 "Filter through regular expression (default %S): "
536 (eval ediff-default-filtering-regexp))
537 (eval ediff-default-filtering-regexp)
538 'ediff-filtering-regexp-history)
87c668b4
MK
539 )))
540 (ediff-directory-revisions-internal
541 dir1 regexp 'ediff-revision 'ediff-directory-revisions
542 ))
543
544;;;###autoload
545(defalias 'edir-revisions 'ediff-directory-revisions)
546
547
548;;;###autoload
549(defun ediff-directories3 (dir1 dir2 dir3 regexp)
550 "Run Ediff on three directories, DIR1, DIR2, and DIR3, comparing files that
6dfd1bcc
MK
551have the same name in all three. The last argument, REGEXP, is nil or a
552regular expression; only file names that match the regexp are considered."
553
87c668b4
MK
554 (interactive
555 (let ((dir-A (ediff-get-default-directory-name))
556 f)
bbe6126c 557 (list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
71296446 558 (setq f (ediff-read-file-name "Directory B to compare:"
87c668b4 559 (if ediff-use-last-dir
71296446 560 ediff-last-dir-B
87c668b4
MK
561 (ediff-strip-last-dir f))
562 nil))
71296446 563 (ediff-read-file-name "Directory C to compare:"
87c668b4 564 (if ediff-use-last-dir
71296446 565 ediff-last-dir-C
87c668b4
MK
566 (ediff-strip-last-dir f))
567 nil)
6e31f65f
MK
568 (read-string (format
569 "Filter through regular expression (default %S): "
570 (eval ediff-default-filtering-regexp))
571 (eval ediff-default-filtering-regexp)
572 'ediff-filtering-regexp-history)
87c668b4
MK
573 )))
574 (ediff-directories-internal
575 dir1 dir2 dir3 regexp 'ediff-files3 'ediff-directories3
576 ))
577
578;;;###autoload
579(defalias 'edirs3 'ediff-directories3)
580
581;;;###autoload
3af0304a 582(defun ediff-merge-directories (dir1 dir2 regexp &optional merge-autostore-dir)
87c668b4 583 "Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have
6dfd1bcc
MK
584the same name in both. The third argument, REGEXP, is nil or a regular
585expression; only file names that match the regexp are considered."
87c668b4
MK
586 (interactive
587 (let ((dir-A (ediff-get-default-directory-name))
588 f)
bbe6126c 589 (list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
71296446 590 (ediff-read-file-name "Directory B to merge:"
87c668b4 591 (if ediff-use-last-dir
71296446 592 ediff-last-dir-B
87c668b4
MK
593 (ediff-strip-last-dir f))
594 nil)
6e31f65f
MK
595 (read-string (format
596 "Filter through regular expression (default %S): "
597 (eval ediff-default-filtering-regexp))
598 (eval ediff-default-filtering-regexp)
599 'ediff-filtering-regexp-history)
87c668b4
MK
600 )))
601 (ediff-directories-internal
602 dir1 dir2 nil regexp 'ediff-merge-files 'ediff-merge-directories
3af0304a 603 nil merge-autostore-dir
87c668b4
MK
604 ))
605
606;;;###autoload
607(defalias 'edirs-merge 'ediff-merge-directories)
608
609;;;###autoload
3af0304a
MK
610(defun ediff-merge-directories-with-ancestor (dir1 dir2 ancestor-dir regexp
611 &optional
612 merge-autostore-dir)
bbe6126c 613 "Merge files in directories DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors.
3af0304a 614Ediff merges files that have identical names in DIR1, DIR2. If a pair of files
bbe6126c 615in DIR1 and DIR2 doesn't have an ancestor in ANCESTOR-DIR, Ediff will merge
6dfd1bcc
MK
616without ancestor. The fourth argument, REGEXP, is nil or a regular expression;
617only file names that match the regexp are considered."
87c668b4
MK
618 (interactive
619 (let ((dir-A (ediff-get-default-directory-name))
620 f)
bbe6126c 621 (list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
71296446 622 (setq f (ediff-read-file-name "Directory B to merge:"
87c668b4 623 (if ediff-use-last-dir
71296446 624 ediff-last-dir-B
87c668b4
MK
625 (ediff-strip-last-dir f))
626 nil))
bbe6126c 627 (ediff-read-file-name "Ancestor directory:"
87c668b4 628 (if ediff-use-last-dir
71296446 629 ediff-last-dir-C
87c668b4
MK
630 (ediff-strip-last-dir f))
631 nil)
6e31f65f
MK
632 (read-string (format
633 "Filter through regular expression (default %S): "
634 (eval ediff-default-filtering-regexp))
635 (eval ediff-default-filtering-regexp)
636 'ediff-filtering-regexp-history)
87c668b4
MK
637 )))
638 (ediff-directories-internal
bbe6126c 639 dir1 dir2 ancestor-dir regexp
87c668b4 640 'ediff-merge-files-with-ancestor 'ediff-merge-directories-with-ancestor
3af0304a 641 nil merge-autostore-dir
87c668b4
MK
642 ))
643
644;;;###autoload
3af0304a
MK
645(defun ediff-merge-directory-revisions (dir1 regexp
646 &optional merge-autostore-dir)
87c668b4
MK
647 "Run Ediff on a directory, DIR1, merging its files with their revisions.
648The second argument, REGEXP, is a regular expression that filters the file
3af0304a 649names. Only the files that are under revision control are taken into account."
87c668b4 650 (interactive
bf5d92c5 651 (let ((dir-A (ediff-get-default-directory-name)))
87c668b4 652 (list (ediff-read-file-name
bbe6126c 653 "Directory to merge with revisions:" dir-A nil)
6e31f65f
MK
654 (read-string (format
655 "Filter through regular expression (default %S): "
656 (eval ediff-default-filtering-regexp))
657 (eval ediff-default-filtering-regexp)
658 'ediff-filtering-regexp-history)
87c668b4
MK
659 )))
660 (ediff-directory-revisions-internal
661 dir1 regexp 'ediff-merge-revisions 'ediff-merge-directory-revisions
3af0304a 662 nil merge-autostore-dir
87c668b4
MK
663 ))
664
665;;;###autoload
666(defalias 'edir-merge-revisions 'ediff-merge-directory-revisions)
667
668;;;###autoload
3af0304a
MK
669(defun ediff-merge-directory-revisions-with-ancestor (dir1 regexp
670 &optional
671 merge-autostore-dir)
87c668b4
MK
672 "Run Ediff on a directory, DIR1, merging its files with their revisions and ancestors.
673The second argument, REGEXP, is a regular expression that filters the file
3af0304a 674names. Only the files that are under revision control are taken into account."
87c668b4 675 (interactive
bf5d92c5 676 (let ((dir-A (ediff-get-default-directory-name)))
87c668b4 677 (list (ediff-read-file-name
bbe6126c 678 "Directory to merge with revisions and ancestors:" dir-A nil)
6e31f65f
MK
679 (read-string (format
680 "Filter through regular expression (default %S): "
681 (eval ediff-default-filtering-regexp))
682 (eval ediff-default-filtering-regexp)
683 'ediff-filtering-regexp-history)
87c668b4
MK
684 )))
685 (ediff-directory-revisions-internal
686 dir1 regexp 'ediff-merge-revisions-with-ancestor
687 'ediff-merge-directory-revisions-with-ancestor
3af0304a 688 nil merge-autostore-dir
87c668b4
MK
689 ))
690
691;;;###autoload
692(defalias
693 'edir-merge-revisions-with-ancestor
71296446 694 'ediff-merge-directory-revisions-with-ancestor)
87c668b4
MK
695
696;;;###autoload
697(defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor)
698
699;; Run ediff-action (ediff-files, ediff-merge, ediff-merge-with-ancestors)
700;; on a pair of directories (three directories, in case of ancestor).
6dfd1bcc
MK
701;; The third argument, REGEXP, is nil or a regular expression;
702;; only file names that match the regexp are considered.
87c668b4 703;; JOBNAME is the symbol indicating the meta-job to be performed.
3af0304a 704;; MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
71296446 705(defun ediff-directories-internal (dir1 dir2 dir3 regexp action jobname
3af0304a
MK
706 &optional startup-hooks
707 merge-autostore-dir)
87c668b4 708 ;; ediff-read-file-name is set to attach a previously entered file name if
3af0304a 709 ;; the currently entered file is a directory. This code takes care of that.
87c668b4
MK
710 (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1))
711 dir2 (if (file-directory-p dir2) dir2 (file-name-directory dir2)))
712
713 (if (stringp dir3)
714 (setq dir3 (if (file-directory-p dir3) dir3 (file-name-directory dir3))))
715
716 (cond ((string= dir1 dir2)
717 (error "Directories A and B are the same: %s" dir1))
718 ((and (eq jobname 'ediff-directories3)
719 (string= dir1 dir3))
720 (error "Directories A and C are the same: %s" dir1))
721 ((and (eq jobname 'ediff-directories3)
722 (string= dir2 dir3))
723 (error "Directories B and C are the same: %s" dir1)))
724
3af0304a
MK
725 (if merge-autostore-dir
726 (or (stringp merge-autostore-dir)
727 (error "%s: Directory for storing merged files must be a string"
728 jobname)))
71296446 729 (let (;; dir-diff-struct is of the form (common-list diff-list)
c3912d54
MK
730 ;; It is a structure where ediff-intersect-directories returns
731 ;; commonalities and differences among directories
732 dir-diff-struct
733 meta-buf)
3af0304a
MK
734 (if (and ediff-autostore-merges
735 (ediff-merge-metajob jobname)
736 (not merge-autostore-dir))
71296446 737 (setq merge-autostore-dir
3af0304a
MK
738 (read-file-name "Save merged files in directory: "
739 (if ediff-use-last-dir
92c51e07
MK
740 ediff-last-merge-autostore-dir
741 (ediff-strip-last-dir dir1))
3af0304a
MK
742 nil
743 'must-match)))
92c51e07 744 ;; verify we are not merging into an orig directory
3af0304a 745 (if merge-autostore-dir
92c51e07 746 (cond ((and (stringp dir1) (string= merge-autostore-dir dir1))
3af0304a
MK
747 (or (y-or-n-p
748 "Directory for saving merged files = Directory A. Sure? ")
92c51e07
MK
749 (error "Directory merge aborted")))
750 ((and (stringp dir2) (string= merge-autostore-dir dir2))
3af0304a
MK
751 (or (y-or-n-p
752 "Directory for saving merged files = Directory B. Sure? ")
92c51e07
MK
753 (error "Directory merge aborted")))
754 ((and (stringp dir3) (string= merge-autostore-dir dir3))
755 (or (y-or-n-p
3af0304a 756 "Directory for saving merged files = Ancestor Directory. Sure? ")
92c51e07 757 (error "Directory merge aborted")))))
71296446
JB
758
759 (setq dir-diff-struct (ediff-intersect-directories
c3912d54
MK
760 jobname
761 regexp dir1 dir2 dir3 merge-autostore-dir))
87c668b4
MK
762 (setq startup-hooks
763 ;; this sets various vars in the meta buffer inside
764 ;; ediff-prepare-meta-buffer
086171bf
MK
765 (cons `(lambda ()
766 ;; tell what to do if the user clicks on a session record
767 (setq ediff-session-action-function (quote ,action))
71296446 768 ;; set ediff-dir-difference-list
c3912d54
MK
769 (setq ediff-dir-difference-list
770 (cdr (quote ,dir-diff-struct))))
87c668b4 771 startup-hooks))
71296446 772 (setq meta-buf (ediff-prepare-meta-buffer
bbe6126c 773 'ediff-filegroup-action
c3912d54 774 (car dir-diff-struct)
87c668b4
MK
775 "*Ediff Session Group Panel"
776 'ediff-redraw-directory-group-buffer
777 jobname
778 startup-hooks))
779 (ediff-show-meta-buffer meta-buf)
780 ))
781
3af0304a
MK
782;; MERGE-AUTOSTORE-DIR can be given to tell ediff where to store the merged
783;; files
71296446 784(defun ediff-directory-revisions-internal (dir1 regexp action jobname
3af0304a
MK
785 &optional startup-hooks
786 merge-autostore-dir)
87c668b4 787 (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1)))
92c51e07 788
3af0304a
MK
789 (if merge-autostore-dir
790 (or (stringp merge-autostore-dir)
791 (error "%S: Directory for storing merged files must be a string"
792 jobname)))
793 (let (file-list meta-buf)
71296446 794 (if (and ediff-autostore-merges
3af0304a
MK
795 (ediff-merge-metajob jobname)
796 (not merge-autostore-dir))
71296446 797 (setq merge-autostore-dir
3af0304a
MK
798 (read-file-name "Save merged files in directory: "
799 (if ediff-use-last-dir
800 ediff-last-merge-autostore-dir
801 (ediff-strip-last-dir dir1))
802 nil
803 'must-match)))
92c51e07 804 ;; verify merge-autostore-dir != dir1
3af0304a 805 (if (and merge-autostore-dir
92c51e07
MK
806 (stringp dir1)
807 (string= merge-autostore-dir dir1))
808 (or (y-or-n-p
3af0304a 809 "Directory for saving merged file = directory A. Sure? ")
92c51e07 810 (error "Merge of directory revisions aborted")))
71296446 811
87c668b4 812 (setq file-list
92c51e07
MK
813 (ediff-get-directory-files-under-revision
814 jobname regexp dir1 merge-autostore-dir))
87c668b4
MK
815 (setq startup-hooks
816 ;; this sets various vars in the meta buffer inside
817 ;; ediff-prepare-meta-buffer
086171bf
MK
818 (cons `(lambda ()
819 ;; tell what to do if the user clicks on a session record
820 (setq ediff-session-action-function (quote ,action)))
87c668b4 821 startup-hooks))
71296446 822 (setq meta-buf (ediff-prepare-meta-buffer
bbe6126c 823 'ediff-filegroup-action
87c668b4
MK
824 file-list
825 "*Ediff Session Group Panel"
826 'ediff-redraw-directory-group-buffer
827 jobname
828 startup-hooks))
829 (ediff-show-meta-buffer meta-buf)
830 ))
0f0b0a86
KH
831
832
833;;; Compare regions and windows
834
835;;;###autoload
f1a5512a
KH
836(defun ediff-windows-wordwise (dumb-mode &optional wind-A wind-B startup-hooks)
837 "Compare WIND-A and WIND-B, which are selected by clicking, wordwise.
0f0b0a86
KH
838With prefix argument, DUMB-MODE, or on a non-windowing display, works as
839follows:
840If WIND-A is nil, use selected window.
841If WIND-B is nil, use window next to WIND-A."
0f0b0a86 842 (interactive "P")
f1a5512a
KH
843 (ediff-windows dumb-mode wind-A wind-B
844 startup-hooks 'ediff-windows-wordwise 'word-mode))
71296446 845
f1a5512a
KH
846;;;###autoload
847(defun ediff-windows-linewise (dumb-mode &optional wind-A wind-B startup-hooks)
848 "Compare WIND-A and WIND-B, which are selected by clicking, linewise.
849With prefix argument, DUMB-MODE, or on a non-windowing display, works as
850follows:
851If WIND-A is nil, use selected window.
852If WIND-B is nil, use window next to WIND-A."
853 (interactive "P")
854 (ediff-windows dumb-mode wind-A wind-B
855 startup-hooks 'ediff-windows-linewise nil))
71296446 856
f1a5512a
KH
857;; Compare WIND-A and WIND-B, which are selected by clicking.
858;; With prefix argument, DUMB-MODE, or on a non-windowing display,
859;; works as follows:
860;; If WIND-A is nil, use selected window.
861;; If WIND-B is nil, use window next to WIND-A.
862(defun ediff-windows (dumb-mode wind-A wind-B startup-hooks job-name word-mode)
863 (if (or dumb-mode (not (ediff-window-display-p)))
0f0b0a86
KH
864 (setq wind-A (ediff-get-next-window wind-A nil)
865 wind-B (ediff-get-next-window wind-B wind-A))
866 (setq wind-A (ediff-get-window-by-clicking wind-A nil 1)
867 wind-B (ediff-get-window-by-clicking wind-B wind-A 2)))
71296446 868
0f0b0a86
KH
869 (let ((buffer-A (window-buffer wind-A))
870 (buffer-B (window-buffer wind-B))
871 beg-A end-A beg-B end-B)
71296446 872
0f0b0a86
KH
873 (save-excursion
874 (save-window-excursion
a7acbbe4 875 (sit-for 0) ; sync before using window-start/end -- a precaution
0f0b0a86
KH
876 (select-window wind-A)
877 (setq beg-A (window-start)
878 end-A (window-end))
879 (select-window wind-B)
880 (setq beg-B (window-start)
881 end-B (window-end))))
50a07e18
MK
882 (setq buffer-A
883 (ediff-clone-buffer-for-window-comparison
c3912d54 884 buffer-A wind-A "-Window.A-")
50a07e18
MK
885 buffer-B
886 (ediff-clone-buffer-for-window-comparison
c3912d54 887 buffer-B wind-B "-Window.B-"))
0f0b0a86
KH
888 (ediff-regions-internal
889 buffer-A beg-A end-A buffer-B beg-B end-B
ddc90f39 890 startup-hooks job-name word-mode nil)))
71296446 891
50a07e18 892
0f0b0a86 893;;;###autoload
f1a5512a 894(defun ediff-regions-wordwise (buffer-A buffer-B &optional startup-hooks)
50a07e18
MK
895 "Run Ediff on a pair of regions in specified buffers.
896Regions \(i.e., point and mark\) are assumed to be set in advance except
897for the second region in the case both regions are from the same buffer.
898In such a case the user is asked to interactively establish the second
899region.
0f0b0a86 900This function is effective only for relatively small regions, up to 200
3af0304a 901lines. For large regions, use `ediff-regions-linewise'."
71296446 902 (interactive
0f0b0a86
KH
903 (let (bf)
904 (list (setq bf (read-buffer "Region's A buffer: "
905 (ediff-other-buffer "") t))
906 (read-buffer "Region's B buffer: "
907 (progn
908 ;; realign buffers so that two visible bufs will be
909 ;; at the top
910 (save-window-excursion (other-window 1))
911 (ediff-other-buffer bf))
912 t))))
913 (if (not (ediff-buffer-live-p buffer-A))
914 (error "Buffer %S doesn't exist" buffer-A))
915 (if (not (ediff-buffer-live-p buffer-B))
916 (error "Buffer %S doesn't exist" buffer-B))
71296446
JB
917
918
50a07e18 919 (let ((buffer-A
c3912d54 920 (ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
50a07e18 921 (buffer-B
c3912d54 922 (ediff-clone-buffer-for-region-comparison buffer-B "-Region.B-"))
50a07e18 923 reg-A-beg reg-A-end reg-B-beg reg-B-end)
0f0b0a86
KH
924 (save-excursion
925 (set-buffer buffer-A)
926 (setq reg-A-beg (region-beginning)
927 reg-A-end (region-end))
928 (set-buffer buffer-B)
929 (setq reg-B-beg (region-beginning)
930 reg-B-end (region-end)))
71296446 931
0f0b0a86
KH
932 (ediff-regions-internal
933 (get-buffer buffer-A) reg-A-beg reg-A-end
934 (get-buffer buffer-B) reg-B-beg reg-B-end
ddc90f39 935 startup-hooks 'ediff-regions-wordwise 'word-mode nil)))
71296446 936
0f0b0a86 937;;;###autoload
f1a5512a 938(defun ediff-regions-linewise (buffer-A buffer-B &optional startup-hooks)
50a07e18
MK
939 "Run Ediff on a pair of regions in specified buffers.
940Regions \(i.e., point and mark\) are assumed to be set in advance except
941for the second region in the case both regions are from the same buffer.
942In such a case the user is asked to interactively establish the second
943region.
0f0b0a86
KH
944Each region is enlarged to contain full lines.
945This function is effective for large regions, over 100-200
3af0304a 946lines. For small regions, use `ediff-regions-wordwise'."
71296446 947 (interactive
0f0b0a86
KH
948 (let (bf)
949 (list (setq bf (read-buffer "Region A's buffer: "
950 (ediff-other-buffer "") t))
951 (read-buffer "Region B's buffer: "
952 (progn
953 ;; realign buffers so that two visible bufs will be
954 ;; at the top
955 (save-window-excursion (other-window 1))
956 (ediff-other-buffer bf))
957 t))))
fcbadd58 958 (if (not (ediff-buffer-live-p buffer-A))
0f0b0a86 959 (error "Buffer %S doesn't exist" buffer-A))
fcbadd58 960 (if (not (ediff-buffer-live-p buffer-B))
0f0b0a86 961 (error "Buffer %S doesn't exist" buffer-B))
71296446 962
50a07e18 963 (let ((buffer-A
c3912d54 964 (ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
50a07e18 965 (buffer-B
c3912d54 966 (ediff-clone-buffer-for-region-comparison buffer-B "-Region.B-"))
50a07e18 967 reg-A-beg reg-A-end reg-B-beg reg-B-end)
0f0b0a86
KH
968 (save-excursion
969 (set-buffer buffer-A)
970 (setq reg-A-beg (region-beginning)
971 reg-A-end (region-end))
972 ;; enlarge the region to hold full lines
71296446 973 (goto-char reg-A-beg)
0f0b0a86
KH
974 (beginning-of-line)
975 (setq reg-A-beg (point))
71296446 976 (goto-char reg-A-end)
0f0b0a86
KH
977 (end-of-line)
978 (or (eobp) (forward-char)) ; include the newline char
979 (setq reg-A-end (point))
71296446 980
0f0b0a86
KH
981 (set-buffer buffer-B)
982 (setq reg-B-beg (region-beginning)
983 reg-B-end (region-end))
984 ;; enlarge the region to hold full lines
71296446 985 (goto-char reg-B-beg)
0f0b0a86
KH
986 (beginning-of-line)
987 (setq reg-B-beg (point))
71296446 988 (goto-char reg-B-end)
0f0b0a86
KH
989 (end-of-line)
990 (or (eobp) (forward-char)) ; include the newline char
991 (setq reg-B-end (point))
992 ) ; save excursion
71296446 993
0f0b0a86
KH
994 (ediff-regions-internal
995 (get-buffer buffer-A) reg-A-beg reg-A-end
996 (get-buffer buffer-B) reg-B-beg reg-B-end
1e70790f 997 startup-hooks 'ediff-regions-linewise nil nil))) ; no word mode
71296446 998
0f0b0a86 999;; compare region beg-A to end-A of buffer-A
71296446 1000;; to regions beg-B -- end-B in buffer-B.
0f0b0a86 1001(defun ediff-regions-internal (buffer-A beg-A end-A buffer-B beg-B end-B
ddc90f39
MK
1002 startup-hooks job-name word-mode
1003 setup-parameters)
0f0b0a86
KH
1004 (let ((tmp-buffer (get-buffer-create ediff-tmp-buffer))
1005 overl-A overl-B
1006 file-A file-B)
71296446 1007
0f0b0a86 1008 ;; in case beg/end-A/B aren't markers--make them into markers
e756eb9f 1009 (ediff-with-current-buffer buffer-A
0f0b0a86
KH
1010 (setq beg-A (move-marker (make-marker) beg-A)
1011 end-A (move-marker (make-marker) end-A)))
e756eb9f 1012 (ediff-with-current-buffer buffer-B
0f0b0a86
KH
1013 (setq beg-B (move-marker (make-marker) beg-B)
1014 end-B (move-marker (make-marker) end-B)))
71296446 1015
0f0b0a86
KH
1016 ;; make file-A
1017 (if word-mode
1018 (ediff-wordify beg-A end-A buffer-A tmp-buffer)
1019 (ediff-copy-to-buffer beg-A end-A buffer-A tmp-buffer))
87c668b4 1020 (setq file-A (ediff-make-temp-file tmp-buffer "regA"))
71296446 1021
0f0b0a86
KH
1022 ;; make file-B
1023 (if word-mode
1024 (ediff-wordify beg-B end-B buffer-B tmp-buffer)
1025 (ediff-copy-to-buffer beg-B end-B buffer-B tmp-buffer))
87c668b4 1026 (setq file-B (ediff-make-temp-file tmp-buffer "regB"))
71296446 1027
0f0b0a86
KH
1028 (setq overl-A (ediff-make-bullet-proof-overlay beg-A end-A buffer-A))
1029 (setq overl-B (ediff-make-bullet-proof-overlay beg-B end-B buffer-B))
1030 (ediff-setup buffer-A file-A
1031 buffer-B file-B
1032 nil nil ; buffer & file C
086171bf
MK
1033 (cons `(lambda ()
1034 (delete-file ,file-A)
1035 (delete-file ,file-B))
813f532d 1036 startup-hooks)
ddc90f39
MK
1037 (append
1038 (list (cons 'ediff-word-mode word-mode)
1039 (cons 'ediff-narrow-bounds (list overl-A overl-B))
1040 (cons 'ediff-job-name job-name))
328b4b70 1041 setup-parameters))
0f0b0a86 1042 ))
71296446
JB
1043
1044
0f0b0a86 1045;;; Merge files and buffers
71296446 1046
0f0b0a86
KH
1047;;;###autoload
1048(defalias 'ediff-merge 'ediff-merge-files)
71296446 1049
0f0b0a86
KH
1050(defsubst ediff-merge-on-startup ()
1051 (ediff-do-merge 0)
e756eb9f 1052 (ediff-with-current-buffer ediff-buffer-C
0f0b0a86
KH
1053 (set-buffer-modified-p nil)))
1054
1055;;;###autoload
328b4b70
MK
1056(defun ediff-merge-files (file-A file-B
1057 ;; MERGE-BUFFER-FILE is the file to be
71296446 1058 ;; associated with the merge buffer
328b4b70 1059 &optional startup-hooks merge-buffer-file)
0f0b0a86
KH
1060 "Merge two files without ancestor."
1061 (interactive
1062 (let ((dir-A (if ediff-use-last-dir
1063 ediff-last-dir-A
1064 default-directory))
1065 dir-B f)
87c668b4 1066 (list (setq f (ediff-read-file-name
50a07e18
MK
1067 "File A to merge"
1068 dir-A
1069 (ediff-get-default-file-name)
1070 'no-dirs))
71296446 1071 (ediff-read-file-name "File B to merge"
0f0b0a86
KH
1072 (setq dir-B
1073 (if ediff-use-last-dir
71296446 1074 ediff-last-dir-B
0f0b0a86
KH
1075 (file-name-directory f)))
1076 (progn
1077 (setq file-name-history
87c668b4 1078 (cons (ediff-abbreviate-file-name
0f0b0a86
KH
1079 (expand-file-name
1080 (file-name-nondirectory f)
1081 dir-B))
1082 file-name-history))
657f9cb8 1083 (ediff-get-default-file-name f 1)))
0f0b0a86
KH
1084 )))
1085 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
71296446 1086 (ediff-files-internal file-A
0f0b0a86
KH
1087 (if (file-directory-p file-B)
1088 (expand-file-name
1089 (file-name-nondirectory file-A) file-B)
1090 file-B)
1091 nil ; file-C
1092 startup-hooks
328b4b70
MK
1093 'ediff-merge-files
1094 merge-buffer-file))
71296446 1095
0f0b0a86
KH
1096;;;###autoload
1097(defun ediff-merge-files-with-ancestor (file-A file-B file-ancestor
328b4b70
MK
1098 &optional
1099 startup-hooks
1100 ;; MERGE-BUFFER-FILE is the file
1101 ;; to be associated with the
1102 ;; merge buffer
1103 merge-buffer-file)
0f0b0a86
KH
1104 "Merge two files with ancestor."
1105 (interactive
1106 (let ((dir-A (if ediff-use-last-dir
1107 ediff-last-dir-A
1108 default-directory))
1109 dir-B dir-ancestor f ff)
87c668b4 1110 (list (setq f (ediff-read-file-name
50a07e18
MK
1111 "File A to merge"
1112 dir-A
1113 (ediff-get-default-file-name)
1114 'no-dirs))
71296446 1115 (setq ff (ediff-read-file-name "File B to merge"
0f0b0a86
KH
1116 (setq dir-B
1117 (if ediff-use-last-dir
71296446 1118 ediff-last-dir-B
0f0b0a86
KH
1119 (file-name-directory f)))
1120 (progn
1121 (setq file-name-history
1122 (cons
87c668b4 1123 (ediff-abbreviate-file-name
0f0b0a86
KH
1124 (expand-file-name
1125 (file-name-nondirectory f)
1126 dir-B))
1127 file-name-history))
657f9cb8 1128 (ediff-get-default-file-name f 1))))
71296446 1129 (ediff-read-file-name "Ancestor file"
0f0b0a86
KH
1130 (setq dir-ancestor
1131 (if ediff-use-last-dir
1132 ediff-last-dir-ancestor
1133 (file-name-directory ff)))
1134 (progn
1135 (setq file-name-history
87c668b4 1136 (cons (ediff-abbreviate-file-name
0f0b0a86
KH
1137 (expand-file-name
1138 (file-name-nondirectory ff)
1139 dir-ancestor))
1140 file-name-history))
657f9cb8 1141 (ediff-get-default-file-name ff 2)))
0f0b0a86
KH
1142 )))
1143 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
71296446 1144 (ediff-files-internal file-A
0f0b0a86
KH
1145 (if (file-directory-p file-B)
1146 (expand-file-name
1147 (file-name-nondirectory file-A) file-B)
1148 file-B)
1149 file-ancestor
1150 startup-hooks
328b4b70
MK
1151 'ediff-merge-files-with-ancestor
1152 merge-buffer-file))
71296446 1153
0f0b0a86
KH
1154;;;###autoload
1155(defalias 'ediff-merge-with-ancestor 'ediff-merge-files-with-ancestor)
71296446 1156
0f0b0a86 1157;;;###autoload
328b4b70
MK
1158(defun ediff-merge-buffers (buffer-A buffer-B
1159 &optional
1160 ;; MERGE-BUFFER-FILE is the file to be
1161 ;; associated with the merge buffer
1162 startup-hooks job-name merge-buffer-file)
0f0b0a86 1163 "Merge buffers without ancestor."
71296446 1164 (interactive
0f0b0a86
KH
1165 (let (bf)
1166 (list (setq bf (read-buffer "Buffer A to merge: "
1167 (ediff-other-buffer "") t))
1168 (read-buffer "Buffer B to merge: "
1169 (progn
1170 ;; realign buffers so that two visible bufs will be
1171 ;; at the top
1172 (save-window-excursion (other-window 1))
1173 (ediff-other-buffer bf))
1174 t))))
71296446 1175
0f0b0a86
KH
1176 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
1177 (or job-name (setq job-name 'ediff-merge-buffers))
1178 (ediff-buffers-internal
328b4b70 1179 buffer-A buffer-B nil startup-hooks job-name merge-buffer-file))
71296446 1180
0f0b0a86 1181;;;###autoload
328b4b70
MK
1182(defun ediff-merge-buffers-with-ancestor (buffer-A buffer-B buffer-ancestor
1183 &optional
1184 startup-hooks
1185 job-name
1186 ;; MERGE-BUFFER-FILE is the
1187 ;; file to be associated
1188 ;; with the merge buffer
1189 merge-buffer-file)
0f0b0a86 1190 "Merge buffers with ancestor."
71296446 1191 (interactive
0f0b0a86
KH
1192 (let (bf bff)
1193 (list (setq bf (read-buffer "Buffer A to merge: "
1194 (ediff-other-buffer "") t))
1195 (setq bff (read-buffer "Buffer B to merge: "
1196 (progn
1197 ;; realign buffers so that two visible
1198 ;; bufs will be at the top
1199 (save-window-excursion (other-window 1))
1200 (ediff-other-buffer bf))
1201 t))
1202 (read-buffer "Ancestor buffer: "
1203 (progn
1204 ;; realign buffers so that three visible
1205 ;; bufs will be at the top
1206 (save-window-excursion (other-window 1))
1207 (ediff-other-buffer (list bf bff)))
1208 t)
1209 )))
71296446 1210
0f0b0a86
KH
1211 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
1212 (or job-name (setq job-name 'ediff-merge-buffers-with-ancestor))
1213 (ediff-buffers-internal
328b4b70 1214 buffer-A buffer-B buffer-ancestor startup-hooks job-name merge-buffer-file))
71296446 1215
0f0b0a86
KH
1216
1217;;;###autoload
328b4b70
MK
1218(defun ediff-merge-revisions (&optional file startup-hooks merge-buffer-file)
1219 ;; MERGE-BUFFER-FILE is the file to be associated with the merge buffer
0f0b0a86 1220 "Run Ediff by merging two revisions of a file.
87c668b4
MK
1221The file is the optional FILE argument or the file visited by the current
1222buffer."
1223 (interactive)
87c668b4 1224 (if (stringp file) (find-file file))
4ae69eac 1225 (let (rev1 rev2)
87c668b4
MK
1226 (setq rev1
1227 (read-string
1228 (format
743a79af 1229 "Version 1 to merge (default: %s's working version): "
87c668b4
MK
1230 (if (stringp file)
1231 (file-name-nondirectory file) "current buffer")))
1232 rev2
1233 (read-string
1234 (format
1235 "Version 2 to merge (default: %s): "
1236 (if (stringp file)
1237 (file-name-nondirectory file) "current buffer"))))
4ae69eac
MK
1238 (ediff-load-version-control)
1239 ;; ancestor-revision=nil
1240 (funcall
92c51e07 1241 (intern (format "ediff-%S-merge-internal" ediff-version-control-package))
328b4b70 1242 rev1 rev2 nil startup-hooks merge-buffer-file)))
71296446 1243
0f0b0a86
KH
1244
1245;;;###autoload
328b4b70
MK
1246(defun ediff-merge-revisions-with-ancestor (&optional
1247 file startup-hooks
1248 ;; MERGE-BUFFER-FILE is the file to
1249 ;; be associated with the merge
1250 ;; buffer
1251 merge-buffer-file)
87c668b4 1252 "Run Ediff by merging two revisions of a file with a common ancestor.
110c171f 1253The file is the optional FILE argument or the file visited by the current
87c668b4
MK
1254buffer."
1255 (interactive)
87c668b4 1256 (if (stringp file) (find-file file))
4ae69eac 1257 (let (rev1 rev2 ancestor-rev)
87c668b4
MK
1258 (setq rev1
1259 (read-string
1260 (format
743a79af 1261 "Version 1 to merge (default: %s's working version): "
87c668b4
MK
1262 (if (stringp file)
1263 (file-name-nondirectory file) "current buffer")))
1264 rev2
1265 (read-string
1266 (format
1267 "Version 2 to merge (default: %s): "
1268 (if (stringp file)
1269 (file-name-nondirectory file) "current buffer")))
1270 ancestor-rev
1271 (read-string
1272 (format
3af0304a 1273 "Ancestor version (default: %s's base revision): "
87c668b4
MK
1274 (if (stringp file)
1275 (file-name-nondirectory file) "current buffer"))))
4ae69eac
MK
1276 (ediff-load-version-control)
1277 (funcall
92c51e07 1278 (intern (format "ediff-%S-merge-internal" ediff-version-control-package))
328b4b70 1279 rev1 rev2 ancestor-rev startup-hooks merge-buffer-file)))
4ae69eac 1280
50a07e18 1281;; MK: Check. This function doesn't seem to be used any more by pcvs or pcl-cvs
4ae69eac
MK
1282;;;###autoload
1283(defun run-ediff-from-cvs-buffer (pos)
1284 "Run Ediff-merge on appropriate revisions of the selected file.
3af0304a 1285First run after `M-x cvs-update'. Then place the cursor on a line describing a
4ae69eac
MK
1286file and then run `run-ediff-from-cvs-buffer'."
1287 (interactive "d")
1288 (ediff-load-version-control)
1289 (let ((tin (tin-locate cvs-cookie-handle pos)))
1290 (if tin
1291 (cvs-run-ediff-on-file-descriptor tin)
1292 (error "There is no file to merge"))))
71296446
JB
1293
1294
0f0b0a86 1295;;; Apply patch
0f0b0a86 1296
bbe6126c 1297;;;###autoload
3af0304a
MK
1298(defun ediff-patch-file (&optional arg patch-buf)
1299 "Run Ediff by patching SOURCE-FILENAME.
1300If optional PATCH-BUF is given, use the patch in that buffer
1301and don't ask the user.
1302If prefix argument, then: if even argument, assume that the patch is in a
1303buffer. If odd -- assume it is in a file."
1304 (interactive "P")
1305 (let (source-dir source-file)
bbe6126c 1306 (require 'ediff-ptch)
3af0304a
MK
1307 (setq patch-buf
1308 (ediff-get-patch-buffer
1309 (if arg (prefix-numeric-value arg)) patch-buf))
bbe6126c
MK
1310 (setq source-dir (cond (ediff-use-last-dir ediff-last-dir-patch)
1311 ((and (not ediff-patch-default-directory)
1312 (buffer-file-name patch-buf))
1313 (file-name-directory
1314 (expand-file-name
1315 (buffer-file-name patch-buf))))
1316 (t default-directory)))
1317 (setq source-file
71296446 1318 (read-file-name
3af0304a 1319 "File to patch (directory, if multifile patch): "
2550055a
MK
1320 ;; use an explicit initial file
1321 source-dir nil nil (ediff-get-default-file-name)))
bbe6126c 1322 (ediff-dispatch-file-patching-job patch-buf source-file)))
0f0b0a86 1323
bbe6126c 1324;;;###autoload
3af0304a 1325(defun ediff-patch-buffer (&optional arg patch-buf)
7261ece3
MK
1326 "Run Ediff by patching BUFFER-NAME.
1327Without prefix argument: asks if the patch is in some buffer and prompts for
1328the buffer or a file, depending on the answer.
1329With prefix arg=1: assumes the patch is in a file and prompts for the file.
1330With prefix arg=2: assumes the patch is in a buffer and prompts for the buffer."
3af0304a
MK
1331 (interactive "P")
1332 (require 'ediff-ptch)
1333 (setq patch-buf
1334 (ediff-get-patch-buffer
1335 (if arg (prefix-numeric-value arg)) patch-buf))
1336 (ediff-patch-buffer-internal
1337 patch-buf
1338 (read-buffer
1339 "Which buffer to patch? "
7261ece3 1340 (current-buffer))))
71296446 1341
3af0304a 1342
bbe6126c
MK
1343;;;###autoload
1344(defalias 'epatch 'ediff-patch-file)
1345;;;###autoload
1346(defalias 'epatch-buffer 'ediff-patch-buffer)
0f0b0a86
KH
1347
1348
813f532d 1349
0f0b0a86 1350\f
71296446
JB
1351;;; Versions Control functions
1352
813f532d 1353;;;###autoload
87c668b4
MK
1354(defun ediff-revision (&optional file startup-hooks)
1355 "Run Ediff by comparing versions of a file.
7261ece3
MK
1356The file is an optional FILE argument or the file entered at the prompt.
1357Default: the file visited by the current buffer.
1358Uses `vc.el' or `rcs.el' depending on `ediff-version-control-package'."
87c668b4 1359 ;; if buffer is non-nil, use that buffer instead of the current buffer
f1a5512a 1360 (interactive "P")
7261ece3
MK
1361 (if (not (stringp file))
1362 (setq file
1363 (ediff-read-file-name "Compare revisions for file"
1364 (if ediff-use-last-dir
1365 ediff-last-dir-A
1366 default-directory)
50a07e18 1367 (ediff-get-default-file-name)
71296446 1368 'no-dirs)))
7261ece3
MK
1369 (find-file file)
1370 (if (and (buffer-modified-p)
1371 (y-or-n-p (message "Buffer %s is modified. Save buffer? "
1372 (buffer-name))))
1373 (save-buffer (current-buffer)))
f1a5512a 1374 (let (rev1 rev2)
87c668b4
MK
1375 (setq rev1
1376 (read-string
0831d50c 1377 (format "Revision 1 to compare (default: %s's latest revision): "
7261ece3 1378 (file-name-nondirectory file)))
87c668b4 1379 rev2
71296446 1380 (read-string
0831d50c 1381 (format "Revision 2 to compare (default: %s's current state): "
7261ece3 1382 (file-name-nondirectory file))))
f1a5512a
KH
1383 (ediff-load-version-control)
1384 (funcall
92c51e07 1385 (intern (format "ediff-%S-internal" ediff-version-control-package))
87c668b4 1386 rev1 rev2 startup-hooks)
f1a5512a 1387 ))
1e70790f
MK
1388
1389
1390;;;###autoload
1391(defalias 'erevision 'ediff-revision)
71296446
JB
1392
1393
0f0b0a86
KH
1394;; Test if version control package is loaded and load if not
1395;; Is SILENT is non-nil, don't report error if package is not found.
1396(defun ediff-load-version-control (&optional silent)
4ae69eac 1397 (require 'ediff-vers)
0f0b0a86
KH
1398 (or (featurep ediff-version-control-package)
1399 (if (locate-library (symbol-name ediff-version-control-package))
1400 (progn
1401 (message "") ; kill the message from `locate-library'
87c668b4 1402 (require ediff-version-control-package))
0f0b0a86 1403 (or silent
3af0304a 1404 (error "Version control package %S.el not found. Use vc.el instead"
0f0b0a86 1405 ediff-version-control-package)))))
87c668b4 1406
b3a26225 1407
138df2ce
MK
1408;;;###autoload
1409(defun ediff-version ()
1410 "Return string describing the version of Ediff.
1411When called interactively, displays the version."
1412 (interactive)
1413 (if (interactive-p)
1414 (message (ediff-version))
1415 (format "Ediff %s of %s" ediff-version ediff-date)))
1416
813f532d 1417
4ae69eac 1418;;;###autoload
92c51e07
MK
1419(defun ediff-documentation (&optional node)
1420 "Display Ediff's manual.
1421With optional NODE, goes to that node."
4ae69eac
MK
1422 (interactive)
1423 (let ((ctl-window ediff-control-window)
1424 (ctl-buf ediff-control-buffer))
1425
1426 (ediff-skip-unsuitable-frames)
1427 (condition-case nil
1428 (progn
1429 (pop-to-buffer (get-buffer-create "*info*"))
1430 (info (if ediff-xemacs-p "ediff.info" "ediff"))
92c51e07
MK
1431 (if node
1432 (Info-goto-node node)
1433 (message "Type `i' to search for a specific topic"))
1434 (raise-frame (selected-frame)))
4ae69eac 1435 (error (beep 1)
bbe6126c 1436 (with-output-to-temp-buffer ediff-msg-buffer
e4d2c130
DL
1437 (ediff-with-current-buffer standard-output
1438 (fundamental-mode))
92c51e07 1439 (princ ediff-BAD-INFO))
4ae69eac
MK
1440 (if (window-live-p ctl-window)
1441 (progn
1442 (select-window ctl-window)
1443 (set-window-buffer ctl-window ctl-buf)))))))
71296446 1444
4ae69eac
MK
1445
1446
1447
1448;;; Local Variables:
1449;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
e756eb9f
MK
1450;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
1451;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
4ae69eac
MK
1452;;; End:
1453
0f0b0a86 1454(require 'ediff-util)
813f532d 1455
3af0304a
MK
1456(run-hooks 'ediff-load-hook)
1457
ab5796a9 1458;;; arch-tag: 97c71396-db02-4f41-8b48-6a51c3348fcc
813f532d 1459;;; ediff.el ends here