Move lisp/emacs-lisp/authors.el to admin/
[bpt/emacs.git] / lisp / vc / ediff.el
CommitLineData
0f0b0a86 1;;; ediff.el --- a comprehensive visual interface to diff & patch
b578f267 2
ba318903 3;; Copyright (C) 1994-2014 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 116(eval-and-compile
6c42fc3e 117 (unless (fboundp 'declare-function) (defmacro declare-function (&rest _r))))
acb93bb2 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)
0b908bf2
GM
370 ;; This duplicates code from menu-bar.el.
371 (unless (or (not (eq revert-buffer-function 'revert-buffer--default))
372 (not (eq revert-buffer-insert-file-contents-function
373 'revert-buffer-insert-file-contents--default-function))
68b962d4
MK
374 (and buffer-file-number
375 (or (buffer-modified-p)
376 (not (verify-visited-file-modtime
377 (current-buffer))))))
378 (error "Nothing to revert"))
379 (let* ((auto-save-p (and (recent-auto-save-p)
380 buffer-auto-save-file-name
381 (file-readable-p buffer-auto-save-file-name)
382 (y-or-n-p
383 "Buffer has been auto-saved recently. Compare with auto-save file? ")))
384 (file-name (if auto-save-p
385 buffer-auto-save-file-name
386 buffer-file-name))
387 (revert-buf-name (concat "FILE=" file-name))
388 (revert-buf (get-buffer revert-buf-name))
389 (current-major major-mode))
390 (unless file-name
391 (error "Buffer does not seem to be associated with any file"))
392 (when revert-buf
393 (kill-buffer revert-buf)
394 (setq revert-buf nil))
395 (setq revert-buf (get-buffer-create revert-buf-name))
396 (with-current-buffer revert-buf
397 (insert-file-contents file-name)
398 ;; Assume same modes:
399 (funcall current-major))
400 (ediff-buffers revert-buf (current-buffer))))
401
402
3755bd32
MR
403;;;###autoload
404(defun ediff-backup (file)
405 "Run Ediff on FILE and its backup file.
406Uses the latest backup, if there are several numerical backups.
407If this file is a backup, `ediff' it with its original."
408 (interactive (list (read-file-name "Ediff (file with backup): ")))
409 ;; The code is taken from `diff-backup'.
410 (require 'diff)
411 (let (bak ori)
412 (if (backup-file-name-p file)
413 (setq bak file
414 ori (file-name-sans-versions file))
415 (setq bak (or (diff-latest-backup-file file)
416 (error "No backup found for %s" file))
417 ori file))
418 (ediff-files bak ori)))
813f532d
RS
419
420;;;###autoload
0f0b0a86 421(defun ediff-buffers (buffer-A buffer-B &optional startup-hooks job-name)
813f532d 422 "Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B."
71296446 423 (interactive
0f0b0a86
KH
424 (let (bf)
425 (list (setq bf (read-buffer "Buffer A to compare: "
426 (ediff-other-buffer "") t))
427 (read-buffer "Buffer B to compare: "
428 (progn
429 ;; realign buffers so that two visible bufs will be
430 ;; at the top
431 (save-window-excursion (other-window 1))
432 (ediff-other-buffer bf))
433 t))))
0f0b0a86
KH
434 (or job-name (setq job-name 'ediff-buffers))
435 (ediff-buffers-internal buffer-A buffer-B nil startup-hooks job-name))
bbe6126c
MK
436
437;;;###autoload
438(defalias 'ebuffers 'ediff-buffers)
439
71296446 440
0f0b0a86
KH
441;;;###autoload
442(defun ediff-buffers3 (buffer-A buffer-B buffer-C
443 &optional startup-hooks job-name)
444 "Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C."
71296446 445 (interactive
0f0b0a86
KH
446 (let (bf bff)
447 (list (setq bf (read-buffer "Buffer A to compare: "
448 (ediff-other-buffer "") t))
449 (setq bff (read-buffer "Buffer B to compare: "
450 (progn
451 ;; realign buffers so that two visible
452 ;; bufs will be at the top
453 (save-window-excursion (other-window 1))
454 (ediff-other-buffer bf))
455 t))
456 (read-buffer "Buffer C to compare: "
457 (progn
458 ;; realign buffers so that three visible
459 ;; bufs will be at the top
460 (save-window-excursion (other-window 1))
461 (ediff-other-buffer (list bf bff)))
462 t)
463 )))
0f0b0a86
KH
464 (or job-name (setq job-name 'ediff-buffers3))
465 (ediff-buffers-internal buffer-A buffer-B buffer-C startup-hooks job-name))
bbe6126c
MK
466
467;;;###autoload
468(defalias 'ebuffers3 'ediff-buffers3)
0f0b0a86 469
71296446
JB
470
471
328b4b70
MK
472;; MERGE-BUFFER-FILE is the file to be associated with the merge buffer
473(defun ediff-buffers-internal (buf-A buf-B buf-C startup-hooks job-name
474 &optional merge-buffer-file)
0f0b0a86
KH
475 (let* ((buf-A-file-name (buffer-file-name (get-buffer buf-A)))
476 (buf-B-file-name (buffer-file-name (get-buffer buf-B)))
477 (buf-C-is-alive (ediff-buffer-live-p buf-C))
478 (buf-C-file-name (if buf-C-is-alive
479 (buffer-file-name (get-buffer buf-B))))
480 file-A file-B file-C)
2de386ca
MK
481 (unwind-protect
482 (progn
483 (if (not (ediff-buffer-live-p buf-A))
484 (error "Buffer %S doesn't exist" buf-A))
485 (if (not (ediff-buffer-live-p buf-B))
486 (error "Buffer %S doesn't exist" buf-B))
487 (let ((ediff-job-name job-name))
488 (if (and ediff-3way-comparison-job
489 (not buf-C-is-alive))
490 (error "Buffer %S doesn't exist" buf-C)))
491 (if (stringp buf-A-file-name)
492 (setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
493 (if (stringp buf-B-file-name)
494 (setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
495 (if (stringp buf-C-file-name)
496 (setq buf-C-file-name (file-name-nondirectory buf-C-file-name)))
01795a1b 497
2de386ca
MK
498 (setq file-A (ediff-make-temp-file buf-A buf-A-file-name)
499 file-B (ediff-make-temp-file buf-B buf-B-file-name))
500 (if buf-C-is-alive
501 (setq file-C (ediff-make-temp-file buf-C buf-C-file-name)))
01795a1b 502
2de386ca
MK
503 (ediff-setup (get-buffer buf-A) file-A
504 (get-buffer buf-B) file-B
505 (if buf-C-is-alive (get-buffer buf-C))
506 file-C
507 (cons `(lambda ()
508 (delete-file ,file-A)
509 (delete-file ,file-B)
510 (if (stringp ,file-C) (delete-file ,file-C)))
511 startup-hooks)
512 (list (cons 'ediff-job-name job-name))
513 merge-buffer-file))
514 (if (and (stringp file-A) (file-exists-p file-A))
515 (delete-file file-A))
516 (if (and (stringp file-B) (file-exists-p file-B))
517 (delete-file file-B))
518 (if (and (stringp file-C) (file-exists-p file-C))
519 (delete-file file-C)))))
87c668b4
MK
520
521
522;;; Directory and file group operations
523
524;; Get appropriate default name for directory:
525;; If ediff-use-last-dir, use ediff-last-dir-A.
526;; In dired mode, use the directory that is under the point (if any);
527;; otherwise, use default-directory
528(defun ediff-get-default-directory-name ()
529 (cond (ediff-use-last-dir ediff-last-dir-A)
530 ((eq major-mode 'dired-mode)
531 (let ((f (dired-get-filename nil 'noerror)))
532 (if (and (stringp f) (file-directory-p f))
533 f
534 default-directory)))
535 (t default-directory)))
536
537
538;;;###autoload
539(defun ediff-directories (dir1 dir2 regexp)
540 "Run Ediff on a pair of directories, DIR1 and DIR2, comparing files that have
6dfd1bcc
MK
541the same name in both. The third argument, REGEXP, is nil or a regular
542expression; only file names that match the regexp are considered."
87c668b4
MK
543 (interactive
544 (let ((dir-A (ediff-get-default-directory-name))
81ef8960 545 (default-regexp (eval ediff-default-filtering-regexp))
87c668b4 546 f)
ec6aebe8 547 (list (setq f (read-directory-name
01795a1b
MA
548 "Directory A to compare: " dir-A nil 'must-match))
549 (read-directory-name "Directory B to compare: "
ec6aebe8
MK
550 (if ediff-use-last-dir
551 ediff-last-dir-B
552 (ediff-strip-last-dir f))
553 nil 'must-match)
81ef8960
MK
554 (read-string
555 (if (stringp default-regexp)
556 (format "Filter through regular expression (default %s): "
557 default-regexp)
558 "Filter through regular expression: ")
559 nil
560 'ediff-filtering-regexp-history
561 (eval ediff-default-filtering-regexp))
87c668b4
MK
562 )))
563 (ediff-directories-internal
564 dir1 dir2 nil regexp 'ediff-files 'ediff-directories
565 ))
566
567;;;###autoload
568(defalias 'edirs 'ediff-directories)
569
570
571;;;###autoload
572(defun ediff-directory-revisions (dir1 regexp)
573 "Run Ediff on a directory, DIR1, comparing its files with their revisions.
574The second argument, REGEXP, is a regular expression that filters the file
3af0304a 575names. Only the files that are under revision control are taken into account."
87c668b4 576 (interactive
81ef8960
MK
577 (let ((dir-A (ediff-get-default-directory-name))
578 (default-regexp (eval ediff-default-filtering-regexp))
579 )
ec6aebe8
MK
580 (list (read-directory-name
581 "Directory to compare with revision:" dir-A nil 'must-match)
81ef8960
MK
582 (read-string
583 (if (stringp default-regexp)
584 (format "Filter through regular expression (default %s): "
585 default-regexp)
586 "Filter through regular expression: ")
587 nil
588 'ediff-filtering-regexp-history
589 (eval ediff-default-filtering-regexp))
87c668b4
MK
590 )))
591 (ediff-directory-revisions-internal
592 dir1 regexp 'ediff-revision 'ediff-directory-revisions
593 ))
594
595;;;###autoload
596(defalias 'edir-revisions 'ediff-directory-revisions)
597
598
599;;;###autoload
600(defun ediff-directories3 (dir1 dir2 dir3 regexp)
601 "Run Ediff on three directories, DIR1, DIR2, and DIR3, comparing files that
6dfd1bcc
MK
602have the same name in all three. The last argument, REGEXP, is nil or a
603regular expression; only file names that match the regexp are considered."
604
87c668b4
MK
605 (interactive
606 (let ((dir-A (ediff-get-default-directory-name))
81ef8960 607 (default-regexp (eval ediff-default-filtering-regexp))
87c668b4 608 f)
ec6aebe8
MK
609 (list (setq f (read-directory-name "Directory A to compare:" dir-A nil))
610 (setq f (read-directory-name "Directory B to compare:"
611 (if ediff-use-last-dir
612 ediff-last-dir-B
613 (ediff-strip-last-dir f))
614 nil 'must-match))
615 (read-directory-name "Directory C to compare:"
616 (if ediff-use-last-dir
617 ediff-last-dir-C
618 (ediff-strip-last-dir f))
619 nil 'must-match)
81ef8960
MK
620 (read-string
621 (if (stringp default-regexp)
622 (format "Filter through regular expression (default %s): "
623 default-regexp)
624 "Filter through regular expression: ")
625 nil
626 'ediff-filtering-regexp-history
627 (eval ediff-default-filtering-regexp))
87c668b4
MK
628 )))
629 (ediff-directories-internal
630 dir1 dir2 dir3 regexp 'ediff-files3 'ediff-directories3
631 ))
632
633;;;###autoload
634(defalias 'edirs3 'ediff-directories3)
635
636;;;###autoload
3af0304a 637(defun ediff-merge-directories (dir1 dir2 regexp &optional merge-autostore-dir)
87c668b4 638 "Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have
6dfd1bcc
MK
639the same name in both. The third argument, REGEXP, is nil or a regular
640expression; only file names that match the regexp are considered."
87c668b4
MK
641 (interactive
642 (let ((dir-A (ediff-get-default-directory-name))
81ef8960 643 (default-regexp (eval ediff-default-filtering-regexp))
87c668b4 644 f)
ec6aebe8
MK
645 (list (setq f (read-directory-name "Directory A to merge:"
646 dir-A nil 'must-match))
647 (read-directory-name "Directory B to merge:"
648 (if ediff-use-last-dir
649 ediff-last-dir-B
650 (ediff-strip-last-dir f))
651 nil 'must-match)
81ef8960
MK
652 (read-string
653 (if (stringp default-regexp)
654 (format "Filter through regular expression (default %s): "
655 default-regexp)
656 "Filter through regular expression: ")
657 nil
658 'ediff-filtering-regexp-history
659 (eval ediff-default-filtering-regexp))
87c668b4
MK
660 )))
661 (ediff-directories-internal
662 dir1 dir2 nil regexp 'ediff-merge-files 'ediff-merge-directories
3af0304a 663 nil merge-autostore-dir
87c668b4
MK
664 ))
665
666;;;###autoload
667(defalias 'edirs-merge 'ediff-merge-directories)
668
669;;;###autoload
3af0304a
MK
670(defun ediff-merge-directories-with-ancestor (dir1 dir2 ancestor-dir regexp
671 &optional
672 merge-autostore-dir)
bbe6126c 673 "Merge files in directories DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors.
3af0304a 674Ediff merges files that have identical names in DIR1, DIR2. If a pair of files
bbe6126c 675in DIR1 and DIR2 doesn't have an ancestor in ANCESTOR-DIR, Ediff will merge
6dfd1bcc
MK
676without ancestor. The fourth argument, REGEXP, is nil or a regular expression;
677only file names that match the regexp are considered."
87c668b4
MK
678 (interactive
679 (let ((dir-A (ediff-get-default-directory-name))
81ef8960 680 (default-regexp (eval ediff-default-filtering-regexp))
87c668b4 681 f)
ec6aebe8
MK
682 (list (setq f (read-directory-name "Directory A to merge:" dir-A nil))
683 (setq f (read-directory-name "Directory B to merge:"
87c668b4 684 (if ediff-use-last-dir
71296446 685 ediff-last-dir-B
87c668b4 686 (ediff-strip-last-dir f))
ec6aebe8
MK
687 nil 'must-match))
688 (read-directory-name "Ancestor directory:"
87c668b4 689 (if ediff-use-last-dir
71296446 690 ediff-last-dir-C
87c668b4 691 (ediff-strip-last-dir f))
ec6aebe8 692 nil 'must-match)
81ef8960
MK
693 (read-string
694 (if (stringp default-regexp)
695 (format "Filter through regular expression (default %s): "
696 default-regexp)
697 "Filter through regular expression: ")
698 nil
699 'ediff-filtering-regexp-history
700 (eval ediff-default-filtering-regexp))
87c668b4
MK
701 )))
702 (ediff-directories-internal
bbe6126c 703 dir1 dir2 ancestor-dir regexp
87c668b4 704 'ediff-merge-files-with-ancestor 'ediff-merge-directories-with-ancestor
3af0304a 705 nil merge-autostore-dir
87c668b4
MK
706 ))
707
708;;;###autoload
3af0304a
MK
709(defun ediff-merge-directory-revisions (dir1 regexp
710 &optional merge-autostore-dir)
87c668b4
MK
711 "Run Ediff on a directory, DIR1, merging its files with their revisions.
712The second argument, REGEXP, is a regular expression that filters the file
3af0304a 713names. Only the files that are under revision control are taken into account."
87c668b4 714 (interactive
81ef8960
MK
715 (let ((dir-A (ediff-get-default-directory-name))
716 (default-regexp (eval ediff-default-filtering-regexp))
717 )
ec6aebe8
MK
718 (list (read-directory-name
719 "Directory to merge with revisions:" dir-A nil 'must-match)
81ef8960
MK
720 (read-string
721 (if (stringp default-regexp)
722 (format "Filter through regular expression (default %s): "
723 default-regexp)
724 "Filter through regular expression: ")
725 nil
726 'ediff-filtering-regexp-history
727 (eval ediff-default-filtering-regexp))
87c668b4
MK
728 )))
729 (ediff-directory-revisions-internal
730 dir1 regexp 'ediff-merge-revisions 'ediff-merge-directory-revisions
3af0304a 731 nil merge-autostore-dir
87c668b4
MK
732 ))
733
734;;;###autoload
735(defalias 'edir-merge-revisions 'ediff-merge-directory-revisions)
736
737;;;###autoload
3af0304a
MK
738(defun ediff-merge-directory-revisions-with-ancestor (dir1 regexp
739 &optional
740 merge-autostore-dir)
87c668b4
MK
741 "Run Ediff on a directory, DIR1, merging its files with their revisions and ancestors.
742The second argument, REGEXP, is a regular expression that filters the file
3af0304a 743names. Only the files that are under revision control are taken into account."
87c668b4 744 (interactive
81ef8960
MK
745 (let ((dir-A (ediff-get-default-directory-name))
746 (default-regexp (eval ediff-default-filtering-regexp))
747 )
ec6aebe8
MK
748 (list (read-directory-name
749 "Directory to merge with revisions and ancestors:"
750 dir-A nil 'must-match)
81ef8960
MK
751 (read-string
752 (if (stringp default-regexp)
753 (format "Filter through regular expression (default %s): "
754 default-regexp)
755 "Filter through regular expression: ")
756 nil
757 'ediff-filtering-regexp-history
758 (eval ediff-default-filtering-regexp))
87c668b4
MK
759 )))
760 (ediff-directory-revisions-internal
761 dir1 regexp 'ediff-merge-revisions-with-ancestor
762 'ediff-merge-directory-revisions-with-ancestor
3af0304a 763 nil merge-autostore-dir
87c668b4
MK
764 ))
765
766;;;###autoload
767(defalias
768 'edir-merge-revisions-with-ancestor
71296446 769 'ediff-merge-directory-revisions-with-ancestor)
87c668b4
MK
770
771;;;###autoload
772(defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor)
773
774;; Run ediff-action (ediff-files, ediff-merge, ediff-merge-with-ancestors)
775;; on a pair of directories (three directories, in case of ancestor).
6dfd1bcc
MK
776;; The third argument, REGEXP, is nil or a regular expression;
777;; only file names that match the regexp are considered.
87c668b4 778;; JOBNAME is the symbol indicating the meta-job to be performed.
3af0304a 779;; MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
71296446 780(defun ediff-directories-internal (dir1 dir2 dir3 regexp action jobname
3af0304a
MK
781 &optional startup-hooks
782 merge-autostore-dir)
87c668b4
MK
783 (if (stringp dir3)
784 (setq dir3 (if (file-directory-p dir3) dir3 (file-name-directory dir3))))
785
786 (cond ((string= dir1 dir2)
787 (error "Directories A and B are the same: %s" dir1))
788 ((and (eq jobname 'ediff-directories3)
789 (string= dir1 dir3))
790 (error "Directories A and C are the same: %s" dir1))
791 ((and (eq jobname 'ediff-directories3)
792 (string= dir2 dir3))
793 (error "Directories B and C are the same: %s" dir1)))
794
3af0304a
MK
795 (if merge-autostore-dir
796 (or (stringp merge-autostore-dir)
797 (error "%s: Directory for storing merged files must be a string"
798 jobname)))
71296446 799 (let (;; dir-diff-struct is of the form (common-list diff-list)
c3912d54
MK
800 ;; It is a structure where ediff-intersect-directories returns
801 ;; commonalities and differences among directories
802 dir-diff-struct
803 meta-buf)
3af0304a
MK
804 (if (and ediff-autostore-merges
805 (ediff-merge-metajob jobname)
806 (not merge-autostore-dir))
71296446 807 (setq merge-autostore-dir
ec6aebe8 808 (read-directory-name "Save merged files in directory: "
3af0304a 809 (if ediff-use-last-dir
92c51e07
MK
810 ediff-last-merge-autostore-dir
811 (ediff-strip-last-dir dir1))
3af0304a
MK
812 nil
813 'must-match)))
92c51e07 814 ;; verify we are not merging into an orig directory
3af0304a 815 (if merge-autostore-dir
92c51e07 816 (cond ((and (stringp dir1) (string= merge-autostore-dir dir1))
3af0304a
MK
817 (or (y-or-n-p
818 "Directory for saving merged files = Directory A. Sure? ")
92c51e07
MK
819 (error "Directory merge aborted")))
820 ((and (stringp dir2) (string= merge-autostore-dir dir2))
3af0304a
MK
821 (or (y-or-n-p
822 "Directory for saving merged files = Directory B. Sure? ")
92c51e07
MK
823 (error "Directory merge aborted")))
824 ((and (stringp dir3) (string= merge-autostore-dir dir3))
825 (or (y-or-n-p
3af0304a 826 "Directory for saving merged files = Ancestor Directory. Sure? ")
92c51e07 827 (error "Directory merge aborted")))))
71296446
JB
828
829 (setq dir-diff-struct (ediff-intersect-directories
c3912d54
MK
830 jobname
831 regexp dir1 dir2 dir3 merge-autostore-dir))
87c668b4
MK
832 (setq startup-hooks
833 ;; this sets various vars in the meta buffer inside
834 ;; ediff-prepare-meta-buffer
086171bf
MK
835 (cons `(lambda ()
836 ;; tell what to do if the user clicks on a session record
837 (setq ediff-session-action-function (quote ,action))
71296446 838 ;; set ediff-dir-difference-list
c3912d54
MK
839 (setq ediff-dir-difference-list
840 (cdr (quote ,dir-diff-struct))))
87c668b4 841 startup-hooks))
71296446 842 (setq meta-buf (ediff-prepare-meta-buffer
bbe6126c 843 'ediff-filegroup-action
c3912d54 844 (car dir-diff-struct)
87c668b4
MK
845 "*Ediff Session Group Panel"
846 'ediff-redraw-directory-group-buffer
847 jobname
848 startup-hooks))
849 (ediff-show-meta-buffer meta-buf)
850 ))
851
3af0304a
MK
852;; MERGE-AUTOSTORE-DIR can be given to tell ediff where to store the merged
853;; files
71296446 854(defun ediff-directory-revisions-internal (dir1 regexp action jobname
3af0304a
MK
855 &optional startup-hooks
856 merge-autostore-dir)
87c668b4 857 (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1)))
92c51e07 858
3af0304a
MK
859 (if merge-autostore-dir
860 (or (stringp merge-autostore-dir)
861 (error "%S: Directory for storing merged files must be a string"
862 jobname)))
863 (let (file-list meta-buf)
71296446 864 (if (and ediff-autostore-merges
3af0304a
MK
865 (ediff-merge-metajob jobname)
866 (not merge-autostore-dir))
71296446 867 (setq merge-autostore-dir
ec6aebe8 868 (read-directory-name "Save merged files in directory: "
3af0304a
MK
869 (if ediff-use-last-dir
870 ediff-last-merge-autostore-dir
871 (ediff-strip-last-dir dir1))
872 nil
873 'must-match)))
92c51e07 874 ;; verify merge-autostore-dir != dir1
3af0304a 875 (if (and merge-autostore-dir
92c51e07
MK
876 (stringp dir1)
877 (string= merge-autostore-dir dir1))
878 (or (y-or-n-p
3af0304a 879 "Directory for saving merged file = directory A. Sure? ")
92c51e07 880 (error "Merge of directory revisions aborted")))
71296446 881
87c668b4 882 (setq file-list
92c51e07
MK
883 (ediff-get-directory-files-under-revision
884 jobname regexp dir1 merge-autostore-dir))
87c668b4
MK
885 (setq startup-hooks
886 ;; this sets various vars in the meta buffer inside
887 ;; ediff-prepare-meta-buffer
086171bf
MK
888 (cons `(lambda ()
889 ;; tell what to do if the user clicks on a session record
890 (setq ediff-session-action-function (quote ,action)))
87c668b4 891 startup-hooks))
71296446 892 (setq meta-buf (ediff-prepare-meta-buffer
bbe6126c 893 'ediff-filegroup-action
87c668b4
MK
894 file-list
895 "*Ediff Session Group Panel"
896 'ediff-redraw-directory-group-buffer
897 jobname
898 startup-hooks))
899 (ediff-show-meta-buffer meta-buf)
900 ))
0f0b0a86
KH
901
902
903;;; Compare regions and windows
904
905;;;###autoload
f1a5512a
KH
906(defun ediff-windows-wordwise (dumb-mode &optional wind-A wind-B startup-hooks)
907 "Compare WIND-A and WIND-B, which are selected by clicking, wordwise.
0f0b0a86
KH
908With prefix argument, DUMB-MODE, or on a non-windowing display, works as
909follows:
910If WIND-A is nil, use selected window.
911If WIND-B is nil, use window next to WIND-A."
0f0b0a86 912 (interactive "P")
f1a5512a
KH
913 (ediff-windows dumb-mode wind-A wind-B
914 startup-hooks 'ediff-windows-wordwise 'word-mode))
71296446 915
f1a5512a
KH
916;;;###autoload
917(defun ediff-windows-linewise (dumb-mode &optional wind-A wind-B startup-hooks)
918 "Compare WIND-A and WIND-B, which are selected by clicking, linewise.
919With prefix argument, DUMB-MODE, or on a non-windowing display, works as
920follows:
921If WIND-A is nil, use selected window.
922If WIND-B is nil, use window next to WIND-A."
923 (interactive "P")
924 (ediff-windows dumb-mode wind-A wind-B
925 startup-hooks 'ediff-windows-linewise nil))
71296446 926
f1a5512a
KH
927;; Compare WIND-A and WIND-B, which are selected by clicking.
928;; With prefix argument, DUMB-MODE, or on a non-windowing display,
929;; works as follows:
930;; If WIND-A is nil, use selected window.
931;; If WIND-B is nil, use window next to WIND-A.
932(defun ediff-windows (dumb-mode wind-A wind-B startup-hooks job-name word-mode)
933 (if (or dumb-mode (not (ediff-window-display-p)))
0f0b0a86
KH
934 (setq wind-A (ediff-get-next-window wind-A nil)
935 wind-B (ediff-get-next-window wind-B wind-A))
936 (setq wind-A (ediff-get-window-by-clicking wind-A nil 1)
937 wind-B (ediff-get-window-by-clicking wind-B wind-A 2)))
71296446 938
0f0b0a86
KH
939 (let ((buffer-A (window-buffer wind-A))
940 (buffer-B (window-buffer wind-B))
941 beg-A end-A beg-B end-B)
71296446 942
0f0b0a86
KH
943 (save-excursion
944 (save-window-excursion
a7acbbe4 945 (sit-for 0) ; sync before using window-start/end -- a precaution
0f0b0a86
KH
946 (select-window wind-A)
947 (setq beg-A (window-start)
948 end-A (window-end))
949 (select-window wind-B)
950 (setq beg-B (window-start)
951 end-B (window-end))))
50a07e18
MK
952 (setq buffer-A
953 (ediff-clone-buffer-for-window-comparison
c3912d54 954 buffer-A wind-A "-Window.A-")
50a07e18
MK
955 buffer-B
956 (ediff-clone-buffer-for-window-comparison
c3912d54 957 buffer-B wind-B "-Window.B-"))
0f0b0a86
KH
958 (ediff-regions-internal
959 buffer-A beg-A end-A buffer-B beg-B end-B
ddc90f39 960 startup-hooks job-name word-mode nil)))
71296446 961
50a07e18 962
0f0b0a86 963;;;###autoload
f1a5512a 964(defun ediff-regions-wordwise (buffer-A buffer-B &optional startup-hooks)
50a07e18 965 "Run Ediff on a pair of regions in specified buffers.
279c800c 966Regions \(i.e., point and mark\) can be set in advance or marked interactively.
0f0b0a86 967This function is effective only for relatively small regions, up to 200
3af0304a 968lines. For large regions, use `ediff-regions-linewise'."
71296446 969 (interactive
0f0b0a86
KH
970 (let (bf)
971 (list (setq bf (read-buffer "Region's A buffer: "
972 (ediff-other-buffer "") t))
973 (read-buffer "Region's B buffer: "
974 (progn
975 ;; realign buffers so that two visible bufs will be
976 ;; at the top
977 (save-window-excursion (other-window 1))
978 (ediff-other-buffer bf))
979 t))))
980 (if (not (ediff-buffer-live-p buffer-A))
981 (error "Buffer %S doesn't exist" buffer-A))
982 (if (not (ediff-buffer-live-p buffer-B))
983 (error "Buffer %S doesn't exist" buffer-B))
71296446
JB
984
985
50a07e18 986 (let ((buffer-A
c3912d54 987 (ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
50a07e18 988 (buffer-B
c3912d54 989 (ediff-clone-buffer-for-region-comparison buffer-B "-Region.B-"))
50a07e18 990 reg-A-beg reg-A-end reg-B-beg reg-B-end)
7fdbcd83 991 (with-current-buffer buffer-A
0f0b0a86
KH
992 (setq reg-A-beg (region-beginning)
993 reg-A-end (region-end))
994 (set-buffer buffer-B)
995 (setq reg-B-beg (region-beginning)
996 reg-B-end (region-end)))
71296446 997
0f0b0a86
KH
998 (ediff-regions-internal
999 (get-buffer buffer-A) reg-A-beg reg-A-end
1000 (get-buffer buffer-B) reg-B-beg reg-B-end
ddc90f39 1001 startup-hooks 'ediff-regions-wordwise 'word-mode nil)))
71296446 1002
0f0b0a86 1003;;;###autoload
f1a5512a 1004(defun ediff-regions-linewise (buffer-A buffer-B &optional startup-hooks)
50a07e18 1005 "Run Ediff on a pair of regions in specified buffers.
279c800c 1006Regions \(i.e., point and mark\) can be set in advance or marked interactively.
0f0b0a86
KH
1007Each region is enlarged to contain full lines.
1008This function is effective for large regions, over 100-200
3af0304a 1009lines. For small regions, use `ediff-regions-wordwise'."
71296446 1010 (interactive
0f0b0a86
KH
1011 (let (bf)
1012 (list (setq bf (read-buffer "Region A's buffer: "
1013 (ediff-other-buffer "") t))
1014 (read-buffer "Region B's buffer: "
1015 (progn
1016 ;; realign buffers so that two visible bufs will be
1017 ;; at the top
1018 (save-window-excursion (other-window 1))
1019 (ediff-other-buffer bf))
1020 t))))
fcbadd58 1021 (if (not (ediff-buffer-live-p buffer-A))
0f0b0a86 1022 (error "Buffer %S doesn't exist" buffer-A))
fcbadd58 1023 (if (not (ediff-buffer-live-p buffer-B))
0f0b0a86 1024 (error "Buffer %S doesn't exist" buffer-B))
71296446 1025
50a07e18 1026 (let ((buffer-A
c3912d54 1027 (ediff-clone-buffer-for-region-comparison buffer-A "-Region.A-"))
50a07e18 1028 (buffer-B
c3912d54 1029 (ediff-clone-buffer-for-region-comparison buffer-B "-Region.B-"))
50a07e18 1030 reg-A-beg reg-A-end reg-B-beg reg-B-end)
7fdbcd83 1031 (with-current-buffer buffer-A
0f0b0a86
KH
1032 (setq reg-A-beg (region-beginning)
1033 reg-A-end (region-end))
1034 ;; enlarge the region to hold full lines
71296446 1035 (goto-char reg-A-beg)
0f0b0a86
KH
1036 (beginning-of-line)
1037 (setq reg-A-beg (point))
71296446 1038 (goto-char reg-A-end)
0f0b0a86
KH
1039 (end-of-line)
1040 (or (eobp) (forward-char)) ; include the newline char
1041 (setq reg-A-end (point))
71296446 1042
0f0b0a86
KH
1043 (set-buffer buffer-B)
1044 (setq reg-B-beg (region-beginning)
1045 reg-B-end (region-end))
1046 ;; enlarge the region to hold full lines
71296446 1047 (goto-char reg-B-beg)
0f0b0a86
KH
1048 (beginning-of-line)
1049 (setq reg-B-beg (point))
71296446 1050 (goto-char reg-B-end)
0f0b0a86
KH
1051 (end-of-line)
1052 (or (eobp) (forward-char)) ; include the newline char
1053 (setq reg-B-end (point))
1054 ) ; save excursion
71296446 1055
0f0b0a86
KH
1056 (ediff-regions-internal
1057 (get-buffer buffer-A) reg-A-beg reg-A-end
1058 (get-buffer buffer-B) reg-B-beg reg-B-end
1e70790f 1059 startup-hooks 'ediff-regions-linewise nil nil))) ; no word mode
71296446 1060
0f0b0a86 1061;; compare region beg-A to end-A of buffer-A
71296446 1062;; to regions beg-B -- end-B in buffer-B.
0f0b0a86 1063(defun ediff-regions-internal (buffer-A beg-A end-A buffer-B beg-B end-B
ddc90f39
MK
1064 startup-hooks job-name word-mode
1065 setup-parameters)
0f0b0a86
KH
1066 (let ((tmp-buffer (get-buffer-create ediff-tmp-buffer))
1067 overl-A overl-B
1068 file-A file-B)
2de386ca
MK
1069 (unwind-protect
1070 (progn
1071 ;; in case beg/end-A/B aren't markers--make them into markers
1072 (ediff-with-current-buffer buffer-A
1073 (setq beg-A (move-marker (make-marker) beg-A)
1074 end-A (move-marker (make-marker) end-A)))
1075 (ediff-with-current-buffer buffer-B
1076 (setq beg-B (move-marker (make-marker) beg-B)
1077 end-B (move-marker (make-marker) end-B)))
01795a1b 1078
2de386ca
MK
1079 ;; make file-A
1080 (if word-mode
1081 (ediff-wordify beg-A end-A buffer-A tmp-buffer)
1082 (ediff-copy-to-buffer beg-A end-A buffer-A tmp-buffer))
1083 (setq file-A (ediff-make-temp-file tmp-buffer "regA"))
1084
1085 ;; make file-B
1086 (if word-mode
1087 (ediff-wordify beg-B end-B buffer-B tmp-buffer)
1088 (ediff-copy-to-buffer beg-B end-B buffer-B tmp-buffer))
1089 (setq file-B (ediff-make-temp-file tmp-buffer "regB"))
01795a1b 1090
2de386ca
MK
1091 (setq overl-A (ediff-make-bullet-proof-overlay beg-A end-A buffer-A))
1092 (setq overl-B (ediff-make-bullet-proof-overlay beg-B end-B buffer-B))
1093 (ediff-setup buffer-A file-A
1094 buffer-B file-B
1095 nil nil ; buffer & file C
1096 (cons `(lambda ()
1097 (delete-file ,file-A)
1098 (delete-file ,file-B))
1099 startup-hooks)
1100 (append
1101 (list (cons 'ediff-word-mode word-mode)
1102 (cons 'ediff-narrow-bounds (list overl-A overl-B))
1103 (cons 'ediff-job-name job-name))
1104 setup-parameters)))
1105 (if (and (stringp file-A) (file-exists-p file-A))
1106 (delete-file file-A))
1107 (if (and (stringp file-B) (file-exists-p file-B))
1108 (delete-file file-B)))
0f0b0a86 1109 ))
71296446
JB
1110
1111
0f0b0a86 1112;;; Merge files and buffers
71296446 1113
0f0b0a86
KH
1114;;;###autoload
1115(defalias 'ediff-merge 'ediff-merge-files)
71296446 1116
0f0b0a86
KH
1117(defsubst ediff-merge-on-startup ()
1118 (ediff-do-merge 0)
17561e4f
MK
1119 ;; Can't remember why this is here, but it may cause the automatically merged
1120 ;; buffer to be lost. So, keep the buffer modified.
1121 ;;(ediff-with-current-buffer ediff-buffer-C
1122 ;; (set-buffer-modified-p nil))
1123 )
0f0b0a86
KH
1124
1125;;;###autoload
328b4b70
MK
1126(defun ediff-merge-files (file-A file-B
1127 ;; MERGE-BUFFER-FILE is the file to be
71296446 1128 ;; associated with the merge buffer
328b4b70 1129 &optional startup-hooks merge-buffer-file)
0f0b0a86
KH
1130 "Merge two files without ancestor."
1131 (interactive
1132 (let ((dir-A (if ediff-use-last-dir
1133 ediff-last-dir-A
1134 default-directory))
1135 dir-B f)
87c668b4 1136 (list (setq f (ediff-read-file-name
50a07e18
MK
1137 "File A to merge"
1138 dir-A
1139 (ediff-get-default-file-name)
1140 'no-dirs))
71296446 1141 (ediff-read-file-name "File B to merge"
0f0b0a86
KH
1142 (setq dir-B
1143 (if ediff-use-last-dir
71296446 1144 ediff-last-dir-B
0f0b0a86
KH
1145 (file-name-directory f)))
1146 (progn
f573c8b0
MK
1147 (ediff-add-to-history
1148 'file-name-history
1149 (ediff-abbreviate-file-name
1150 (expand-file-name
1151 (file-name-nondirectory f)
1152 dir-B)))
657f9cb8 1153 (ediff-get-default-file-name f 1)))
0f0b0a86
KH
1154 )))
1155 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
71296446 1156 (ediff-files-internal file-A
0f0b0a86
KH
1157 (if (file-directory-p file-B)
1158 (expand-file-name
1159 (file-name-nondirectory file-A) file-B)
1160 file-B)
1161 nil ; file-C
1162 startup-hooks
328b4b70
MK
1163 'ediff-merge-files
1164 merge-buffer-file))
71296446 1165
0f0b0a86
KH
1166;;;###autoload
1167(defun ediff-merge-files-with-ancestor (file-A file-B file-ancestor
328b4b70
MK
1168 &optional
1169 startup-hooks
1170 ;; MERGE-BUFFER-FILE is the file
1171 ;; to be associated with the
1172 ;; merge buffer
1173 merge-buffer-file)
0f0b0a86
KH
1174 "Merge two files with ancestor."
1175 (interactive
1176 (let ((dir-A (if ediff-use-last-dir
1177 ediff-last-dir-A
1178 default-directory))
1179 dir-B dir-ancestor f ff)
87c668b4 1180 (list (setq f (ediff-read-file-name
50a07e18
MK
1181 "File A to merge"
1182 dir-A
1183 (ediff-get-default-file-name)
1184 'no-dirs))
71296446 1185 (setq ff (ediff-read-file-name "File B to merge"
0f0b0a86
KH
1186 (setq dir-B
1187 (if ediff-use-last-dir
71296446 1188 ediff-last-dir-B
0f0b0a86
KH
1189 (file-name-directory f)))
1190 (progn
f573c8b0
MK
1191 (ediff-add-to-history
1192 'file-name-history
1193 (ediff-abbreviate-file-name
1194 (expand-file-name
1195 (file-name-nondirectory f)
1196 dir-B)))
657f9cb8 1197 (ediff-get-default-file-name f 1))))
71296446 1198 (ediff-read-file-name "Ancestor file"
0f0b0a86
KH
1199 (setq dir-ancestor
1200 (if ediff-use-last-dir
1201 ediff-last-dir-ancestor
1202 (file-name-directory ff)))
1203 (progn
f573c8b0
MK
1204 (ediff-add-to-history
1205 'file-name-history
1206 (ediff-abbreviate-file-name
1207 (expand-file-name
1208 (file-name-nondirectory ff)
1209 dir-ancestor)))
657f9cb8 1210 (ediff-get-default-file-name ff 2)))
0f0b0a86
KH
1211 )))
1212 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
71296446 1213 (ediff-files-internal file-A
0f0b0a86
KH
1214 (if (file-directory-p file-B)
1215 (expand-file-name
1216 (file-name-nondirectory file-A) file-B)
1217 file-B)
1218 file-ancestor
1219 startup-hooks
328b4b70
MK
1220 'ediff-merge-files-with-ancestor
1221 merge-buffer-file))
71296446 1222
0f0b0a86
KH
1223;;;###autoload
1224(defalias 'ediff-merge-with-ancestor 'ediff-merge-files-with-ancestor)
71296446 1225
0f0b0a86 1226;;;###autoload
328b4b70
MK
1227(defun ediff-merge-buffers (buffer-A buffer-B
1228 &optional
1229 ;; MERGE-BUFFER-FILE is the file to be
1230 ;; associated with the merge buffer
1231 startup-hooks job-name merge-buffer-file)
0f0b0a86 1232 "Merge buffers without ancestor."
71296446 1233 (interactive
0f0b0a86
KH
1234 (let (bf)
1235 (list (setq bf (read-buffer "Buffer A to merge: "
1236 (ediff-other-buffer "") t))
1237 (read-buffer "Buffer B to merge: "
1238 (progn
1239 ;; realign buffers so that two visible bufs will be
1240 ;; at the top
1241 (save-window-excursion (other-window 1))
1242 (ediff-other-buffer bf))
1243 t))))
71296446 1244
0f0b0a86
KH
1245 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
1246 (or job-name (setq job-name 'ediff-merge-buffers))
1247 (ediff-buffers-internal
328b4b70 1248 buffer-A buffer-B nil startup-hooks job-name merge-buffer-file))
71296446 1249
0f0b0a86 1250;;;###autoload
328b4b70
MK
1251(defun ediff-merge-buffers-with-ancestor (buffer-A buffer-B buffer-ancestor
1252 &optional
1253 startup-hooks
1254 job-name
1255 ;; MERGE-BUFFER-FILE is the
1256 ;; file to be associated
1257 ;; with the merge buffer
1258 merge-buffer-file)
0f0b0a86 1259 "Merge buffers with ancestor."
71296446 1260 (interactive
0f0b0a86
KH
1261 (let (bf bff)
1262 (list (setq bf (read-buffer "Buffer A to merge: "
1263 (ediff-other-buffer "") t))
1264 (setq bff (read-buffer "Buffer B to merge: "
1265 (progn
1266 ;; realign buffers so that two visible
1267 ;; bufs will be at the top
1268 (save-window-excursion (other-window 1))
1269 (ediff-other-buffer bf))
1270 t))
1271 (read-buffer "Ancestor buffer: "
1272 (progn
1273 ;; realign buffers so that three visible
1274 ;; bufs will be at the top
1275 (save-window-excursion (other-window 1))
1276 (ediff-other-buffer (list bf bff)))
1277 t)
1278 )))
71296446 1279
0f0b0a86
KH
1280 (setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
1281 (or job-name (setq job-name 'ediff-merge-buffers-with-ancestor))
1282 (ediff-buffers-internal
328b4b70 1283 buffer-A buffer-B buffer-ancestor startup-hooks job-name merge-buffer-file))
71296446 1284
0f0b0a86
KH
1285
1286;;;###autoload
328b4b70
MK
1287(defun ediff-merge-revisions (&optional file startup-hooks merge-buffer-file)
1288 ;; MERGE-BUFFER-FILE is the file to be associated with the merge buffer
0f0b0a86 1289 "Run Ediff by merging two revisions of a file.
87c668b4
MK
1290The file is the optional FILE argument or the file visited by the current
1291buffer."
1292 (interactive)
87c668b4 1293 (if (stringp file) (find-file file))
4ae69eac 1294 (let (rev1 rev2)
87c668b4
MK
1295 (setq rev1
1296 (read-string
1297 (format
5b76833f 1298 "Version 1 to merge (default %s's working version): "
87c668b4
MK
1299 (if (stringp file)
1300 (file-name-nondirectory file) "current buffer")))
1301 rev2
1302 (read-string
1303 (format
5b76833f 1304 "Version 2 to merge (default %s): "
87c668b4
MK
1305 (if (stringp file)
1306 (file-name-nondirectory file) "current buffer"))))
4ae69eac
MK
1307 (ediff-load-version-control)
1308 ;; ancestor-revision=nil
1309 (funcall
92c51e07 1310 (intern (format "ediff-%S-merge-internal" ediff-version-control-package))
328b4b70 1311 rev1 rev2 nil startup-hooks merge-buffer-file)))
71296446 1312
0f0b0a86
KH
1313
1314;;;###autoload
328b4b70
MK
1315(defun ediff-merge-revisions-with-ancestor (&optional
1316 file startup-hooks
1317 ;; MERGE-BUFFER-FILE is the file to
1318 ;; be associated with the merge
1319 ;; buffer
1320 merge-buffer-file)
87c668b4 1321 "Run Ediff by merging two revisions of a file with a common ancestor.
110c171f 1322The file is the optional FILE argument or the file visited by the current
87c668b4
MK
1323buffer."
1324 (interactive)
87c668b4 1325 (if (stringp file) (find-file file))
4ae69eac 1326 (let (rev1 rev2 ancestor-rev)
87c668b4
MK
1327 (setq rev1
1328 (read-string
1329 (format
5b76833f 1330 "Version 1 to merge (default %s's working version): "
87c668b4
MK
1331 (if (stringp file)
1332 (file-name-nondirectory file) "current buffer")))
1333 rev2
1334 (read-string
1335 (format
5b76833f 1336 "Version 2 to merge (default %s): "
87c668b4
MK
1337 (if (stringp file)
1338 (file-name-nondirectory file) "current buffer")))
1339 ancestor-rev
1340 (read-string
1341 (format
5b76833f 1342 "Ancestor version (default %s's base revision): "
87c668b4
MK
1343 (if (stringp file)
1344 (file-name-nondirectory file) "current buffer"))))
4ae69eac
MK
1345 (ediff-load-version-control)
1346 (funcall
92c51e07 1347 (intern (format "ediff-%S-merge-internal" ediff-version-control-package))
328b4b70 1348 rev1 rev2 ancestor-rev startup-hooks merge-buffer-file)))
4ae69eac 1349
0f0b0a86 1350;;; Apply patch
a5c7df1a
GM
1351(defvar ediff-last-dir-patch)
1352(defvar ediff-patch-default-directory)
1353(declare-function ediff-get-patch-buffer "ediff-ptch"
1354 (&optional arg patch-buf))
1355(declare-function ediff-dispatch-file-patching-job "ediff-ptch"
1356 (patch-buf filename &optional startup-hooks))
0f0b0a86 1357
bbe6126c 1358;;;###autoload
3af0304a 1359(defun ediff-patch-file (&optional arg patch-buf)
be958f1d 1360 "Query for a file name, and then run Ediff by patching that file.
3af0304a
MK
1361If optional PATCH-BUF is given, use the patch in that buffer
1362and don't ask the user.
1363If prefix argument, then: if even argument, assume that the patch is in a
1364buffer. If odd -- assume it is in a file."
1365 (interactive "P")
1366 (let (source-dir source-file)
bbe6126c 1367 (require 'ediff-ptch)
3af0304a
MK
1368 (setq patch-buf
1369 (ediff-get-patch-buffer
1370 (if arg (prefix-numeric-value arg)) patch-buf))
bbe6126c
MK
1371 (setq source-dir (cond (ediff-use-last-dir ediff-last-dir-patch)
1372 ((and (not ediff-patch-default-directory)
1373 (buffer-file-name patch-buf))
1374 (file-name-directory
1375 (expand-file-name
1376 (buffer-file-name patch-buf))))
1377 (t default-directory)))
1378 (setq source-file
71296446 1379 (read-file-name
3af0304a 1380 "File to patch (directory, if multifile patch): "
2550055a
MK
1381 ;; use an explicit initial file
1382 source-dir nil nil (ediff-get-default-file-name)))
bbe6126c 1383 (ediff-dispatch-file-patching-job patch-buf source-file)))
0f0b0a86 1384
a5c7df1a
GM
1385(declare-function ediff-patch-buffer-internal "ediff-ptch"
1386 (patch-buf buf-to-patch-name &optional startup-hooks))
1387
bbe6126c 1388;;;###autoload
3af0304a 1389(defun ediff-patch-buffer (&optional arg patch-buf)
acfb6f24
MK
1390 "Run Ediff by patching the buffer specified at prompt.
1391Without the optional prefix ARG, asks if the patch is in some buffer and
1392prompts for the buffer or a file, depending on the answer.
1393With ARG=1, assumes the patch is in a file and prompts for the file.
1394With ARG=2, assumes the patch is in a buffer and prompts for the buffer.
1395PATCH-BUF is an optional argument, which specifies the buffer that contains the
1396patch. If not given, the user is prompted according to the prefix argument."
3af0304a
MK
1397 (interactive "P")
1398 (require 'ediff-ptch)
1399 (setq patch-buf
1400 (ediff-get-patch-buffer
1401 (if arg (prefix-numeric-value arg)) patch-buf))
1402 (ediff-patch-buffer-internal
1403 patch-buf
1404 (read-buffer
1405 "Which buffer to patch? "
b6178721 1406 (ediff-other-buffer patch-buf))))
71296446 1407
3af0304a 1408
bbe6126c
MK
1409;;;###autoload
1410(defalias 'epatch 'ediff-patch-file)
1411;;;###autoload
1412(defalias 'epatch-buffer 'ediff-patch-buffer)
0f0b0a86
KH
1413
1414
813f532d 1415
0f0b0a86 1416\f
71296446
JB
1417;;; Versions Control functions
1418
813f532d 1419;;;###autoload
87c668b4
MK
1420(defun ediff-revision (&optional file startup-hooks)
1421 "Run Ediff by comparing versions of a file.
7261ece3
MK
1422The file is an optional FILE argument or the file entered at the prompt.
1423Default: the file visited by the current buffer.
1424Uses `vc.el' or `rcs.el' depending on `ediff-version-control-package'."
87c668b4 1425 ;; if buffer is non-nil, use that buffer instead of the current buffer
f1a5512a 1426 (interactive "P")
7261ece3
MK
1427 (if (not (stringp file))
1428 (setq file
1429 (ediff-read-file-name "Compare revisions for file"
1430 (if ediff-use-last-dir
1431 ediff-last-dir-A
1432 default-directory)
50a07e18 1433 (ediff-get-default-file-name)
71296446 1434 'no-dirs)))
7261ece3
MK
1435 (find-file file)
1436 (if (and (buffer-modified-p)
c3994f6c
JB
1437 (y-or-n-p (format "Buffer %s is modified. Save buffer? "
1438 (buffer-name))))
7261ece3 1439 (save-buffer (current-buffer)))
f1a5512a 1440 (let (rev1 rev2)
87c668b4
MK
1441 (setq rev1
1442 (read-string
5b76833f 1443 (format "Revision 1 to compare (default %s's latest revision): "
7261ece3 1444 (file-name-nondirectory file)))
87c668b4 1445 rev2
71296446 1446 (read-string
5b76833f 1447 (format "Revision 2 to compare (default %s's current state): "
7261ece3 1448 (file-name-nondirectory file))))
f1a5512a
KH
1449 (ediff-load-version-control)
1450 (funcall
92c51e07 1451 (intern (format "ediff-%S-internal" ediff-version-control-package))
87c668b4 1452 rev1 rev2 startup-hooks)
f1a5512a 1453 ))
1e70790f
MK
1454
1455
1456;;;###autoload
1457(defalias 'erevision 'ediff-revision)
71296446
JB
1458
1459
0f0b0a86
KH
1460;; Test if version control package is loaded and load if not
1461;; Is SILENT is non-nil, don't report error if package is not found.
1462(defun ediff-load-version-control (&optional silent)
4ae69eac 1463 (require 'ediff-vers)
0f0b0a86
KH
1464 (or (featurep ediff-version-control-package)
1465 (if (locate-library (symbol-name ediff-version-control-package))
1466 (progn
1467 (message "") ; kill the message from `locate-library'
87c668b4 1468 (require ediff-version-control-package))
0f0b0a86 1469 (or silent
3af0304a 1470 (error "Version control package %S.el not found. Use vc.el instead"
0f0b0a86 1471 ediff-version-control-package)))))
87c668b4 1472
b3a26225 1473
138df2ce
MK
1474;;;###autoload
1475(defun ediff-version ()
1476 "Return string describing the version of Ediff.
1477When called interactively, displays the version."
1478 (interactive)
5f70c169
GM
1479 (if (if (featurep 'xemacs)
1480 (interactive-p)
1481 (called-interactively-p 'interactive))
f6e7ec02 1482 (message "%s" (ediff-version))
138df2ce
MK
1483 (format "Ediff %s of %s" ediff-version ediff-date)))
1484
76d0c408 1485;; info is run first, and will autoload info.el.
16d9f896 1486(declare-function Info-goto-node "info" (nodename &optional fork strict-case))
813f532d 1487
4ae69eac 1488;;;###autoload
92c51e07
MK
1489(defun ediff-documentation (&optional node)
1490 "Display Ediff's manual.
1491With optional NODE, goes to that node."
4ae69eac
MK
1492 (interactive)
1493 (let ((ctl-window ediff-control-window)
1494 (ctl-buf ediff-control-buffer))
1495
1496 (ediff-skip-unsuitable-frames)
1497 (condition-case nil
1498 (progn
1499 (pop-to-buffer (get-buffer-create "*info*"))
e83d1fe8 1500 (info (if (featurep 'xemacs) "ediff.info" "ediff"))
92c51e07
MK
1501 (if node
1502 (Info-goto-node node)
1503 (message "Type `i' to search for a specific topic"))
12b4c0ea 1504 (raise-frame))
4ae69eac 1505 (error (beep 1)
bbe6126c 1506 (with-output-to-temp-buffer ediff-msg-buffer
e4d2c130
DL
1507 (ediff-with-current-buffer standard-output
1508 (fundamental-mode))
92c51e07 1509 (princ ediff-BAD-INFO))
4ae69eac
MK
1510 (if (window-live-p ctl-window)
1511 (progn
1512 (select-window ctl-window)
1513 (set-window-buffer ctl-window ctl-buf)))))))
71296446 1514
4ae69eac 1515
fb0fb4fa
JL
1516(dolist (mess '("^Errors in diff output. Diff output is in "
1517 "^Hmm... I don't see an Ediff command around here...$"
1518 "^Undocumented command! Type `G' in Ediff Control Panel to drop a note to the Ediff maintainer$"
1519 ": This command runs in Ediff Control Buffer only!$"
1520 ": Invalid op in ediff-check-version$"
1521 "^ediff-shrink-window-C can be used only for merging jobs$"
1522 "^Lost difference info on these directories$"
1523 "^This command is inapplicable in the present context$"
1524 "^This session group has no parent$"
1525 "^Can't hide active session, $"
1526 "^Ediff: something wrong--no multiple diffs buffer$"
1527 "^Can't make context diff for Session $"
1528 "^The patch buffer wasn't found$"
1529 "^Aborted$"
1530 "^This Ediff session is not part of a session group$"
1531 "^No active Ediff sessions or corrupted session registry$"
1532 "^No session info in this line$"
1533 "^`.*' is not an ordinary file$"
1534 "^Patch appears to have failed$"
1535 "^Recomputation of differences cancelled$"
1536 "^No fine differences in this mode$"
1537 "^Lost connection to ancestor buffer...sorry$"
1538 "^Not merging with ancestor$"
1539 "^Don't know how to toggle read-only in buffer "
1540 "Emacs is not running as a window application$"
1541 "^This command makes sense only when merging with an ancestor$"
1542 "^At end of the difference list$"
1543 "^At beginning of the difference list$"
1544 "^Nothing saved for diff .* in buffer "
1545 "^Buffer is out of sync for file "
1546 "^Buffer out of sync for file "
1547 "^Output from `diff' not found$"
1548 "^You forgot to specify a region in buffer "
1549 "^All right. Make up your mind and come back...$"
1550 "^Current buffer is not visiting any file$"
1551 "^Failed to retrieve revision: $"
1552 "^Can't determine display width.$"
1553 "^File `.*' does not exist or is not readable$"
1554 "^File `.*' is a directory$"
1555 "^Buffer .* doesn't exist$"
1556 "^Directories . and . are the same: "
1557 "^Directory merge aborted$"
1558 "^Merge of directory revisions aborted$"
1559 "^Buffer .* doesn't exist$"
1560 "^There is no file to merge$"
1561 "^Version control package .*.el not found. Use vc.el instead$"))
1562 (add-to-list 'debug-ignored-errors mess))
4ae69eac
MK
1563
1564
f1e6674b
MK
1565\f
1566;;; Command line interface
1567
1568;;;###autoload
1569(defun ediff-files-command ()
1570 (let ((file-a (nth 0 command-line-args-left))
1571 (file-b (nth 1 command-line-args-left)))
1572 (setq command-line-args-left (nthcdr 2 command-line-args-left))
1573 (ediff file-a file-b)))
1574
1575;;;###autoload
1576(defun ediff3-files-command ()
1577 (let ((file-a (nth 0 command-line-args-left))
1578 (file-b (nth 1 command-line-args-left))
1579 (file-c (nth 2 command-line-args-left)))
1580 (setq command-line-args-left (nthcdr 3 command-line-args-left))
1581 (ediff3 file-a file-b file-c)))
1582
1583;;;###autoload
1584(defun ediff-merge-command ()
1585 (let ((file-a (nth 0 command-line-args-left))
1586 (file-b (nth 1 command-line-args-left)))
1587 (setq command-line-args-left (nthcdr 2 command-line-args-left))
1588 (ediff-merge-files file-a file-b)))
1589
1590;;;###autoload
1591(defun ediff-merge-with-ancestor-command ()
1592 (let ((file-a (nth 0 command-line-args-left))
1593 (file-b (nth 1 command-line-args-left))
1594 (ancestor (nth 2 command-line-args-left)))
1595 (setq command-line-args-left (nthcdr 3 command-line-args-left))
1596 (ediff-merge-files-with-ancestor file-a file-b ancestor)))
1597
1598;;;###autoload
1599(defun ediff-directories-command ()
1600 (let ((file-a (nth 0 command-line-args-left))
1601 (file-b (nth 1 command-line-args-left))
1602 (regexp (nth 2 command-line-args-left)))
1603 (setq command-line-args-left (nthcdr 3 command-line-args-left))
1604 (ediff-directories file-a file-b regexp)))
1605
1606;;;###autoload
1607(defun ediff-directories3-command ()
1608 (let ((file-a (nth 0 command-line-args-left))
1609 (file-b (nth 1 command-line-args-left))
1610 (file-c (nth 2 command-line-args-left))
1611 (regexp (nth 3 command-line-args-left)))
1612 (setq command-line-args-left (nthcdr 4 command-line-args-left))
1613 (ediff-directories3 file-a file-b file-c regexp)))
1614
1615;;;###autoload
1616(defun ediff-merge-directories-command ()
1617 (let ((file-a (nth 0 command-line-args-left))
1618 (file-b (nth 1 command-line-args-left))
1619 (regexp (nth 2 command-line-args-left)))
1620 (setq command-line-args-left (nthcdr 3 command-line-args-left))
1621 (ediff-merge-directories file-a file-b regexp)))
1622
1623;;;###autoload
1624(defun ediff-merge-directories-with-ancestor-command ()
1625 (let ((file-a (nth 0 command-line-args-left))
1626 (file-b (nth 1 command-line-args-left))
1627 (ancestor (nth 2 command-line-args-left))
1628 (regexp (nth 3 command-line-args-left)))
1629 (setq command-line-args-left (nthcdr 4 command-line-args-left))
1630 (ediff-merge-directories-with-ancestor file-a file-b ancestor regexp)))
1631
1632
1633
8ea74b0e
MK
1634(require 'ediff-util)
1635
1636(run-hooks 'ediff-load-hook)
1637
b6178721 1638
fa043571
SM
1639;; Local Variables:
1640;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
1641;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
1642;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
1643;; End:
4ae69eac 1644
813f532d 1645;;; ediff.el ends here