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