Fix up coding system.
[bpt/emacs.git] / lisp / ediff.el
CommitLineData
0f0b0a86 1;;; ediff.el --- a comprehensive visual interface to diff & patch
b578f267 2
ddc90f39 3;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
813f532d
RS
4
5;; Author: Michael Kifer <kifer@cs.sunysb.edu>
6;; Created: February 2, 1994
fcbadd58 7;; Keywords: comparing, merging, patching, version control.
813f532d 8
e756eb9f
MK
9(defconst ediff-version "2.67" "The current version of Ediff")
10(defconst ediff-date "July 31, 1997" "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
MK
44;; Ediff also supports merging operations on files and buffers, including
45;; merging using ancestor versions. Both comparison and merging operations can
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
KH
58;; Ediff is aware of version control, which lets the user compare
59;; files with their older versions. Ediff can also work with remote and
60;; compressed files. Details are given below.
61
bbe6126c 62;; Finally, Ediff supports directory-level comparison, merging and patching.
87c668b4 63;; See the on-line manual for details.
813f532d 64
87c668b4
MK
65;; This package builds upon the ideas borrowed from emerge.el and several
66;; Ediff's functions are adaptations from emerge.el. Much of the functionality
67;; Ediff provides is also influenced by emerge.el.
68
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
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
RS
77
78;; 1. The undo command doesn't restore deleted regions well. That is, if
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
b3a26225 88;; highlight fine differences is limited. By default, Ediff is using
a7acbbe4 89;; underlining. However, if the region is already underlined by some other
b3a26225
RS
90;; overlays, there is no simple way to temporarily remove that residual
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
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"
139 :group 'tools)
140
141
142(defcustom ediff-use-last-dir nil
1e70790f 143 "*If t, Ediff will use previous directory as default when reading file name."
ddc90f39
MK
144 :type 'boolean
145 :group 'ediff)
bbe6126c 146
1e70790f
MK
147;; Last directory used by an Ediff command for file-A.
148(defvar ediff-last-dir-A nil)
149;; Last directory used by an Ediff command for file-B.
150(defvar ediff-last-dir-B nil)
151;; Last directory used by an Ediff command for file-C.
152(defvar ediff-last-dir-C nil)
153;; Last directory used by an Ediff command for the ancestor file.
154(defvar ediff-last-dir-ancestor nil)
155;; Last directory used by an Ediff command as the output directory for merge.
156(defvar ediff-last-merge-autostore-dir)
813f532d 157
87c668b4 158
4ae69eac 159;; Used as a startup hook to set `_orig' patch file read-only.
f1a5512a 160(defun ediff-set-read-only-in-buf-A ()
e756eb9f 161 (ediff-with-current-buffer ediff-buffer-A
f1a5512a 162 (toggle-read-only 1)))
813f532d 163
87c668b4
MK
164;; Return a plausible default for ediff's first file:
165;; In dired, return the file name under the point, unless it is a directory
166;; If the buffer has a file name, return that file name.
167(defun ediff-get-default-file-name ()
168 (cond ((eq major-mode 'dired-mode)
169 (let ((f (dired-get-filename nil 'no-error)))
170 (if (and (stringp f) (not (file-directory-p f)))
171 f)))
172 ((buffer-file-name (current-buffer))
173 (file-name-nondirectory (buffer-file-name (current-buffer))))
174 ))
175
0f0b0a86 176;;; Compare files/buffers
813f532d
RS
177
178;;;###autoload
179(defun ediff-files (file-A file-B &optional startup-hooks)
0f0b0a86 180 "Run Ediff on a pair of files, FILE-A and FILE-B."
813f532d 181 (interactive
0f0b0a86
KH
182 (let ((dir-A (if ediff-use-last-dir
183 ediff-last-dir-A
184 default-directory))
185 dir-B f)
87c668b4
MK
186 (list (setq f (ediff-read-file-name
187 "File A to compare" dir-A
188 (ediff-get-default-file-name)))
813f532d 189 (ediff-read-file-name "File B to compare"
0f0b0a86
KH
190 (setq dir-B
191 (if ediff-use-last-dir
192 ediff-last-dir-B
193 (file-name-directory f)))
194 (progn
195 (setq file-name-history
87c668b4 196 (cons (ediff-abbreviate-file-name
0f0b0a86
KH
197 (expand-file-name
198 (file-name-nondirectory f)
199 dir-B))
200 file-name-history))
201 f))
202 )))
203 (ediff-files-internal file-A
204 (if (file-directory-p file-B)
205 (expand-file-name
206 (file-name-nondirectory file-A) file-B)
207 file-B)
208 nil ; file-C
209 startup-hooks
210 'ediff-files))
211
212;;;###autoload
213(defun ediff-files3 (file-A file-B file-C &optional startup-hooks)
214 "Run Ediff on three files, FILE-A, FILE-B, and FILE-C."
215 (interactive
216 (let ((dir-A (if ediff-use-last-dir
217 ediff-last-dir-A
218 default-directory))
219 dir-B dir-C f ff)
87c668b4
MK
220 (list (setq f (ediff-read-file-name
221 "File A to compare" dir-A
222 (ediff-get-default-file-name)))
0f0b0a86
KH
223 (setq ff (ediff-read-file-name "File B to compare"
224 (setq dir-B
225 (if ediff-use-last-dir
226 ediff-last-dir-B
227 (file-name-directory f)))
228 (progn
229 (setq file-name-history
230 (cons
87c668b4 231 (ediff-abbreviate-file-name
0f0b0a86
KH
232 (expand-file-name
233 (file-name-nondirectory f)
234 dir-B))
235 file-name-history))
236 f)))
237 (ediff-read-file-name "File C to compare"
238 (setq dir-C (if ediff-use-last-dir
239 ediff-last-dir-C
240 (file-name-directory ff)))
241 (progn
242 (setq file-name-history
87c668b4 243 (cons (ediff-abbreviate-file-name
0f0b0a86
KH
244 (expand-file-name
245 (file-name-nondirectory ff)
246 dir-C))
247 file-name-history))
248 ff))
813f532d 249 )))
b3a26225
RS
250 (ediff-files-internal file-A
251 (if (file-directory-p file-B)
252 (expand-file-name
253 (file-name-nondirectory file-A) file-B)
254 file-B)
0f0b0a86
KH
255 (if (file-directory-p file-C)
256 (expand-file-name
257 (file-name-nondirectory file-A) file-C)
258 file-C)
259 startup-hooks
260 'ediff-files3))
813f532d 261
0f0b0a86
KH
262;;;###autoload
263(defalias 'ediff3 'ediff-files3)
813f532d 264
813f532d 265
4ae69eac
MK
266;; Visit FILE and arrange its buffer to Ediff's liking.
267;; FILE is actually a variable symbol that must contain a true file name.
268;; BUFFER-NAME is a variable symbol, which will get the buffer object into
269;; which FILE is read.
270;; LAST-DIR is the directory variable symbol where FILE's
271;; directory name should be returned. HOOKS-VAR is a variable symbol that will
272;; be assigned the hook to be executed after `ediff-startup' is finished.
273;; `ediff-find-file' arranges that the temp files it might create will be
274;; deleted.
0f0b0a86 275(defun ediff-find-file (file-var buffer-name &optional last-dir hooks-var)
0f0b0a86 276 (let* ((file (symbol-value file-var))
f1a5512a 277 (file-magic (find-file-name-handler file 'find-file-noselect))
0f0b0a86 278 (temp-file-name-prefix (file-name-nondirectory file)))
87c668b4
MK
279 (cond ((not (file-readable-p file))
280 (error "File `%s' does not exist or is not readable" file))
281 ((file-directory-p file)
282 (error "File `%s' is a directory" file)))
0f0b0a86 283
4ae69eac 284 ;; some of the commands, below, require full file name
0f0b0a86
KH
285 (setq file (expand-file-name file))
286
287 ;; Record the directory of the file
288 (if last-dir
289 (set last-dir (expand-file-name (file-name-directory file))))
290
291 ;; Setup the buffer
292 (set buffer-name (find-file-noselect file))
293
e756eb9f 294 (ediff-with-current-buffer (symbol-value buffer-name)
0f0b0a86 295 (widen) ; Make sure the entire file is seen
ddc90f39
MK
296 (cond (file-magic ; file has a handler, such as jka-compr-handler or
297 ;;; ange-ftp-hook-function--arrange for temp file
0f0b0a86 298 (ediff-verify-file-buffer 'magic)
87c668b4
MK
299 (setq file
300 (ediff-make-temp-file
301 (current-buffer) temp-file-name-prefix))
0f0b0a86
KH
302 (set hooks-var (cons (` (lambda () (delete-file (, file))))
303 (symbol-value hooks-var))))
304 ;; file processed via auto-mode-alist, a la uncompress.el
305 ((not (equal (file-truename file)
306 (file-truename (buffer-file-name))))
87c668b4
MK
307 (setq file
308 (ediff-make-temp-file
309 (current-buffer) temp-file-name-prefix))
0f0b0a86
KH
310 (set hooks-var (cons (` (lambda () (delete-file (, file))))
311 (symbol-value hooks-var))))
312 (t ;; plain file---just check that the file matches the buffer
313 (ediff-verify-file-buffer))))
314 (set file-var file)))
315
316(defun ediff-files-internal (file-A file-B file-C startup-hooks job-name)
317 (let (buf-A buf-B buf-C)
87c668b4
MK
318 (message "Reading file %s ... " file-A)
319 ;;(sit-for 0)
0f0b0a86 320 (ediff-find-file 'file-A 'buf-A 'ediff-last-dir-A 'startup-hooks)
87c668b4
MK
321 (message "Reading file %s ... " file-B)
322 ;;(sit-for 0)
0f0b0a86 323 (ediff-find-file 'file-B 'buf-B 'ediff-last-dir-B 'startup-hooks)
87c668b4 324 (if (stringp file-C)
0f0b0a86 325 (progn
87c668b4
MK
326 (message "Reading file %s ... " file-C)
327 ;;(sit-for 0)
0f0b0a86
KH
328 (ediff-find-file
329 'file-C 'buf-C
330 (if (eq job-name 'ediff-merge-files-with-ancestor)
331 'ediff-last-dir-ancestor 'ediff-last-dir-C)
332 'startup-hooks)))
333 (ediff-setup buf-A file-A
334 buf-B file-B
335 buf-C file-C
336 startup-hooks
337 (list (cons 'ediff-job-name job-name)))))
338
339
340;;;###autoload
341(defalias 'ediff 'ediff-files)
813f532d 342
813f532d
RS
343
344;;;###autoload
0f0b0a86 345(defun ediff-buffers (buffer-A buffer-B &optional startup-hooks job-name)
813f532d 346 "Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B."
fcbadd58 347 (interactive
0f0b0a86
KH
348 (let (bf)
349 (list (setq bf (read-buffer "Buffer A to compare: "
350 (ediff-other-buffer "") t))
351 (read-buffer "Buffer B to compare: "
352 (progn
353 ;; realign buffers so that two visible bufs will be
354 ;; at the top
355 (save-window-excursion (other-window 1))
356 (ediff-other-buffer bf))
357 t))))
0f0b0a86
KH
358 (or job-name (setq job-name 'ediff-buffers))
359 (ediff-buffers-internal buffer-A buffer-B nil startup-hooks job-name))
bbe6126c
MK
360
361;;;###autoload
362(defalias 'ebuffers 'ediff-buffers)
363
0f0b0a86
KH
364
365;;;###autoload
366(defun ediff-buffers3 (buffer-A buffer-B buffer-C
367 &optional startup-hooks job-name)
368 "Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C."
369 (interactive
370 (let (bf bff)
371 (list (setq bf (read-buffer "Buffer A to compare: "
372 (ediff-other-buffer "") t))
373 (setq bff (read-buffer "Buffer B to compare: "
374 (progn
375 ;; realign buffers so that two visible
376 ;; bufs will be at the top
377 (save-window-excursion (other-window 1))
378 (ediff-other-buffer bf))
379 t))
380 (read-buffer "Buffer C to compare: "
381 (progn
382 ;; realign buffers so that three visible
383 ;; bufs will be at the top
384 (save-window-excursion (other-window 1))
385 (ediff-other-buffer (list bf bff)))
386 t)
387 )))
0f0b0a86
KH
388 (or job-name (setq job-name 'ediff-buffers3))
389 (ediff-buffers-internal buffer-A buffer-B buffer-C startup-hooks job-name))
bbe6126c
MK
390
391;;;###autoload
392(defalias 'ebuffers3 'ediff-buffers3)
0f0b0a86
KH
393
394
395
396(defun ediff-buffers-internal (buf-A buf-B buf-C startup-hooks job-name)
397 (let* ((buf-A-file-name (buffer-file-name (get-buffer buf-A)))
398 (buf-B-file-name (buffer-file-name (get-buffer buf-B)))
399 (buf-C-is-alive (ediff-buffer-live-p buf-C))
400 (buf-C-file-name (if buf-C-is-alive
401 (buffer-file-name (get-buffer buf-B))))
402 file-A file-B file-C)
403 (if (not (ediff-buffer-live-p buf-A))
404 (error "Buffer %S doesn't exist" buf-A))
405 (if (not (ediff-buffer-live-p buf-B))
406 (error "Buffer %S doesn't exist" buf-B))
407 (let ((ediff-job-name job-name))
408 (if (and ediff-3way-comparison-job
409 (not buf-C-is-alive))
410 (error "Buffer %S doesn't exist" buf-C)))
411 (if (stringp buf-A-file-name)
412 (setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
413 (if (stringp buf-B-file-name)
414 (setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
415 (if (stringp buf-C-file-name)
416 (setq buf-C-file-name (file-name-nondirectory buf-C-file-name)))
417
4ae69eac
MK
418 (setq file-A (ediff-make-temp-file buf-A buf-A-file-name)
419 file-B (ediff-make-temp-file buf-B buf-B-file-name))
0f0b0a86 420 (if buf-C-is-alive
87c668b4 421 (setq file-C (ediff-make-temp-file buf-C buf-C-file-name)))
0f0b0a86
KH
422
423 (ediff-setup (get-buffer buf-A) file-A
424 (get-buffer buf-B) file-B
425 (if buf-C-is-alive (get-buffer buf-C))
426 file-C
427 (cons (` (lambda ()
428 (delete-file (, file-A))
429 (delete-file (, file-B))
430 (if (stringp (, file-C)) (delete-file (, file-C)))
431 ))
432 startup-hooks)
433 (list (cons 'ediff-job-name job-name))
434 )))
87c668b4
MK
435
436
437;;; Directory and file group operations
438
439;; Get appropriate default name for directory:
440;; If ediff-use-last-dir, use ediff-last-dir-A.
441;; In dired mode, use the directory that is under the point (if any);
442;; otherwise, use default-directory
443(defun ediff-get-default-directory-name ()
444 (cond (ediff-use-last-dir ediff-last-dir-A)
445 ((eq major-mode 'dired-mode)
446 (let ((f (dired-get-filename nil 'noerror)))
447 (if (and (stringp f) (file-directory-p f))
448 f
449 default-directory)))
450 (t default-directory)))
451
452
453;;;###autoload
454(defun ediff-directories (dir1 dir2 regexp)
455 "Run Ediff on a pair of directories, DIR1 and DIR2, comparing files that have
456the same name in both. The third argument, REGEXP, is a regular expression that
bbe6126c 457can be used to filter out certain file names."
87c668b4
MK
458 (interactive
459 (let ((dir-A (ediff-get-default-directory-name))
460 f)
bbe6126c
MK
461 (list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
462 (ediff-read-file-name "Directory B to compare:"
87c668b4
MK
463 (if ediff-use-last-dir
464 ediff-last-dir-B
465 (ediff-strip-last-dir f))
466 nil)
467 (read-string "Filter through regular expression: "
bbe6126c 468 nil 'ediff-filtering-regexp-history)
87c668b4
MK
469 )))
470 (ediff-directories-internal
471 dir1 dir2 nil regexp 'ediff-files 'ediff-directories
472 ))
473
474;;;###autoload
475(defalias 'edirs 'ediff-directories)
476
477
478;;;###autoload
479(defun ediff-directory-revisions (dir1 regexp)
480 "Run Ediff on a directory, DIR1, comparing its files with their revisions.
481The second argument, REGEXP, is a regular expression that filters the file
482names. Only the files that are under revision control are taken into account."
483 (interactive
484 (let ((dir-A (ediff-get-default-directory-name)))
485 (list (ediff-read-file-name
bbe6126c 486 "Directory to compare with revision:" dir-A nil)
87c668b4 487 (read-string "Filter through regular expression: "
bbe6126c 488 nil 'ediff-filtering-regexp-history)
87c668b4
MK
489 )))
490 (ediff-directory-revisions-internal
491 dir1 regexp 'ediff-revision 'ediff-directory-revisions
492 ))
493
494;;;###autoload
495(defalias 'edir-revisions 'ediff-directory-revisions)
496
497
498;;;###autoload
499(defun ediff-directories3 (dir1 dir2 dir3 regexp)
500 "Run Ediff on three directories, DIR1, DIR2, and DIR3, comparing files that
501have the same name in all three. The last argument, REGEXP, is a regular
bbe6126c 502expression that can be used to filter out certain file names."
87c668b4
MK
503 (interactive
504 (let ((dir-A (ediff-get-default-directory-name))
505 f)
bbe6126c
MK
506 (list (setq f (ediff-read-file-name "Directory A to compare:" dir-A nil))
507 (setq f (ediff-read-file-name "Directory B to compare:"
87c668b4
MK
508 (if ediff-use-last-dir
509 ediff-last-dir-B
510 (ediff-strip-last-dir f))
511 nil))
bbe6126c 512 (ediff-read-file-name "Directory C to compare:"
87c668b4
MK
513 (if ediff-use-last-dir
514 ediff-last-dir-C
515 (ediff-strip-last-dir f))
516 nil)
517 (read-string "Filter through regular expression: "
bbe6126c 518 nil 'ediff-filtering-regexp-history)
87c668b4
MK
519 )))
520 (ediff-directories-internal
521 dir1 dir2 dir3 regexp 'ediff-files3 'ediff-directories3
522 ))
523
524;;;###autoload
525(defalias 'edirs3 'ediff-directories3)
526
527;;;###autoload
528(defun ediff-merge-directories (dir1 dir2 regexp)
529 "Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have
530the same name in both. The third argument, REGEXP, is a regular expression that
bbe6126c 531can be used to filter out certain file names."
87c668b4
MK
532 (interactive
533 (let ((dir-A (ediff-get-default-directory-name))
534 f)
bbe6126c
MK
535 (list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
536 (ediff-read-file-name "Directory B to merge:"
87c668b4
MK
537 (if ediff-use-last-dir
538 ediff-last-dir-B
539 (ediff-strip-last-dir f))
540 nil)
541 (read-string "Filter through regular expression: "
bbe6126c 542 nil 'ediff-filtering-regexp-history)
87c668b4
MK
543 )))
544 (ediff-directories-internal
545 dir1 dir2 nil regexp 'ediff-merge-files 'ediff-merge-directories
546 ))
547
548;;;###autoload
549(defalias 'edirs-merge 'ediff-merge-directories)
550
551;;;###autoload
bbe6126c
MK
552(defun ediff-merge-directories-with-ancestor (dir1 dir2 ancestor-dir regexp)
553 "Merge files in directories DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors.
554Ediff merges files that have identical names in DIR1, DIR2. If a pair of files
555in DIR1 and DIR2 doesn't have an ancestor in ANCESTOR-DIR, Ediff will merge
556without ancestor. The fourth argument, REGEXP, is a regular expression that
557can be used to filter out certain file names."
87c668b4
MK
558 (interactive
559 (let ((dir-A (ediff-get-default-directory-name))
560 f)
bbe6126c
MK
561 (list (setq f (ediff-read-file-name "Directory A to merge:" dir-A nil))
562 (setq f (ediff-read-file-name "Directory B to merge:"
87c668b4
MK
563 (if ediff-use-last-dir
564 ediff-last-dir-B
565 (ediff-strip-last-dir f))
566 nil))
bbe6126c 567 (ediff-read-file-name "Ancestor directory:"
87c668b4
MK
568 (if ediff-use-last-dir
569 ediff-last-dir-C
570 (ediff-strip-last-dir f))
571 nil)
572 (read-string "Filter through regular expression: "
bbe6126c 573 nil 'ediff-filtering-regexp-history)
87c668b4
MK
574 )))
575 (ediff-directories-internal
bbe6126c 576 dir1 dir2 ancestor-dir regexp
87c668b4
MK
577 'ediff-merge-files-with-ancestor 'ediff-merge-directories-with-ancestor
578 ))
579
580;;;###autoload
581(defun ediff-merge-directory-revisions (dir1 regexp)
582 "Run Ediff on a directory, DIR1, merging its files with their revisions.
583The second argument, REGEXP, is a regular expression that filters the file
584names. Only the files that are under revision control are taken into account."
585 (interactive
bf5d92c5 586 (let ((dir-A (ediff-get-default-directory-name)))
87c668b4 587 (list (ediff-read-file-name
bbe6126c 588 "Directory to merge with revisions:" dir-A nil)
87c668b4 589 (read-string "Filter through regular expression: "
bbe6126c 590 nil 'ediff-filtering-regexp-history)
87c668b4
MK
591 )))
592 (ediff-directory-revisions-internal
593 dir1 regexp 'ediff-merge-revisions 'ediff-merge-directory-revisions
594 ))
595
596;;;###autoload
597(defalias 'edir-merge-revisions 'ediff-merge-directory-revisions)
598
599;;;###autoload
600(defun ediff-merge-directory-revisions-with-ancestor (dir1 regexp)
601 "Run Ediff on a directory, DIR1, merging its files with their revisions and ancestors.
602The second argument, REGEXP, is a regular expression that filters the file
603names. Only the files that are under revision control are taken into account."
604 (interactive
bf5d92c5 605 (let ((dir-A (ediff-get-default-directory-name)))
87c668b4 606 (list (ediff-read-file-name
bbe6126c 607 "Directory to merge with revisions and ancestors:" dir-A nil)
87c668b4 608 (read-string "Filter through regular expression: "
bbe6126c 609 nil 'ediff-filtering-regexp-history)
87c668b4
MK
610 )))
611 (ediff-directory-revisions-internal
612 dir1 regexp 'ediff-merge-revisions-with-ancestor
613 'ediff-merge-directory-revisions-with-ancestor
614 ))
615
616;;;###autoload
617(defalias
618 'edir-merge-revisions-with-ancestor
619 'ediff-merge-directory-revisions-with-ancestor)
620
621;;;###autoload
622(defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor)
623
624;; Run ediff-action (ediff-files, ediff-merge, ediff-merge-with-ancestors)
625;; on a pair of directories (three directories, in case of ancestor).
bbe6126c
MK
626;; The third argument, REGEXP, is a regular expression that can be used to
627;; filter out certain file names.
87c668b4 628;; JOBNAME is the symbol indicating the meta-job to be performed.
92c51e07
MK
629;; MERGE-DIR is the directory in which to store merged files.
630(defun ediff-directories-internal (dir1 dir2 dir3 regexp action jobname
87c668b4
MK
631 &optional startup-hooks)
632 ;; ediff-read-file-name is set to attach a previously entered file name if
633 ;; the currently entered file is a directory. This code takes care of that.
634 (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1))
635 dir2 (if (file-directory-p dir2) dir2 (file-name-directory dir2)))
636
637 (if (stringp dir3)
638 (setq dir3 (if (file-directory-p dir3) dir3 (file-name-directory dir3))))
639
640 (cond ((string= dir1 dir2)
641 (error "Directories A and B are the same: %s" dir1))
642 ((and (eq jobname 'ediff-directories3)
643 (string= dir1 dir3))
644 (error "Directories A and C are the same: %s" dir1))
645 ((and (eq jobname 'ediff-directories3)
646 (string= dir2 dir3))
647 (error "Directories B and C are the same: %s" dir1)))
648
649 (let (diffs ; var where ediff-intersect-directories returns the diff list
92c51e07 650 merge-autostore-dir
87c668b4 651 file-list meta-buf)
92c51e07
MK
652 (if (and ediff-autostore-merges (ediff-merge-metajob jobname))
653 (setq merge-autostore-dir
654 (ediff-read-file-name "Directory to save merged files:"
655 (if ediff-use-last-dir
656 ediff-last-merge-autostore-dir
657 (ediff-strip-last-dir dir1))
658 nil)))
659 ;; verify we are not merging into an orig directory
660 (if (stringp merge-autostore-dir)
661 (cond ((and (stringp dir1) (string= merge-autostore-dir dir1))
662 (or (y-or-n-p "Merge directory same as directory A, sure? ")
663 (error "Directory merge aborted")))
664 ((and (stringp dir2) (string= merge-autostore-dir dir2))
665 (or (y-or-n-p "Merge directory same as directory B, sure? ")
666 (error "Directory merge aborted")))
667 ((and (stringp dir3) (string= merge-autostore-dir dir3))
668 (or (y-or-n-p
669 "Merge directory same as ancestor directory, sure? ")
670 (error "Directory merge aborted")))))
671
87c668b4 672 (setq file-list (ediff-intersect-directories
92c51e07
MK
673 jobname 'diffs
674 regexp dir1 dir2 dir3 merge-autostore-dir))
87c668b4
MK
675 (setq startup-hooks
676 ;; this sets various vars in the meta buffer inside
677 ;; ediff-prepare-meta-buffer
678 (cons (` (lambda ()
679 ;; tell what to do if the user clicks on a session record
680 (setq ediff-session-action-function (quote (, action)))
681 ;; set ediff-dir-difference-list
682 (setq ediff-dir-difference-list (quote (, diffs)))))
683 startup-hooks))
684 (setq meta-buf (ediff-prepare-meta-buffer
bbe6126c 685 'ediff-filegroup-action
87c668b4
MK
686 file-list
687 "*Ediff Session Group Panel"
688 'ediff-redraw-directory-group-buffer
689 jobname
690 startup-hooks))
691 (ediff-show-meta-buffer meta-buf)
692 ))
693
694(defun ediff-directory-revisions-internal (dir1 regexp action jobname
695 &optional startup-hooks)
696 (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1)))
92c51e07
MK
697
698 (let (file-list meta-buf merge-autostore-dir)
699 (if (and ediff-autostore-merges (ediff-merge-metajob jobname))
700 (setq merge-autostore-dir
701 (ediff-read-file-name "Directory to save merged files:"
702 (if ediff-use-last-dir
703 ediff-last-merge-autostore-dir
704 (ediff-strip-last-dir dir1))
705 nil)))
706 ;; verify merge-autostore-dir != dir1
707 (if (and (stringp merge-autostore-dir)
708 (stringp dir1)
709 (string= merge-autostore-dir dir1))
710 (or (y-or-n-p
711 "Directory for saving merges is the same as directory A. Sure? ")
712 (error "Merge of directory revisions aborted")))
713
87c668b4 714 (setq file-list
92c51e07
MK
715 (ediff-get-directory-files-under-revision
716 jobname regexp dir1 merge-autostore-dir))
87c668b4
MK
717 (setq startup-hooks
718 ;; this sets various vars in the meta buffer inside
719 ;; ediff-prepare-meta-buffer
720 (cons (` (lambda ()
721 ;; tell what to do if the user clicks on a session record
722 (setq ediff-session-action-function (quote (, action)))
723 ))
724 startup-hooks))
725 (setq meta-buf (ediff-prepare-meta-buffer
bbe6126c 726 'ediff-filegroup-action
87c668b4
MK
727 file-list
728 "*Ediff Session Group Panel"
729 'ediff-redraw-directory-group-buffer
730 jobname
731 startup-hooks))
732 (ediff-show-meta-buffer meta-buf)
733 ))
0f0b0a86
KH
734
735
736;;; Compare regions and windows
737
738;;;###autoload
f1a5512a
KH
739(defun ediff-windows-wordwise (dumb-mode &optional wind-A wind-B startup-hooks)
740 "Compare WIND-A and WIND-B, which are selected by clicking, wordwise.
0f0b0a86
KH
741With prefix argument, DUMB-MODE, or on a non-windowing display, works as
742follows:
743If WIND-A is nil, use selected window.
744If WIND-B is nil, use window next to WIND-A."
0f0b0a86 745 (interactive "P")
f1a5512a
KH
746 (ediff-windows dumb-mode wind-A wind-B
747 startup-hooks 'ediff-windows-wordwise 'word-mode))
748
749;;;###autoload
750(defun ediff-windows-linewise (dumb-mode &optional wind-A wind-B startup-hooks)
751 "Compare WIND-A and WIND-B, which are selected by clicking, linewise.
752With prefix argument, DUMB-MODE, or on a non-windowing display, works as
753follows:
754If WIND-A is nil, use selected window.
755If WIND-B is nil, use window next to WIND-A."
756 (interactive "P")
757 (ediff-windows dumb-mode wind-A wind-B
758 startup-hooks 'ediff-windows-linewise nil))
0f0b0a86 759
f1a5512a
KH
760;; Compare WIND-A and WIND-B, which are selected by clicking.
761;; With prefix argument, DUMB-MODE, or on a non-windowing display,
762;; works as follows:
763;; If WIND-A is nil, use selected window.
764;; If WIND-B is nil, use window next to WIND-A.
765(defun ediff-windows (dumb-mode wind-A wind-B startup-hooks job-name word-mode)
766 (if (or dumb-mode (not (ediff-window-display-p)))
0f0b0a86
KH
767 (setq wind-A (ediff-get-next-window wind-A nil)
768 wind-B (ediff-get-next-window wind-B wind-A))
769 (setq wind-A (ediff-get-window-by-clicking wind-A nil 1)
770 wind-B (ediff-get-window-by-clicking wind-B wind-A 2)))
771
772 (let ((buffer-A (window-buffer wind-A))
773 (buffer-B (window-buffer wind-B))
774 beg-A end-A beg-B end-B)
775
776 (save-excursion
777 (save-window-excursion
a7acbbe4 778 (sit-for 0) ; sync before using window-start/end -- a precaution
0f0b0a86
KH
779 (select-window wind-A)
780 (setq beg-A (window-start)
781 end-A (window-end))
782 (select-window wind-B)
783 (setq beg-B (window-start)
784 end-B (window-end))))
785 (ediff-regions-internal
786 buffer-A beg-A end-A buffer-B beg-B end-B
ddc90f39 787 startup-hooks job-name word-mode nil)))
0f0b0a86
KH
788
789;;;###autoload
f1a5512a 790(defun ediff-regions-wordwise (buffer-A buffer-B &optional startup-hooks)
0f0b0a86
KH
791 "Run Ediff on a pair of regions in two different buffers.
792Regions \(i.e., point and mark\) are assumed to be set in advance.
793This function is effective only for relatively small regions, up to 200
f1a5512a 794lines. For large regions, use `ediff-regions-linewise'."
0f0b0a86
KH
795 (interactive
796 (let (bf)
797 (list (setq bf (read-buffer "Region's A buffer: "
798 (ediff-other-buffer "") t))
799 (read-buffer "Region's B buffer: "
800 (progn
801 ;; realign buffers so that two visible bufs will be
802 ;; at the top
803 (save-window-excursion (other-window 1))
804 (ediff-other-buffer bf))
805 t))))
806 (if (not (ediff-buffer-live-p buffer-A))
807 (error "Buffer %S doesn't exist" buffer-A))
808 (if (not (ediff-buffer-live-p buffer-B))
809 (error "Buffer %S doesn't exist" buffer-B))
810
811
812 (let (reg-A-beg reg-A-end reg-B-beg reg-B-end)
813 (save-excursion
814 (set-buffer buffer-A)
815 (setq reg-A-beg (region-beginning)
816 reg-A-end (region-end))
817 (set-buffer buffer-B)
818 (setq reg-B-beg (region-beginning)
819 reg-B-end (region-end)))
820
821 (ediff-regions-internal
822 (get-buffer buffer-A) reg-A-beg reg-A-end
823 (get-buffer buffer-B) reg-B-beg reg-B-end
ddc90f39 824 startup-hooks 'ediff-regions-wordwise 'word-mode nil)))
0f0b0a86
KH
825
826;;;###autoload
f1a5512a 827(defun ediff-regions-linewise (buffer-A buffer-B &optional startup-hooks)
0f0b0a86
KH
828 "Run Ediff on a pair of regions in two different buffers.
829Regions \(i.e., point and mark\) are assumed to be set in advance.
830Each region is enlarged to contain full lines.
831This function is effective for large regions, over 100-200
f1a5512a 832lines. For small regions, use `ediff-regions-wordwise'."
0f0b0a86
KH
833 (interactive
834 (let (bf)
835 (list (setq bf (read-buffer "Region A's buffer: "
836 (ediff-other-buffer "") t))
837 (read-buffer "Region B's buffer: "
838 (progn
839 ;; realign buffers so that two visible bufs will be
840 ;; at the top
841 (save-window-excursion (other-window 1))
842 (ediff-other-buffer bf))
843 t))))
fcbadd58 844 (if (not (ediff-buffer-live-p buffer-A))
0f0b0a86 845 (error "Buffer %S doesn't exist" buffer-A))
fcbadd58 846 (if (not (ediff-buffer-live-p buffer-B))
0f0b0a86
KH
847 (error "Buffer %S doesn't exist" buffer-B))
848
849 (let (reg-A-beg reg-A-end reg-B-beg reg-B-end)
850 (save-excursion
851 (set-buffer buffer-A)
852 (setq reg-A-beg (region-beginning)
853 reg-A-end (region-end))
854 ;; enlarge the region to hold full lines
855 (goto-char reg-A-beg)
856 (beginning-of-line)
857 (setq reg-A-beg (point))
858 (goto-char reg-A-end)
859 (end-of-line)
860 (or (eobp) (forward-char)) ; include the newline char
861 (setq reg-A-end (point))
fcbadd58 862
0f0b0a86
KH
863 (set-buffer buffer-B)
864 (setq reg-B-beg (region-beginning)
865 reg-B-end (region-end))
866 ;; enlarge the region to hold full lines
0f0b0a86
KH
867 (goto-char reg-B-beg)
868 (beginning-of-line)
869 (setq reg-B-beg (point))
870 (goto-char reg-B-end)
871 (end-of-line)
872 (or (eobp) (forward-char)) ; include the newline char
873 (setq reg-B-end (point))
874 ) ; save excursion
875
876 (ediff-regions-internal
877 (get-buffer buffer-A) reg-A-beg reg-A-end
878 (get-buffer buffer-B) reg-B-beg reg-B-end
1e70790f 879 startup-hooks 'ediff-regions-linewise nil nil))) ; no word mode
0f0b0a86
KH
880
881;; compare region beg-A to end-A of buffer-A
882;; to regions beg-B -- end-B in buffer-B.
883(defun ediff-regions-internal (buffer-A beg-A end-A buffer-B beg-B end-B
ddc90f39
MK
884 startup-hooks job-name word-mode
885 setup-parameters)
0f0b0a86
KH
886 (let ((tmp-buffer (get-buffer-create ediff-tmp-buffer))
887 overl-A overl-B
888 file-A file-B)
889
890 ;; in case beg/end-A/B aren't markers--make them into markers
e756eb9f 891 (ediff-with-current-buffer buffer-A
0f0b0a86
KH
892 (setq beg-A (move-marker (make-marker) beg-A)
893 end-A (move-marker (make-marker) end-A)))
e756eb9f 894 (ediff-with-current-buffer buffer-B
0f0b0a86
KH
895 (setq beg-B (move-marker (make-marker) beg-B)
896 end-B (move-marker (make-marker) end-B)))
897
898 (if (and (eq buffer-A buffer-B)
899 (or (and (< beg-A end-B) (<= beg-B beg-A)) ; b-B b-A e-B
900 (and (< beg-B end-A) (<= end-A end-B)))) ; b-B e-A e-B
901 (progn
902 (with-output-to-temp-buffer ediff-msg-buffer
903 (princ "
904You have requested to compare overlapping regions of the same buffer.
905
906In this case, Ediff's highlighting may be confusing---in the same window,
907you may see highlighted regions that belong to different regions.
908
909Continue anyway? (y/n) "))
910
911 (if (y-or-n-p "Continue anyway? ")
912 ()
913 (error "%S aborted" job-name))))
914
915 ;; make file-A
916 (if word-mode
917 (ediff-wordify beg-A end-A buffer-A tmp-buffer)
918 (ediff-copy-to-buffer beg-A end-A buffer-A tmp-buffer))
87c668b4 919 (setq file-A (ediff-make-temp-file tmp-buffer "regA"))
0f0b0a86
KH
920
921 ;; make file-B
922 (if word-mode
923 (ediff-wordify beg-B end-B buffer-B tmp-buffer)
924 (ediff-copy-to-buffer beg-B end-B buffer-B tmp-buffer))
87c668b4 925 (setq file-B (ediff-make-temp-file tmp-buffer "regB"))
0f0b0a86
KH
926
927 (setq overl-A (ediff-make-bullet-proof-overlay beg-A end-A buffer-A))
928 (setq overl-B (ediff-make-bullet-proof-overlay beg-B end-B buffer-B))
929 (ediff-setup buffer-A file-A
930 buffer-B file-B
931 nil nil ; buffer & file C
813f532d 932 (cons (` (lambda ()
b3a26225
RS
933 (delete-file (, file-A))
934 (delete-file (, file-B))))
813f532d 935 startup-hooks)
ddc90f39
MK
936 (append
937 (list (cons 'ediff-word-mode word-mode)
938 (cons 'ediff-narrow-bounds (list overl-A overl-B))
939 (cons 'ediff-job-name job-name))
940 setup-parameters)
0f0b0a86
KH
941 )
942 ))
943
944
945;;; Merge files and buffers
946
947;;;###autoload
948(defalias 'ediff-merge 'ediff-merge-files)
949
950(defsubst ediff-merge-on-startup ()
951 (ediff-do-merge 0)
e756eb9f 952 (ediff-with-current-buffer ediff-buffer-C
0f0b0a86
KH
953 (set-buffer-modified-p nil)))
954
955;;;###autoload
956(defun ediff-merge-files (file-A file-B &optional startup-hooks)
957 "Merge two files without ancestor."
958 (interactive
959 (let ((dir-A (if ediff-use-last-dir
960 ediff-last-dir-A
961 default-directory))
962 dir-B f)
87c668b4
MK
963 (list (setq f (ediff-read-file-name
964 "File A to merge" dir-A
965 (ediff-get-default-file-name)))
0f0b0a86
KH
966 (ediff-read-file-name "File B to merge"
967 (setq dir-B
968 (if ediff-use-last-dir
969 ediff-last-dir-B
970 (file-name-directory f)))
971 (progn
972 (setq file-name-history
87c668b4 973 (cons (ediff-abbreviate-file-name
0f0b0a86
KH
974 (expand-file-name
975 (file-name-nondirectory f)
976 dir-B))
977 file-name-history))
978 f))
979 )))
980 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
981 (ediff-files-internal file-A
982 (if (file-directory-p file-B)
983 (expand-file-name
984 (file-name-nondirectory file-A) file-B)
985 file-B)
986 nil ; file-C
987 startup-hooks
988 'ediff-merge-files))
989
990;;;###autoload
991(defun ediff-merge-files-with-ancestor (file-A file-B file-ancestor
992 &optional startup-hooks)
993 "Merge two files with ancestor."
994 (interactive
995 (let ((dir-A (if ediff-use-last-dir
996 ediff-last-dir-A
997 default-directory))
998 dir-B dir-ancestor f ff)
87c668b4
MK
999 (list (setq f (ediff-read-file-name
1000 "File A to merge" dir-A
1001 (ediff-get-default-file-name)))
0f0b0a86
KH
1002 (setq ff (ediff-read-file-name "File B to merge"
1003 (setq dir-B
1004 (if ediff-use-last-dir
1005 ediff-last-dir-B
1006 (file-name-directory f)))
1007 (progn
1008 (setq file-name-history
1009 (cons
87c668b4 1010 (ediff-abbreviate-file-name
0f0b0a86
KH
1011 (expand-file-name
1012 (file-name-nondirectory f)
1013 dir-B))
1014 file-name-history))
1015 f)))
1016 (ediff-read-file-name "Ancestor file"
1017 (setq dir-ancestor
1018 (if ediff-use-last-dir
1019 ediff-last-dir-ancestor
1020 (file-name-directory ff)))
1021 (progn
1022 (setq file-name-history
87c668b4 1023 (cons (ediff-abbreviate-file-name
0f0b0a86
KH
1024 (expand-file-name
1025 (file-name-nondirectory ff)
1026 dir-ancestor))
1027 file-name-history))
1028 ff))
1029 )))
1030 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
1031 (ediff-files-internal file-A
1032 (if (file-directory-p file-B)
1033 (expand-file-name
1034 (file-name-nondirectory file-A) file-B)
1035 file-B)
1036 file-ancestor
1037 startup-hooks
1038 'ediff-merge-files-with-ancestor))
1039
1040;;;###autoload
1041(defalias 'ediff-merge-with-ancestor 'ediff-merge-files-with-ancestor)
1042
1043;;;###autoload
1044(defun ediff-merge-buffers (buffer-A buffer-B &optional startup-hooks job-name)
1045 "Merge buffers without ancestor."
1046 (interactive
1047 (let (bf)
1048 (list (setq bf (read-buffer "Buffer A to merge: "
1049 (ediff-other-buffer "") t))
1050 (read-buffer "Buffer B to merge: "
1051 (progn
1052 ;; realign buffers so that two visible bufs will be
1053 ;; at the top
1054 (save-window-excursion (other-window 1))
1055 (ediff-other-buffer bf))
1056 t))))
1057
1058 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
1059 (or job-name (setq job-name 'ediff-merge-buffers))
1060 (ediff-buffers-internal
1061 buffer-A buffer-B nil startup-hooks job-name))
1062
1063;;;###autoload
1064(defun ediff-merge-buffers-with-ancestor (buffer-A
1065 buffer-B buffer-ancestor
1066 &optional startup-hooks job-name)
1067 "Merge buffers with ancestor."
1068 (interactive
1069 (let (bf bff)
1070 (list (setq bf (read-buffer "Buffer A to merge: "
1071 (ediff-other-buffer "") t))
1072 (setq bff (read-buffer "Buffer B to merge: "
1073 (progn
1074 ;; realign buffers so that two visible
1075 ;; bufs will be at the top
1076 (save-window-excursion (other-window 1))
1077 (ediff-other-buffer bf))
1078 t))
1079 (read-buffer "Ancestor buffer: "
1080 (progn
1081 ;; realign buffers so that three visible
1082 ;; bufs will be at the top
1083 (save-window-excursion (other-window 1))
1084 (ediff-other-buffer (list bf bff)))
1085 t)
1086 )))
1087
1088 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
1089 (or job-name (setq job-name 'ediff-merge-buffers-with-ancestor))
1090 (ediff-buffers-internal
1091 buffer-A buffer-B buffer-ancestor startup-hooks job-name))
1092
1093
1094;;;###autoload
87c668b4 1095(defun ediff-merge-revisions (&optional file startup-hooks)
0f0b0a86 1096 "Run Ediff by merging two revisions of a file.
87c668b4
MK
1097The file is the optional FILE argument or the file visited by the current
1098buffer."
1099 (interactive)
87c668b4 1100 (if (stringp file) (find-file file))
4ae69eac 1101 (let (rev1 rev2)
87c668b4
MK
1102 (setq rev1
1103 (read-string
1104 (format
1105 "Version 1 to merge (default: %s's latest version): "
1106 (if (stringp file)
1107 (file-name-nondirectory file) "current buffer")))
1108 rev2
1109 (read-string
1110 (format
1111 "Version 2 to merge (default: %s): "
1112 (if (stringp file)
1113 (file-name-nondirectory file) "current buffer"))))
4ae69eac
MK
1114 (ediff-load-version-control)
1115 ;; ancestor-revision=nil
1116 (funcall
92c51e07 1117 (intern (format "ediff-%S-merge-internal" ediff-version-control-package))
4ae69eac 1118 rev1 rev2 nil startup-hooks)))
0f0b0a86
KH
1119
1120
1121;;;###autoload
87c668b4
MK
1122(defun ediff-merge-revisions-with-ancestor (&optional file startup-hooks)
1123 "Run Ediff by merging two revisions of a file with a common ancestor.
1124The file is the the optional FILE argument or the file visited by the current
1125buffer."
1126 (interactive)
87c668b4 1127 (if (stringp file) (find-file file))
4ae69eac 1128 (let (rev1 rev2 ancestor-rev)
87c668b4
MK
1129 (setq rev1
1130 (read-string
1131 (format
1132 "Version 1 to merge (default: %s's latest version): "
1133 (if (stringp file)
1134 (file-name-nondirectory file) "current buffer")))
1135 rev2
1136 (read-string
1137 (format
1138 "Version 2 to merge (default: %s): "
1139 (if (stringp file)
1140 (file-name-nondirectory file) "current buffer")))
1141 ancestor-rev
1142 (read-string
1143 (format
1144 "Ancestor version (default: %s): "
1145 (if (stringp file)
1146 (file-name-nondirectory file) "current buffer"))))
4ae69eac
MK
1147 (ediff-load-version-control)
1148 (funcall
92c51e07 1149 (intern (format "ediff-%S-merge-internal" ediff-version-control-package))
4ae69eac
MK
1150 rev1 rev2 ancestor-rev startup-hooks)))
1151
1152;;;###autoload
1153(defun run-ediff-from-cvs-buffer (pos)
1154 "Run Ediff-merge on appropriate revisions of the selected file.
ddc90f39 1155First run after `M-x cvs-update'. Then place the cursor on a line describing a
4ae69eac
MK
1156file and then run `run-ediff-from-cvs-buffer'."
1157 (interactive "d")
1158 (ediff-load-version-control)
1159 (let ((tin (tin-locate cvs-cookie-handle pos)))
1160 (if tin
1161 (cvs-run-ediff-on-file-descriptor tin)
1162 (error "There is no file to merge"))))
0f0b0a86
KH
1163
1164
1165;;; Apply patch
0f0b0a86 1166
bbe6126c
MK
1167;;;###autoload
1168(defun ediff-patch-file ()
1169 "Run Ediff by patching SOURCE-FILENAME."
1170 ;; This now returns the control buffer
1171 (interactive)
1172 (let (source-dir source-file patch-buf)
1173 (require 'ediff-ptch)
1174 (setq patch-buf (ediff-get-patch-buffer))
1175 (setq source-dir (cond (ediff-use-last-dir ediff-last-dir-patch)
1176 ((and (not ediff-patch-default-directory)
1177 (buffer-file-name patch-buf))
1178 (file-name-directory
1179 (expand-file-name
1180 (buffer-file-name patch-buf))))
1181 (t default-directory)))
1182 (setq source-file
1183 ;; the default is the directory, not the visited file name
1184 (ediff-read-file-name "Which file to patch? " source-dir source-dir))
1185 (ediff-dispatch-file-patching-job patch-buf source-file)))
0f0b0a86 1186
bbe6126c
MK
1187;;;###autoload
1188(defun ediff-patch-buffer ()
1189 "Run Ediff by patching BUFFER-NAME."
1190 (interactive)
1191 (let (patch-buf)
1192 (require 'ediff-ptch)
1193 (setq patch-buf (ediff-get-patch-buffer))
1194 (ediff-patch-buffer-internal
1195 patch-buf
1196 (read-buffer "Which buffer to patch? "
1197 (cond ((eq patch-buf (current-buffer))
1198 (window-buffer (other-window 1)))
1199 (t (current-buffer)))
1200 'must-match))))
0f0b0a86 1201
bbe6126c
MK
1202;;;###autoload
1203(defalias 'epatch 'ediff-patch-file)
1204;;;###autoload
1205(defalias 'epatch-buffer 'ediff-patch-buffer)
0f0b0a86
KH
1206
1207
813f532d 1208
0f0b0a86 1209\f
813f532d
RS
1210;;; Versions Control functions
1211
1212;;;###autoload
87c668b4
MK
1213(defun ediff-revision (&optional file startup-hooks)
1214 "Run Ediff by comparing versions of a file.
1215The file is an optional FILE argument or the file visited by the current
1216buffer. Use `vc.el' or `rcs.el' depending on `ediff-version-control-package'."
1217 ;; if buffer is non-nil, use that buffer instead of the current buffer
f1a5512a 1218 (interactive "P")
87c668b4 1219 (if (stringp file) (find-file file))
f1a5512a 1220 (let (rev1 rev2)
87c668b4
MK
1221 (setq rev1
1222 (read-string
1223 (format "Version 1 to compare (default: %s's latest version): "
1224 (if (stringp file)
1225 (file-name-nondirectory file) "current buffer")))
1226 rev2
1227 (read-string
1228 (format "Version 2 to compare (default: %s): "
1229 (if (stringp file)
1230 (file-name-nondirectory file) "current buffer"))))
f1a5512a
KH
1231 (ediff-load-version-control)
1232 (funcall
92c51e07 1233 (intern (format "ediff-%S-internal" ediff-version-control-package))
87c668b4 1234 rev1 rev2 startup-hooks)
f1a5512a 1235 ))
1e70790f
MK
1236
1237
1238;;;###autoload
1239(defalias 'erevision 'ediff-revision)
0f0b0a86 1240
0f0b0a86
KH
1241
1242;; Test if version control package is loaded and load if not
1243;; Is SILENT is non-nil, don't report error if package is not found.
1244(defun ediff-load-version-control (&optional silent)
4ae69eac 1245 (require 'ediff-vers)
0f0b0a86
KH
1246 (or (featurep ediff-version-control-package)
1247 (if (locate-library (symbol-name ediff-version-control-package))
1248 (progn
1249 (message "") ; kill the message from `locate-library'
87c668b4 1250 (require ediff-version-control-package))
0f0b0a86 1251 (or silent
f1a5512a 1252 (error "Version control package %S.el not found. Use vc.el instead"
0f0b0a86 1253 ediff-version-control-package)))))
87c668b4 1254
b3a26225 1255
138df2ce
MK
1256;;;###autoload
1257(defun ediff-version ()
1258 "Return string describing the version of Ediff.
1259When called interactively, displays the version."
1260 (interactive)
1261 (if (interactive-p)
1262 (message (ediff-version))
1263 (format "Ediff %s of %s" ediff-version ediff-date)))
1264
813f532d 1265
4ae69eac 1266;;;###autoload
92c51e07
MK
1267(defun ediff-documentation (&optional node)
1268 "Display Ediff's manual.
1269With optional NODE, goes to that node."
4ae69eac
MK
1270 (interactive)
1271 (let ((ctl-window ediff-control-window)
1272 (ctl-buf ediff-control-buffer))
1273
1274 (ediff-skip-unsuitable-frames)
1275 (condition-case nil
1276 (progn
1277 (pop-to-buffer (get-buffer-create "*info*"))
1278 (info (if ediff-xemacs-p "ediff.info" "ediff"))
92c51e07
MK
1279 (if node
1280 (Info-goto-node node)
1281 (message "Type `i' to search for a specific topic"))
1282 (raise-frame (selected-frame)))
4ae69eac 1283 (error (beep 1)
bbe6126c 1284 (with-output-to-temp-buffer ediff-msg-buffer
92c51e07 1285 (princ ediff-BAD-INFO))
4ae69eac
MK
1286 (if (window-live-p ctl-window)
1287 (progn
1288 (select-window ctl-window)
1289 (set-window-buffer ctl-window ctl-buf)))))))
1290
1291
1292
1293
1294;;; Local Variables:
1295;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
e756eb9f
MK
1296;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
1297;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
4ae69eac
MK
1298;;; End:
1299
0f0b0a86 1300(require 'ediff-util)
813f532d
RS
1301
1302;;; ediff.el ends here