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