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