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