1 ;;; ediff.el --- a comprehensive visual interface to diff & patch
2 ;;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4 ;; Author: Michael Kifer <kifer@cs.sunysb.edu>
5 ;; Created: February 2, 1994
6 ;; Keywords: comparing, merging, patching, version control.
8 (defconst ediff-version
"2.26" "The current version of Ediff")
9 (defconst ediff-date
"June 3, 1995" "Date of last update")
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to
25 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30 ;; Never read that diff output again!
31 ;; Apply patch selectively, like a pro!
34 ;; This package provides a convenient way of simultaneous browsing through
35 ;; the differences between a pair (or a triple) of files or buffers. The
36 ;; files being compared, file-A, file-B, and file-C (if applicable) are
37 ;; shown in separate windows (side by side, one above the another, or in
38 ;; separate frames), and the differences are highlighted as you step
39 ;; through them. You can also copy difference regions from one buffer to
40 ;; another (and recover old differences if you change your mind).
42 ;; In addition, Ediff can apply a patch to a file and then let you step
43 ;; though both files, the patched and the original one, simultaneously,
44 ;; difference-by-difference. You can even apply a patch right out of a
45 ;; mail buffer, i.e., patches received by mail don't even have to be saved.
46 ;; Since Ediff lets you copy differences between buffers, you can, in
47 ;; effect, apply patches selectively (i.e., you can copy a difference
48 ;; region from file_orig to file, thereby undoing any particular patch that
51 ;; Ediff is aware of version control, which lets the user compare
52 ;; files with their older versions. Ediff can also work with remote and
53 ;; compressed files. Details are given below.
55 ;; This package builds upon the ideas borrowed from emerge.el and
56 ;; several Ediff's functions are adaptations from emerge.el.
57 ;; Much of the functionality of Ediff is also influenced by emerge.el.
59 ;; The present version of Ediff supersedes Emerge. It provides a superior
60 ;; user interface and has many features not found in Emerge. In particular,
61 ;; it can do patching and 2-way and 3-way file comparison in addition to
69 ;; When you byte-compile Ediff, you will get some warnings about functions
70 ;; being undefined. These can be safely ignored.
75 ;; 1. The undo command doesn't restore deleted regions well. That is, if
76 ;; you delete all characters in a difference region and then invoke
77 ;; `undo', the reinstated text will most likely be inserted outside of
78 ;; what Ediff thinks is the current difference region. (This problem
79 ;; doesn't seem to exist with XEmacs.)
81 ;; If at any point you feel that difference regions are no longer correct,
82 ;; you can hit '!' to recompute the differences.
84 ;; 2. On a monochrome display, the repertoire of faces with which to
85 ;; highlight fine differences is limited. By default, Ediff is using
86 ;; underlining. However, if the region is already underlied by some other
87 ;; overlays, there is no simple way to temporarily remove that residual
88 ;; underlining. This problem occurs when a buffer is highlighted with
89 ;; hilit19.el or font-lock.el packages. If this residual highlighting gets
90 ;; in the way, you can do the following. Both font-lock.el and hilit19.el
91 ;; provide commands for unhighlighting buffers. You can either place these
92 ;; commands in `ediff-prepare-buffer-hooks' (which will unhighlight every
93 ;; buffer used by Ediff) or you can execute them interactively, at any time
102 ;; Fixed a bug in ediff-setup-windows that caused control window to
103 ;; appear in a wrong place when split-window-keep-point is nil
104 ;; (Thanks to Kevin Broadey <KevinB@bartley.demon.co.uk>.)
106 ;; Added mechanism for using faces instead of before/after flags. This
107 ;; looks much better on an X display, especially on a color one.
108 ;; (Thanks to Boris Goldowsky <boris@cs.rochester.edu> for the code
109 ;; that led to ediff-highlight-diff.
110 ;; Also, thanks to Kevin Esler <esler@ch.hp.com> for suggestions
111 ;; regarding highlighting differences on X displays.)
113 ;; Added functions to apply patches.
114 ;; (Thanks to Kevin Broadey <KevinB@bartley.demon.co.uk> for this
119 ;; Added mechanism for toggling vertical/horizontal window split.
120 ;; (Inspired by a suggestion from Allan Gottlieb
121 ;; <gottlieb@allan.ultra.nyu.edu> -- thanks.)
123 ;; Added mechanism for toggling between highlighting using faces and
124 ;; highlighting using ASCII flags.
126 ;; Fixed a problem with undo. Now, Ediff has smartened up and doesn't
127 ;; keep undo info on ASCII flags inserted in buffer-A and buffer-B.
128 ;; So, if you edit the files while browsing through them, undo behaves
129 ;; as you would expect, i.e., faces/flags don't get in the way.
133 ;; Added horizontal scrolling. Added ediff-position-region to ensure
134 ;; that difference regions in buffer-A and buffer-B are aligned with
135 ;; each other. Disabled ediff-toggle-split when buffers are displayed
136 ;; in different frames.
138 ;; Added toggle-window help (Suggested by Boris Goldowsky
139 ;; <boris@cs.rochester.edu>.)
140 ;; Added functions to copy differences from one buffer to another and to
141 ;; recover old differences.
142 ;; Added prefix arguments to ediff-next-difference and
143 ;; ediff-previous-difference.
147 ;; Replaced text properties with overlays. Fixed ediff-setup-windows.
148 ;; Added ediff-save-buffer to local-write-file-hooks to prevent user
149 ;; from saving corrupted states. (Thanks to <boris@cs.rochester.edu>
150 ;; for suggestion.) Instead, Ediff now has a pair of functions for
151 ;; safe saving of buffers.
152 ;; Changed ediff-read-file-name to be more intuitive on ediff-files.
153 ;; Added ediff-prepare-buffer-hooks. (Thanks to Kevin Esler
154 ;; <esler@ch.hp.com> for the idea.)
156 ;; Cleanups in ediff-patch-file. Protected ediff-copy-diff against
157 ;; a bug that Emacs has in kill-region.
159 ;; Added support for Lemacs. (Thanks to Alastair Burt
160 ;; <burt@dfki.uni-kl.de> for coercing Ediff into working under Lemacs.)
161 ;; Added ediff-kill-buffer-carefully and other suggestions by Boris
162 ;; Goldowsky <boris@cs.rochester.edu>.
163 ;; Refined the protection against interference with highlighting caused
164 ;; by Hilit19. Added the variable ediff-third-party-highlighting.
165 ;; Added mechanisn for unhighlighting regions highlighted with Hilit19
166 ;; before hightlighting them with Ediff's overlays. (And for
167 ;; rehighlighting them with Hilit19, when the current difference moves on.)
171 ;; Added ediff-place-flags-in-buffer and ediff-remote-exit, which are
172 ;; modifications of Emerge's similar functions. The difference is that
173 ;; in Ediff they make ediff-before-flag and ediff-after-flag into
174 ;; read-only regions, so the user can't change them by mistake.
176 ;; Adopted a suggestion by Boris Goldowsky <boris@cs.rochester.edu>
177 ;; that led to a more elegant treatment of faces.
179 ;; Added protection against interference with Font-Lock highlighting
180 ;; similar to that of Hilit19's protection.
184 ;; Deleted spurious (auto-save-mode 1) in ediff-control-buffer, which
185 ;; was causing this buffer to be auto-saved for no good reason.
186 ;; Added read-only protection to ediff-before/after-flags in Lemacs.
187 ;; (Thanks to Alastair Burt <burt@dfki.uni-kl.de> for help in testing.)
189 ;; Further fixes in the XEmacs part. Changed highlighted region in
190 ;; ediff-highlight-diff so that an extra character will be highlighted
191 ;; only if a difference is empty (thereby allowing the user to see where an
192 ;; insertion or a deletion has taken place).
194 ;; Simplified interaction with other highlighting packages by giving
195 ;; Ediff overlays the highest priority. (Taking a cue from
196 ;; ediff-highlight-diff-lemacs written by Alastair Burt
197 ;; <burt@dfki.uni-kl.de>.) Zapped ediff-third-party-highlighting
198 ;; variable and hooks that were previously used to
199 ;; unhighlight/rehighlight buffers when hilit19/font-lock are on.
203 ;; Added a bit more sophistication to ediff-read-file-name. Now,
204 ;; ediff-files remembers both, the file-A and the file-B directories.
205 ;; They are offered as defaults when ediff-use-last-dir is set to t.
209 ;; Added ediff-before-change-guard to remove ASCII highlighting when
210 ;; the user attempts to change buffer-A/B. This is needed because
211 ;; otherwise the undo info may become screwed up in those buffers.
212 ;; Hitting `h' (ediff-toggle-hilit) on a dumb terminal will toggle
213 ;; between ASCII highlighting and no highlighting.
217 ;; Fixed problems with multiple Ediff sessions running simultaneously.
221 ;; Added vc-ediff, the Ediff interface to vc.el. (Thanks to Eric
222 ;; Freudenthal <freudent@jan.ultra.nyu.edu> for contributing this
227 ;; Added rcs-ediff, an Ediff interface to RCS via rcs.el. (Thanks to
228 ;; Alastair Burt <burt@dfki.uni-kl.de>.)
229 ;; Some minor improvements.
231 ;; Tue March 15, 1994
233 ;; Fixed a buglet in defining ediff-current-diff-face-A/B.
234 ;; (Thanks to Job Ganzevoort <Job.Ganzevoort@cwi.nl>.)
236 ;; Tue March 22, 1994
238 ;; Fixed a bug with ediffing narrowed buffers, reported by Kevin
239 ;; Broadey <KevinB@bartley.demon.co.uk>.
240 ;; Made Ediff to work with files that have incomplete last line.
241 ;; Made Ediff execute diff and patch using Bourne Shell, which
242 ;; should eliminate problems with $prompt that some people had.
244 ;; Thu March 24, 1994
246 ;; Achieved quadratic speedup in the size of the file by replacing the
247 ;; slow goto-line by forward-line.
248 ;; Converted demarkation of difference regions
249 ;; from markers to overlays. This will later allow us to highlight all
250 ;; diffs, not just the current one.
252 ;; Wed March 30, 1994
254 ;; Under X, Ediff now highlights all differences in dim colors and the
255 ;; current difference in bright colors. Improved XEmacs support.
256 ;; Changed toggle hilit to cycle through 3 states: highlighting all
257 ;; diffs, highlighting only the current diff, and highlighting using
259 ;; Added support for difference regions that are not full lines.
263 ;; Fixed bugs related to writing buffers A and B.
264 ;; Added commands `ga', `gb' to jump directly to the closest diff in
265 ;; buffer A and B, respectively.
267 ;; Fri April 11, 1994
269 ;; Added `ediff-update-diffs', a function that lets the user recompute
270 ;; difference regions after extensive editing done to buffers A and B
273 ;; Wed April 13, 1994
275 ;; Added the new feature: refining the current difference region.
276 ;; This would highlight the precise differences between the regions in
277 ;; buffer A and B. (A way to implement this was suggested by Boris
278 ;; Goldowsky <boris@cs.rochester.edu>.)
280 ;; Fixed Ediff to be immune to several different versions of rcs.el
281 ;; that are currently in distribution.
283 ;; Thu April 14, 1994
285 ;; Ediff now respects X resources for the faces it uses. It no longer
286 ;; barks when the colormap has no colors it is using; or when face
287 ;; fonts can't be italicized, etc.
289 ;; Fri April 15, 1994
291 ;; Changed `ediff-setup-windows' to minimize the need to delete and
292 ;; create windows. Now jumps faster from diff to diff.
293 ;; Added Ediff to the File menu on the menu bar (FSF's version).
295 ;; Mon April 18, 1994
297 ;; Fixed to work with OS/2's PM-Emacs.
299 ;; Thu April 21, 1994
301 ;; Lemacs' menus added (thanks to Alastair Burt for the help).
303 ;; Wed April 28, 1994
305 ;; Fixed ediff-keep-window-config (thanks to Norbert Kiesel
306 ;; <norbert@i3.informatik.rwth-aachen.de>), ediff-shell and
307 ;; ediff-protect-metachars (thanks to Richard Stanton
308 ;; <stanton@haas.berkeley.edu>). Made access to difference
309 ;; overlays structure-independent, making it less bug-prone.
310 ;; Patched ediff-read-file-name to work more intuitively with directory
311 ;; names (thanks to Kevin Broadey <KevinB@bartley.demon.co.uk>).
315 ;; Added `ediff-frame-has-menubar' to guard against the possibility that
316 ;; the current frame has no menu bar.
320 ;; Fixed buglet in vc-ediff (thanks to Ray Nickson <nickson@cs.uq.oz.au>).
324 ;; Modified ediff-read-file-name to not put long file names in the
325 ;; default prompt area, as suggested by KevinB@bartley.demon.co.uk.
326 ;; Applied patch supplied by burt@dfki.uni-kl.de, fixing a problem with
327 ;; ediff-diff-to-diff in Lemacs.
331 ;; Added ediff-forward-word-function (as suggested by Job Ganzevoort
332 ;; <Job.Ganzevoort@cwi.nl>).
336 ;; Added `ediff-toggle-regexp-match', which allows the user to step
337 ;; through only those difference regions that match some regexp; or,
338 ;; vice versa, to skip over regions that match a regexp. (This feature
339 ;; was suggested by Andy Scott <ascott@pcocd2.intel.com>.)
340 ;; Added ediff-eval-in-buffer, which is a modified emerge-eval-in-buffer.
341 ;; The function ediff-status-info, bound to `i', now replaces and extends
342 ;; ediff-file-names and ediff-line-numbers, which were bound to `f'
343 ;; and `i', respectively.
348 ;; Improved `ediff-read-file-name' and `ediff-buffers' so they are now
349 ;; providing more intuitive defaults. Modified `ediff-read-file-name'
350 ;; so it won't cause problems under OS/2.
354 ;; Modified ediff-find-file, ediff-files-internal, and made
355 ;; emerge-verify-file-buffer into ediff-verify-file-buffer so that
356 ;; Ediff will work correctly with remote and compressed
357 ;; files. (Suggested by Sandy Rutherford <sandy@ibm550.sissa.it>.)
361 ;; Fixed ediff-patch-files to work with remote and compressed files.
365 ;; Changed menu bar items per RMS's suggestion. Changed odd/even faces
366 ;; in Lemacs to italic. Changed ediff-*-face-* variables so that they
367 ;; will contain names of faces instead of the face internal
368 ;; representation. (Copy-face works better with face names than with
369 ;; face internal representation. With face internal representation, if
370 ;; a face vector mentions a font explicitly, copy-face may attempt to
371 ;; copy this font, which would cause an error if the font has a wrong
372 ;; size for one of the existing frames.) Improved the way
373 ;; mode-line-buffer-identification is set in ediff-setup so that Ediff
374 ;; will accommodate the way buffers are identified in mode-line.el and
377 ;; Fri August 5, 1994
379 ;; Ediff can now automatically skip over regions that differ only in
380 ;; the white space and line breaks. This is controled with the variable
381 ;; `ediff-ignore-similar-regions' and can be toggled on/off by typing
384 ;; Mon August 8, 1994
386 ;; If ediff-save-buffer is invoked with `wd', it'll save the diff
389 ;; Wed August 24, 1994
391 ;; Fixed ediff-toggle-read-only and ediff-patch-file so that they will
392 ;; check out version-controled files before modifying them. This will
393 ;; permit checking the modified versions back in. In earlier
394 ;; versions, such modifications could be lost, unless the user takes
395 ;; special care of preserving them.
397 ;; Tue August 30, 1994
399 ;; Added ediff-submit-report.
400 ;; Introduced ediff-revision as a uniform way of calling vc.el and
401 ;; rcs.el. This is controled by ediff-version-control-package
402 ;; variable. Functions vc-ediff, rcs-ediff are replaced by their
403 ;; internal versions.
405 ;; Thu September 1, 1994
407 ;; Made ediff-overlay-put and ediff-move-overlay into bona fide
408 ;; functions (rather than fset symbols). These now check if overlay's
409 ;; buffer is alive. If not, overlay is deleted. This overcomes some of
410 ;; the problems with Lemacs.
412 ;; Thu September 8, 1994
414 ;; Added ediff-revision-key, ediff-load-version-control and streamlined
415 ;; vc/rcs-ediff[-internal]. Eliminated dependency on emerge.el.
417 ;; Fri September 23, 1994
419 ;; Added ediff-windows and ediff-regions.
420 ;; Changed ediff-setup-windows and related procedures to create
421 ;; a separate dedicated control frame for each invocation of Ediff.
423 ;; Tue September 27, 1994
425 ;; Added redraw-display everywhere before creating or deleting
426 ;; frames. It appears that this cures Emacs' bug where it trashes some
427 ;; fonts which leads to crashes. Also, some code cleanups and bug fixes.
429 ;; Fri September 30, 1994
431 ;; Fixed ediff-update-diffs so it'll work correctly with
432 ;; ediff-windows and ediff-regions. Added narrowing and widening to the
433 ;; suite of commands available for ediff-windows and ediff-regions.
435 ;; Fri October 7, 1994
437 ;; Changed ediff-setup-windows to funcall the actual window setting
438 ;; function, which is either ediff-setup-windows-multiframe or
439 ;; ediff-setup-windows-plain. Changed all temp file names to use `_'
440 ;; instead of `.'. Presumably, this makes VMS happier.
441 ;; Ported to VMS (thanks to Richard Levitte <levitte@e.kth.se>).
442 ;; Added ediff-prefer-long-help-message and changed defaults.
443 ;; Fighting with XEmacs bugs. Made it possible to switch between plain
444 ;; and multiframe display easier, but XEmacs is still getting confused
445 ;; at times. Added ediff-check-version and ediff-set-help-message.
446 ;; Made more sensible temp file names, which is important when
447 ;; generating context diffs. Added ediff-make-frame-position and
448 ;; ediff-control-frame-position-function.
450 ;; Wed October 12, 1994
452 ;; ediff-window-visible-p now makes a call to frame-visible-p
453 ;; only when window-system is non-nil. Rearranged the block of fset's
454 ;; so that the wrong things won't be defined when window-system is nil.
455 ;; Added ediff-revert-buffers-then-recompute-diffs function.
456 ;; Removed flag-argument from a background call to shell-command.
457 ;; Added ediff-shell-command to enable custom diff execute in the
458 ;; background and insert output in ediff-custom-diff-buffer.
459 ;; Added ediff-shell-command-filter, because XEmacs doesn't have it.
460 ;; Made ediff-revision set up ediff-job-name to `ediff-revision'.
461 ;; This enables users do ediff-revision-specific actions on exiting
462 ;; Ediff using ediff-quit-hooks.
463 ;; Reshaffled some fset's so that functions for checking color and
464 ;; faces won't be touched on a non-windowing display.
466 ;; Thu October 20, 1994
468 ;; Modified ediff-make-fine-diffs so that no fine diffs are computed if
469 ;; one of the diff regions is empty. Saves time and also works around
470 ;; the buggy diff program in AIX.
471 ;; ediff no longer loads the version control package
472 ;; automatically---only when ediff-revision is called.
473 ;; Enabled focusing/hiding diff regions that match both or just one of the
475 ;; Changed ediff-regions to ediff-small-regions. Added ediff-large-regions.
476 ;; Modified ediff-next/previous-difference to work right when both
477 ;; skipping regexp matches and skipping similar regions is enabled.
478 ;; Fixed bugs in positioning the control frame.
480 ;; Fri October 28, 1994
482 ;; Fixed bugs in ediff-next/previous-difference, ediff-set-visible-region
483 ;; Changed/added ediff-word-[1-4].
485 ;; Tue November 1, 1994
487 ;; Made ediff-revision delete the temporary version files it creates.
489 ;; Tue November 29, 1994
491 ;; Added ediff-swap-buffers. Split ediff-difference-vector into
492 ;; ediff-difference-vector-A and ediff-difference-vector-B, which
493 ;; allowed to factor out a lot of stuff.
494 ;; Made the code buffer-C ready.
496 ;; Thu December 1, 1994
498 ;; Lotsa bug fixes. Further rationalized the code.
499 ;; Added ediff-display-help-hooks, ediff-mode-hooks.
500 ;; Replaced almost identical ediff-scroll-up/down with
501 ;; ediff-scroll-vertically.
502 ;; Replaced almost identical ediff-scroll-left/right with
503 ;; ediff-scroll-horizontally.
504 ;; Made the code buffer-C ready.
506 ;; Thu December 8, 1994
508 ;; Added ediff-toggle-wide-display. In plain display, help message is
509 ;; now centered correctly.
511 ;; Fri December 9, 1994
513 ;; Added ediff-toggle-multiframe.
514 ;; Fixed ediff-pop-diff and ediff-copy-diff, so that they will
515 ;; invoke auto-refining, if necessary.
517 ;; Mon December 12, 1994
519 ;; Modified ediff-toggle-wide-display so it would funcall
520 ;; ediff-make-wide-display-function.
522 ;; Tue December 13, 1994
524 ;; Ediff now chooses its surrogate minibuffer from frame A.
526 ;; Mon December 20, 1994
528 ;; Added ediff-keymap-setup-hooks.
530 ;; Fri December 23, 1994
532 ;; Changed the representation in ediff-killed-diffs-alist so that
533 ;; ediff-save-diff-region and ediff-pop-diff won't be confused when the
534 ;; user swaps buffers.
536 ;; Mon December 26, 1994
538 ;; Placated OS/2 by making Ediff to synchronize the call to startup
539 ;; hooks with the acynchronous process that computes custom diffs.
540 ;; This has no effect on Unix installations (and VMS?), but
541 ;; may increase Ediff's startup time under OS/2 by 1 or 2 seconds.
543 ;; Thu December 29, 1994
545 ;; ediff-recenter now deactivates the mark, so that transient mark mode
546 ;; highlighting won't interfere with Ediff's highlighting.
547 ;; Also, ediff-recenter tries to not deiconify control frame, if it is
550 ;; Fri December 30, 1994
552 ;; Small bugs. Worked around the OS/2 bug where
553 ;; modify-frame-parameters has no effect on iconified frames. Ediff
554 ;; now remembers the iconification status of the control frame and uses
555 ;; it as a preferred way of displaying it when help is toggled
556 ;; off. (This can be observed only in Emacs (not XEmacs) and only if
557 ;; the window manager lets icons accept keyboard input.)
559 ;; Tue January 3, 1995
561 ;; Some futher work on incorporating buffer C in ediff-extract-diffs,
562 ;; ediff-focus/hide-on-regexp-matches, and
563 ;; ediff-setup-windows-plain/multiframe. The preceding two functions
564 ;; now dispatch the appropriate setup function depending on whether the
565 ;; current job is comparison or merge.
567 ;; Wed January 4, 1995
569 ;; Made it work under Emacs built without the X support.
571 ;; Fri January 6, 1995
573 ;; Slightly changed the prompting behavior of ediff-files. Bug fix in
574 ;; mode-line-buffer-identification.
576 ;; Wed January 18, 1995
578 ;; Added 3way comparison and support for diff3. Ported to NeXTStep
580 ;; Fri January 20, 1995
582 ;; Added ediff-merge-files, ediff-merge-buffers,
583 ;; ediff-merge-files-with-ancestor, ediff-merge-buffers-with-ancestor,
584 ;; ediff-merge-revisions, ediff-merge-revisions-with-ancestor.
586 ;; Tue January 24, 1995
588 ;; Bug fixes. Split into several files.
590 ;; Thu January 26, 1995
592 ;; `*' is now bound to ediff-make-or-kill-fine-diffs. This lets the
593 ;; user to kill fine diffs for the current region (by providing a
594 ;; negative prefix arg), if there are so many of them as to hamper
597 ;; Mon January 30, 1995
599 ;; Changed ediff-selective-display to ediff-set-visible-region,
600 ;; ediff-toggle-selective-display to ediff-toggle-narrow-region.
601 ;; Ediff now turns selective display off before starting. Restores
602 ;; selective display on exit.
603 ;; In 2-way comparison, `a' now copies to buf `b' and `b' to buf `a'.
604 ;; Previously, the bindings were `ab' and `ba'.
606 ;; Wed February 1, 1995
608 ;; Added ediff-undo-selective-display (thanks to Stig <stig@inse.com>).
609 ;; Rearranged autoloads. Renamed ediff-entry.el into ediff.el and
610 ;; ediff.el into ediff-util.el.
614 ;; Added ediff-toggle-show-clashes-only, which is bound to `$'.
618 ;; Some minor patches from Stig. Also, made ediff-xemacs-p and
619 ;; ediff-*-job into variables for better performance.
620 ;; In ediff-setup, diff regions are now computed after buffers A/B/C
621 ;; are set up. Previously, it didn't work right with selective display.
622 ;; Also, added ediff-profile to time Ediff commands and
623 ;; ediff-debug-info for civilized display of the difference vectors
624 ;; (and possibly more in the future).
628 ;; Fixed ediff-diff-at-point and ediff-toggle-multiframe.
629 ;; Added ediff-destroy-control-frame, ediff-window-display-p. The latter
630 ;; replaces window-system in many cases. Needed because in XEmacs 19.12
631 ;; window-system returns 'tty on a tty display.
632 ;; Converted xemacs *screen* nomenclature to *frame*.
633 ;; Made ediff-patch-buffer cope with buffers that don't visit any file.
634 ;; Fixed ediff-toggle-read-only so it knows the difference between
635 ;; version-controlled files and others. It also knows whether we are using
637 ;; Renamed ediff-windows to ediff-windows-wordwise, added
638 ;; ediff-windows-linewise. Changed ediff-small/large-regions to
639 ;; ediff-regions-wordwise/linewise
643 ;; Added ediff-documentation. Fixes for XEmacs 19.12.
644 ;; Merge buffer now assumes the major mode of ediff-default-variant.
648 ;; Ediff-revision now takes a prefix argument. Can compare two versions of
649 ;; the same file. Cleaned up ediff-make-control-frame.
650 ;; Fixed a bug in ediff-get-visible-buffer-window.
651 ;; Added ediff-cleanup-hooks, ediff-janitor.
652 ;; ediff-cleanup-hooks is called before ediff-quit-hooks.
658 ;; 1. Add support for multiple sessions. (At present, one can run
659 ;; multiple Ediff sessions, but they won't be related.) The idea is to
660 ;; have vars local to each control buffer, which will tell which buffer is
661 ;; the next and which is the previous one. The user could then go forward
662 ;; and backward by typing C-SPC and C-DEL (or C-n and C-p).
663 ;; This will probably entail some minor modifications to ediff-setup.
664 ;; The primary use of this feature would be comparing directories of
665 ;; similarly named files and multi-file patch. For the latter, Ediff will
666 ;; have to parse patches to extract the names of files.
669 ;;; Acknowledgements:
671 ;; Special thanks to Alastair Burt <burt@dfki.uni-kl.de>, Kevin Broadey
672 ;; <KevinB@bartley.demon.co.uk>, Harald Boegeholz
673 ;; <hwb@machnix.mathematik.uni-stuttgart.de>, Jin S. Choi" <jin@atype.com>,
674 ;; Eric Eide <eeide@asylum.cs.utah.edu>, Kevin Esler <esler@ch.hp.com>, Robert
675 ;; Estes <estes@ece.ucdavis.edu>, Eric Freudenthal
676 ;; <freudent@jan.ultra.nyu.edu>,
677 ;; Job Ganzevoort <Job.Ganzevoort@cwi.nl>, Boris Goldowsky
678 ;; <boris@cs.rochester.edu>, Allan Gottlieb <gottlieb@allan.ultra.nyu.edu>,
679 ;; Xiaoli Huang <hxl@epic.com>, Larry Gouge <larry@itginc.com>,
680 ;; Karl Heuer <kwzh@gnu.ai.mit.edu>, <irvine@lks.csi.com>,
681 ;; <jaffe@chipmunk.cita.utoronto.ca>, David Karr
682 ;; <dkarr@nmo.gtegsc.com>, Norbert Kiesel
683 ;; <norbert@i3.informatik.rwth-aachen.de>, Fritz Knabe <Fritz.Knabe@ecrc.de>,
684 ;; Heinz Knutzen <hk@informatik.uni-kiel.d400.de>, Ken Laprade
685 ;; <laprade@dw3f.ess.harris.com>, Richard Levitte
686 ;; <levitte@e.kth.se>, Martin Maechler <maechler@stat.math.ethz.ch>,
687 ;; Richard Mlynarik <mly@adoc.xerox.com>, Chris Murphy
688 ;; <murphycm@sun.aston.ac.uk>, Eyvind Ness <Eyvind.Ness@hrp.no>, Ray Nickson
689 ;; <nickson@cs.uq.oz.au>, Paul Raines <raines@slac.stanford.edu>, Tibor
690 ;; Polgar <tlp00@spg.amdahl.com>, C.S. Roberson <roberson@aur.alcatel.com>,
691 ;; Kevin Rodgers <kevin.rodgers@ihs.com>, Sandy Rutherford
692 ;; <sandy@ibm550.sissa.it>, Heribert Schuetz <schuetz@ecrc.de>, Andy Scott
693 ;; <ascott@pcocd2.intel.com>, Axel Seibert
694 ;; <axel@tumbolia.ppp.informatik.uni-muenchen.de>, Richard Stallman
695 ;; <rms@gnu.ai.mit.edu>, Richard Stanton <stanton@haas.berkeley.edu>,
696 ;; Ake Stenhoff <etxaksf@aom.ericsson.se>,
697 ;; Stig <stig@hackvan.com>, Peter Stout <Peter_Stout@cs.cmu.edu>,
698 ;; Raymond Toy <toy@rtp.ericsson.se>,
699 ;; and Ilya Zakharevich <ilya@math.ohio-state.edu>
700 ;; for contributing ideas, patches, and bug reports.
702 ;; Thanks also to many others who felt obliged to drop a thank you note.
707 (require 'ediff-init
)
709 (defvar ediff-version-control-package
'vc
710 "Version control package used.
711 Currently, Ediff supports vc.el and rcs.el. Set this to `rcs' if you have
712 rcs.el and want to use it instead of the standard vc.el.
714 Note: both packages provide access to RCS, but only vc.el comes with Emacs
717 (defvar ediff-revision-key nil
718 "Key to which `ediff-revision' is to be bound.")
720 (defvar ediff-use-last-dir nil
721 "*If t, Ediff uses previous directory as default when reading file name.")
723 (defvar ediff-last-dir-A nil
724 "Last directory used by an Ediff command for file-A.")
725 (defvar ediff-last-dir-B nil
726 "Last directory used by an Ediff command for file-B.")
727 (defvar ediff-last-dir-C nil
728 "Last directory used by an Ediff command for file-C.")
729 (defvar ediff-last-dir-ancestor nil
730 "Last directory used by an Ediff command for the ancestor file.")
731 (defvar ediff-last-dir-patch nil
732 "Last directory used by an Ediff command for file to patch.")
737 (defun ediff-patch-file (source-filename &optional startup-hooks job-name
)
738 "Run Ediff by patching FILE-TP-PATCH."
739 ;; This now returns the control buffer
741 (list (ediff-read-file-name "File to patch"
742 (if ediff-use-last-dir
747 (setq source-filename
(expand-file-name source-filename
))
748 (ediff-get-patch-buffer
749 (if (eq job-name
'ediff-patch-buffer
)
750 (ediff-eval-in-buffer (get-file-buffer source-filename
)
752 (file-name-directory source-filename
)))
754 (let* ((backup-extension
755 ;; if the user specified a -b option, extract the backup
756 ;; extension from there; else use `_orig'
757 (substring ediff-patch-options
758 (if (string-match "-b[ \t]+" ediff-patch-options
)
760 (if (string-match "-b[ \t]+[^ \t]+" ediff-patch-options
)
762 (shell-file-name ediff-shell
)
763 ;; ediff-find-file may use a temp file to do the patch
764 ;; so, we save source-filename and true-source-filename as a var
765 ;; that initially is source-filename but may be changed to a temp
766 ;; file for the purpose of patching.
767 (true-source-filename source-filename
)
768 (target-filename source-filename
)
769 target-buf buf-to-patch file-name-magic-p ctl-buf
)
771 ;; if the user didn't specify a backup extension, use _orig
772 (if (string= backup-extension
"")
773 (setq backup-extension
"_orig"))
775 ;; Make a temp file, if source-filename has a magic file handler (or if
776 ;; it is handled via auto-mode-alist and similar magic).
777 ;; Check if there is a buffer visiting source-filename and if they are in
778 ;; synch; arrange for the deletion of temp file.
779 (ediff-find-file 'true-source-filename
'buf-to-patch
780 'ediff-last-dir-patch
'startup-hooks
)
782 ;; Check if source file name has triggered black magic, such as file name
783 ;; handlers or auto mode alist, and make a note of it.
784 ;; true-source-filename should be either the original name or a
785 ;; temporary file where we put the after-product of the file handler.
786 (setq file-name-magic-p
(not (equal (file-truename true-source-filename
)
787 (file-truename source-filename
))))
789 ;; Checkout orig file, if necessary, so that the patched file could be
791 (if (ediff-file-checked-in-p (buffer-file-name buf-to-patch
))
792 (ediff-toggle-read-only buf-to-patch
))
794 (ediff-eval-in-buffer ediff-patch-diagnostics
795 (message "Applying patch ... ")(sit-for 0)
796 ;; always pass patch the -f option, so it won't ask any questions
797 (shell-command-on-region
798 (point-min) (point-max)
799 (format "%s -f %s -b %s %s"
800 ediff-patch-program ediff-patch-options
802 (expand-file-name true-source-filename
))
804 (message "Applying patch ... done")(sit-for 0)
805 (switch-to-buffer ediff-patch-diagnostics
)
806 (sit-for 0) ; synchronize
808 (or (file-exists-p (concat true-source-filename backup-extension
))
809 (error "Patch failed or didn't modify the original file"))
811 ;; If black magic is involved, apply patch to a temp copy of the
812 ;; file. Otherwise, apply patch to the orig copy. If patch is applied
813 ;; to temp copy, we name the result old-name_patched for local files
814 ;; and temp-copy_patched for remote files. The orig file name isn't
815 ;; changed, and the temp copy of the original is later deleted.
816 ;; Without magic, the original file is renamed (usually into
817 ;; old-name_orig) and the result of patching will have the same name as
819 (if (not file-name-magic-p
)
820 (ediff-eval-in-buffer buf-to-patch
821 (set-visited-file-name (concat source-filename backup-extension
))
822 (set-buffer-modified-p nil
))
824 ;; Black magic in effect.
825 ;; If orig file was remote, put the patched file in the temp directory.
826 ;; If orig file is local, put the patched file in the directory of
828 (setq target-filename
830 (if (ediff-file-remote-p (file-truename source-filename
))
835 (rename-file true-source-filename target-filename t
)
837 ;; arrange that the temp copy of orig will be deleted
838 (rename-file (concat true-source-filename backup-extension
)
839 true-source-filename t
))
841 ;; make orig buffer read-only
843 (cons 'ediff-set-read-only-in-buf-A startup-hooks
))
845 ;; set up a buf for the patched file
846 (setq target-buf
(find-file-noselect target-filename
))
849 (ediff-buffers-internal
850 buf-to-patch target-buf nil
851 startup-hooks
'(or job-name ediff-patch-file
)))
853 (bury-buffer ediff-patch-diagnostics
)
854 (message "Patch diagnostics are available in buffer %s"
855 (buffer-name ediff-patch-diagnostics
))
858 (defun ediff-set-read-only-in-buf-A ()
859 "Used as a startup hook to set `_orig' patch file read-only."
860 (ediff-eval-in-buffer ediff-buffer-A
861 (toggle-read-only 1)))
864 (defalias 'epatch
'ediff-patch-file
)
866 (defalias 'epatch-buffer
'ediff-patch-buffer
)
868 ;;; Compare files/buffers
871 (defun ediff-files (file-A file-B
&optional startup-hooks
)
872 "Run Ediff on a pair of files, FILE-A and FILE-B."
874 (let ((dir-A (if ediff-use-last-dir
878 (list (setq f
(ediff-read-file-name "File A to compare" dir-A nil
))
879 (ediff-read-file-name "File B to compare"
881 (if ediff-use-last-dir
883 (file-name-directory f
)))
885 (setq file-name-history
886 (cons (abbreviate-file-name
888 (file-name-nondirectory f
)
893 (ediff-files-internal file-A
894 (if (file-directory-p file-B
)
896 (file-name-nondirectory file-A
) file-B
)
903 (defun ediff-files3 (file-A file-B file-C
&optional startup-hooks
)
904 "Run Ediff on three files, FILE-A, FILE-B, and FILE-C."
906 (let ((dir-A (if ediff-use-last-dir
910 (list (setq f
(ediff-read-file-name "File A to compare" dir-A nil
))
911 (setq ff
(ediff-read-file-name "File B to compare"
913 (if ediff-use-last-dir
915 (file-name-directory f
)))
917 (setq file-name-history
919 (abbreviate-file-name
921 (file-name-nondirectory f
)
925 (ediff-read-file-name "File C to compare"
926 (setq dir-C
(if ediff-use-last-dir
928 (file-name-directory ff
)))
930 (setq file-name-history
931 (cons (abbreviate-file-name
933 (file-name-nondirectory ff
)
938 (ediff-files-internal file-A
939 (if (file-directory-p file-B
)
941 (file-name-nondirectory file-A
) file-B
)
943 (if (file-directory-p file-C
)
945 (file-name-nondirectory file-A
) file-C
)
951 (defalias 'ediff3
'ediff-files3
)
954 (defun ediff-find-file (file-var buffer-name
&optional last-dir hooks-var
)
955 "Visit FILE and arrange its buffer to Ediff's liking.
956 FILE is actually a variable symbol that must contain a true file name.
957 BUFFER-NAME is a variable symbol, which will get the buffer object into which
958 FILE is read. LAST-DIR is the directory variable symbol where FILE's
959 directory name should be returned. HOOKS is a variable symbol that will be
960 assigned the hook to be executed after `ediff-startup' is finished.
961 `ediff-find-file' arranges that the temp files it might create will be
963 (let* ((file (symbol-value file-var
))
964 (file-magic (find-file-name-handler file
'find-file-noselect
))
965 (temp-file-name-prefix (file-name-nondirectory file
)))
966 (if (not (file-readable-p file
))
967 (error "File `%s' does not exist or is not readable" file
))
969 ;; some of the command, below, require full file name
970 (setq file
(expand-file-name file
))
972 ;; Record the directory of the file
974 (set last-dir
(expand-file-name (file-name-directory file
))))
977 (set buffer-name
(find-file-noselect file
))
979 (ediff-eval-in-buffer (symbol-value buffer-name
)
980 (widen) ; Make sure the entire file is seen
981 (cond (file-magic ;; file has handler, such as jka-compr-handler or
982 ;; ange-ftp-hook-function--arrange for temp file
983 (ediff-verify-file-buffer 'magic
)
984 (setq file
(ediff-make-temp-file temp-file-name-prefix
))
985 (set hooks-var
(cons (` (lambda () (delete-file (, file
))))
986 (symbol-value hooks-var
))))
987 ;; file processed via auto-mode-alist, a la uncompress.el
988 ((not (equal (file-truename file
)
989 (file-truename (buffer-file-name))))
990 (setq file
(ediff-make-temp-file temp-file-name-prefix
))
991 (set hooks-var
(cons (` (lambda () (delete-file (, file
))))
992 (symbol-value hooks-var
))))
993 (t ;; plain file---just check that the file matches the buffer
994 (ediff-verify-file-buffer))))
995 (set file-var file
)))
997 (defun ediff-files-internal (file-A file-B file-C startup-hooks job-name
)
998 (let (buf-A buf-B buf-C
)
999 (message "Reading file %s ... " file-A
)(sit-for 0)
1000 (ediff-find-file 'file-A
'buf-A
'ediff-last-dir-A
'startup-hooks
)
1001 (message "Reading file %s ... " file-B
)(sit-for 0)
1002 (ediff-find-file 'file-B
'buf-B
'ediff-last-dir-B
'startup-hooks
)
1003 (if (and (stringp file-C
) (not ediff-merge-job
))
1005 (message "Reading file %s ... " file-C
)(sit-for 0)
1008 (if (eq job-name
'ediff-merge-files-with-ancestor
)
1009 'ediff-last-dir-ancestor
'ediff-last-dir-C
)
1011 (ediff-setup buf-A file-A
1015 (list (cons 'ediff-job-name job-name
)))))
1019 (defalias 'ediff
'ediff-files
)
1023 (defun ediff-buffers (buffer-A buffer-B
&optional startup-hooks job-name
)
1024 "Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B."
1027 (list (setq bf
(read-buffer "Buffer A to compare: "
1028 (ediff-other-buffer "") t
))
1029 (read-buffer "Buffer B to compare: "
1031 ;; realign buffers so that two visible bufs will be
1033 (save-window-excursion (other-window 1))
1034 (ediff-other-buffer bf
))
1037 (or job-name
(setq job-name
'ediff-buffers
))
1038 (ediff-buffers-internal buffer-A buffer-B nil startup-hooks job-name
))
1041 (defun ediff-buffers3 (buffer-A buffer-B buffer-C
1042 &optional startup-hooks job-name
)
1043 "Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C."
1046 (list (setq bf
(read-buffer "Buffer A to compare: "
1047 (ediff-other-buffer "") t
))
1048 (setq bff
(read-buffer "Buffer B to compare: "
1050 ;; realign buffers so that two visible
1051 ;; bufs will be at the top
1052 (save-window-excursion (other-window 1))
1053 (ediff-other-buffer bf
))
1055 (read-buffer "Buffer C to compare: "
1057 ;; realign buffers so that three visible
1058 ;; bufs will be at the top
1059 (save-window-excursion (other-window 1))
1060 (ediff-other-buffer (list bf bff
)))
1064 (or job-name
(setq job-name
'ediff-buffers3
))
1065 (ediff-buffers-internal buffer-A buffer-B buffer-C startup-hooks job-name
))
1069 (defun ediff-buffers-internal (buf-A buf-B buf-C startup-hooks job-name
)
1070 (let* ((buf-A-file-name (buffer-file-name (get-buffer buf-A
)))
1071 (buf-B-file-name (buffer-file-name (get-buffer buf-B
)))
1072 (buf-C-is-alive (ediff-buffer-live-p buf-C
))
1073 (buf-C-file-name (if buf-C-is-alive
1074 (buffer-file-name (get-buffer buf-B
))))
1075 file-A file-B file-C
)
1076 (if (not (ediff-buffer-live-p buf-A
))
1077 (error "Buffer %S doesn't exist" buf-A
))
1078 (if (not (ediff-buffer-live-p buf-B
))
1079 (error "Buffer %S doesn't exist" buf-B
))
1080 (let ((ediff-job-name job-name
))
1081 (if (and ediff-3way-comparison-job
1082 (not buf-C-is-alive
))
1083 (error "Buffer %S doesn't exist" buf-C
)))
1084 (if (stringp buf-A-file-name
)
1085 (setq buf-A-file-name
(file-name-nondirectory buf-A-file-name
)))
1086 (if (stringp buf-B-file-name
)
1087 (setq buf-B-file-name
(file-name-nondirectory buf-B-file-name
)))
1088 (if (stringp buf-C-file-name
)
1089 (setq buf-C-file-name
(file-name-nondirectory buf-C-file-name
)))
1091 ;; these three need to be evaluated in their buffers, since
1092 ;; ediff-make-temp-file checks the current buffer when assigning file
1094 (ediff-eval-in-buffer buf-A
1095 (setq file-A
(ediff-make-temp-file buf-A-file-name
)))
1096 (ediff-eval-in-buffer buf-B
1097 (setq file-B
(ediff-make-temp-file buf-B-file-name
)))
1099 (ediff-eval-in-buffer buf-C
1100 (setq file-C
(ediff-make-temp-file buf-C-file-name
))))
1102 (ediff-setup (get-buffer buf-A
) file-A
1103 (get-buffer buf-B
) file-B
1104 (if buf-C-is-alive
(get-buffer buf-C
))
1107 (delete-file (, file-A
))
1108 (delete-file (, file-B
))
1109 (if (stringp (, file-C
)) (delete-file (, file-C
)))
1112 (list (cons 'ediff-job-name job-name
))
1117 ;;; Compare regions and windows
1120 (defun ediff-windows-wordwise (dumb-mode &optional wind-A wind-B startup-hooks
)
1121 "Compare WIND-A and WIND-B, which are selected by clicking, wordwise.
1122 With prefix argument, DUMB-MODE, or on a non-windowing display, works as
1124 If WIND-A is nil, use selected window.
1125 If WIND-B is nil, use window next to WIND-A."
1127 (ediff-windows dumb-mode wind-A wind-B
1128 startup-hooks
'ediff-windows-wordwise
'word-mode
))
1131 (defun ediff-windows-linewise (dumb-mode &optional wind-A wind-B startup-hooks
)
1132 "Compare WIND-A and WIND-B, which are selected by clicking, linewise.
1133 With prefix argument, DUMB-MODE, or on a non-windowing display, works as
1135 If WIND-A is nil, use selected window.
1136 If WIND-B is nil, use window next to WIND-A."
1138 (ediff-windows dumb-mode wind-A wind-B
1139 startup-hooks
'ediff-windows-linewise nil
))
1141 ;; Compare WIND-A and WIND-B, which are selected by clicking.
1142 ;; With prefix argument, DUMB-MODE, or on a non-windowing display,
1143 ;; works as follows:
1144 ;; If WIND-A is nil, use selected window.
1145 ;; If WIND-B is nil, use window next to WIND-A.
1146 (defun ediff-windows (dumb-mode wind-A wind-B startup-hooks job-name word-mode
)
1147 (if (or dumb-mode
(not (ediff-window-display-p)))
1148 (setq wind-A
(ediff-get-next-window wind-A nil
)
1149 wind-B
(ediff-get-next-window wind-B wind-A
))
1150 (setq wind-A
(ediff-get-window-by-clicking wind-A nil
1)
1151 wind-B
(ediff-get-window-by-clicking wind-B wind-A
2)))
1153 (let ((buffer-A (window-buffer wind-A
))
1154 (buffer-B (window-buffer wind-B
))
1155 beg-A end-A beg-B end-B
)
1158 (save-window-excursion
1159 (sit-for 0) ; synch before using window-start/end -- a precaution
1160 (select-window wind-A
)
1161 (setq beg-A
(window-start)
1163 (select-window wind-B
)
1164 (setq beg-B
(window-start)
1165 end-B
(window-end))))
1166 (ediff-regions-internal
1167 buffer-A beg-A end-A buffer-B beg-B end-B
1168 startup-hooks job-name word-mode
)))
1171 (defun ediff-regions-wordwise (buffer-A buffer-B
&optional startup-hooks
)
1172 "Run Ediff on a pair of regions in two different buffers.
1173 Regions \(i.e., point and mark\) are assumed to be set in advance.
1174 This function is effective only for relatively small regions, up to 200
1175 lines. For large regions, use `ediff-regions-linewise'."
1178 (list (setq bf
(read-buffer "Region's A buffer: "
1179 (ediff-other-buffer "") t
))
1180 (read-buffer "Region's B buffer: "
1182 ;; realign buffers so that two visible bufs will be
1184 (save-window-excursion (other-window 1))
1185 (ediff-other-buffer bf
))
1187 (if (not (ediff-buffer-live-p buffer-A
))
1188 (error "Buffer %S doesn't exist" buffer-A
))
1189 (if (not (ediff-buffer-live-p buffer-B
))
1190 (error "Buffer %S doesn't exist" buffer-B
))
1193 (let (reg-A-beg reg-A-end reg-B-beg reg-B-end
)
1195 (set-buffer buffer-A
)
1196 (setq reg-A-beg
(region-beginning)
1197 reg-A-end
(region-end))
1198 (set-buffer buffer-B
)
1199 (setq reg-B-beg
(region-beginning)
1200 reg-B-end
(region-end)))
1202 (ediff-regions-internal
1203 (get-buffer buffer-A
) reg-A-beg reg-A-end
1204 (get-buffer buffer-B
) reg-B-beg reg-B-end
1205 startup-hooks
'ediff-regions-wordwise
'word-mode
)))
1208 (defun ediff-regions-linewise (buffer-A buffer-B
&optional startup-hooks
)
1209 "Run Ediff on a pair of regions in two different buffers.
1210 Regions \(i.e., point and mark\) are assumed to be set in advance.
1211 Each region is enlarged to contain full lines.
1212 This function is effective for large regions, over 100-200
1213 lines. For small regions, use `ediff-regions-wordwise'."
1216 (list (setq bf
(read-buffer "Region A's buffer: "
1217 (ediff-other-buffer "") t
))
1218 (read-buffer "Region B's buffer: "
1220 ;; realign buffers so that two visible bufs will be
1222 (save-window-excursion (other-window 1))
1223 (ediff-other-buffer bf
))
1225 (if (not (ediff-buffer-live-p buffer-A
))
1226 (error "Buffer %S doesn't exist" buffer-A
))
1227 (if (not (ediff-buffer-live-p buffer-B
))
1228 (error "Buffer %S doesn't exist" buffer-B
))
1230 (let (reg-A-beg reg-A-end reg-B-beg reg-B-end
)
1232 (set-buffer buffer-A
)
1233 (setq reg-A-beg
(region-beginning)
1234 reg-A-end
(region-end))
1235 ;; enlarge the region to hold full lines
1236 (goto-char reg-A-beg
)
1238 (setq reg-A-beg
(point))
1239 (goto-char reg-A-end
)
1241 (or (eobp) (forward-char)) ; include the newline char
1242 (setq reg-A-end
(point))
1244 (set-buffer buffer-B
)
1245 (setq reg-B-beg
(region-beginning)
1246 reg-B-end
(region-end))
1247 ;; enlarge the region to hold full lines
1248 (goto-char reg-A-beg
)
1249 (goto-char reg-B-beg
)
1251 (setq reg-B-beg
(point))
1252 (goto-char reg-B-end
)
1254 (or (eobp) (forward-char)) ; include the newline char
1255 (setq reg-B-end
(point))
1258 (ediff-regions-internal
1259 (get-buffer buffer-A
) reg-A-beg reg-A-end
1260 (get-buffer buffer-B
) reg-B-beg reg-B-end
1261 startup-hooks
'ediff-regions-linewise nil
))) ; no word mode
1263 ;; compare region beg-A to end-A of buffer-A
1264 ;; to regions beg-B -- end-B in buffer-B.
1265 (defun ediff-regions-internal (buffer-A beg-A end-A buffer-B beg-B end-B
1266 startup-hooks job-name word-mode
)
1267 (let ((tmp-buffer (get-buffer-create ediff-tmp-buffer
))
1271 ;; in case beg/end-A/B aren't markers--make them into markers
1272 (ediff-eval-in-buffer buffer-A
1273 (setq beg-A
(move-marker (make-marker) beg-A
)
1274 end-A
(move-marker (make-marker) end-A
)))
1275 (ediff-eval-in-buffer buffer-B
1276 (setq beg-B
(move-marker (make-marker) beg-B
)
1277 end-B
(move-marker (make-marker) end-B
)))
1279 (if (and (eq buffer-A buffer-B
)
1280 (or (and (< beg-A end-B
) (<= beg-B beg-A
)) ; b-B b-A e-B
1281 (and (< beg-B end-A
) (<= end-A end-B
)))) ; b-B e-A e-B
1283 (with-output-to-temp-buffer ediff-msg-buffer
1285 You have requested to compare overlapping regions of the same buffer.
1287 In this case, Ediff's highlighting may be confusing---in the same window,
1288 you may see highlighted regions that belong to different regions.
1290 Continue anyway? (y/n) "))
1292 (if (y-or-n-p "Continue anyway? ")
1294 (error "%S aborted" job-name
))))
1298 (ediff-wordify beg-A end-A buffer-A tmp-buffer
)
1299 (ediff-copy-to-buffer beg-A end-A buffer-A tmp-buffer
))
1300 (ediff-eval-in-buffer tmp-buffer
1301 (setq file-A
(ediff-make-temp-file "regA")))
1305 (ediff-wordify beg-B end-B buffer-B tmp-buffer
)
1306 (ediff-copy-to-buffer beg-B end-B buffer-B tmp-buffer
))
1307 (ediff-eval-in-buffer tmp-buffer
1308 (setq file-B
(ediff-make-temp-file "regB")))
1310 (setq overl-A
(ediff-make-bullet-proof-overlay beg-A end-A buffer-A
))
1311 (setq overl-B
(ediff-make-bullet-proof-overlay beg-B end-B buffer-B
))
1312 (ediff-setup buffer-A file-A
1314 nil nil
; buffer & file C
1316 (delete-file (, file-A
))
1317 (delete-file (, file-B
))))
1319 (list (cons 'ediff-word-mode word-mode
)
1320 (cons 'ediff-narrow-bounds
(list overl-A overl-B
))
1321 (cons 'ediff-job-name job-name
))
1326 ;;; Merge files and buffers
1329 (defalias 'ediff-merge
'ediff-merge-files
)
1331 (defsubst ediff-merge-on-startup
()
1333 (ediff-eval-in-buffer ediff-buffer-C
1334 (set-buffer-modified-p nil
)))
1337 (defun ediff-merge-files (file-A file-B
&optional startup-hooks
)
1338 "Merge two files without ancestor."
1340 (let ((dir-A (if ediff-use-last-dir
1344 (list (setq f
(ediff-read-file-name "File A to merge" dir-A nil
))
1345 (ediff-read-file-name "File B to merge"
1347 (if ediff-use-last-dir
1349 (file-name-directory f
)))
1351 (setq file-name-history
1352 (cons (abbreviate-file-name
1354 (file-name-nondirectory f
)
1359 (setq startup-hooks
(cons 'ediff-merge-on-startup startup-hooks
))
1360 (ediff-files-internal file-A
1361 (if (file-directory-p file-B
)
1363 (file-name-nondirectory file-A
) file-B
)
1367 'ediff-merge-files
))
1370 (defun ediff-merge-files-with-ancestor (file-A file-B file-ancestor
1371 &optional startup-hooks
)
1372 "Merge two files with ancestor."
1374 (let ((dir-A (if ediff-use-last-dir
1377 dir-B dir-ancestor f ff
)
1378 (list (setq f
(ediff-read-file-name "File A to merge" dir-A nil
))
1379 (setq ff
(ediff-read-file-name "File B to merge"
1381 (if ediff-use-last-dir
1383 (file-name-directory f
)))
1385 (setq file-name-history
1387 (abbreviate-file-name
1389 (file-name-nondirectory f
)
1393 (ediff-read-file-name "Ancestor file"
1395 (if ediff-use-last-dir
1396 ediff-last-dir-ancestor
1397 (file-name-directory ff
)))
1399 (setq file-name-history
1400 (cons (abbreviate-file-name
1402 (file-name-nondirectory ff
)
1407 (setq startup-hooks
(cons 'ediff-merge-on-startup startup-hooks
))
1408 (ediff-files-internal file-A
1409 (if (file-directory-p file-B
)
1411 (file-name-nondirectory file-A
) file-B
)
1415 'ediff-merge-files-with-ancestor
))
1418 (defalias 'ediff-merge-with-ancestor
'ediff-merge-files-with-ancestor
)
1421 (defun ediff-merge-buffers (buffer-A buffer-B
&optional startup-hooks job-name
)
1422 "Merge buffers without ancestor."
1425 (list (setq bf
(read-buffer "Buffer A to merge: "
1426 (ediff-other-buffer "") t
))
1427 (read-buffer "Buffer B to merge: "
1429 ;; realign buffers so that two visible bufs will be
1431 (save-window-excursion (other-window 1))
1432 (ediff-other-buffer bf
))
1435 (setq startup-hooks
(cons 'ediff-merge-on-startup startup-hooks
))
1436 (or job-name
(setq job-name
'ediff-merge-buffers
))
1437 (ediff-buffers-internal
1438 buffer-A buffer-B nil startup-hooks job-name
))
1441 (defun ediff-merge-buffers-with-ancestor (buffer-A
1442 buffer-B buffer-ancestor
1443 &optional startup-hooks job-name
)
1444 "Merge buffers with ancestor."
1447 (list (setq bf
(read-buffer "Buffer A to merge: "
1448 (ediff-other-buffer "") t
))
1449 (setq bff
(read-buffer "Buffer B to merge: "
1451 ;; realign buffers so that two visible
1452 ;; bufs will be at the top
1453 (save-window-excursion (other-window 1))
1454 (ediff-other-buffer bf
))
1456 (read-buffer "Ancestor buffer: "
1458 ;; realign buffers so that three visible
1459 ;; bufs will be at the top
1460 (save-window-excursion (other-window 1))
1461 (ediff-other-buffer (list bf bff
)))
1465 (setq startup-hooks
(cons 'ediff-merge-on-startup startup-hooks
))
1466 (or job-name
(setq job-name
'ediff-merge-buffers-with-ancestor
))
1467 (ediff-buffers-internal
1468 buffer-A buffer-B buffer-ancestor startup-hooks job-name
))
1472 (defun ediff-merge-revisions (rev1 rev2
&optional startup-hooks
)
1473 "Run Ediff by merging two revisions of a file.
1474 The file is the one visited by the current buffer."
1476 "sVersion 1 to merge (default is the latest version): \nsVersion 2 to merge (default is the latest version): ")
1477 (ediff-load-version-control)
1479 (if (eq ediff-version-control-package
'vc
)
1482 (vc-version-other-window rev1
)
1483 (setq buf1
(current-buffer)))
1485 (vc-version-other-window rev2
)
1486 (setq buf2
(current-buffer)))
1489 (delete-file (, (buffer-file-name buf1
)))
1490 (delete-file (, (buffer-file-name buf2
))))))))
1491 (setq buf1
(rcs-ediff-view-revision rev1
)
1492 buf2
(rcs-ediff-view-revision rev2
)))
1493 (ediff-merge-buffers buf1 buf2 startup-hooks
'ediff-merge-revisions
)))
1497 (defun ediff-merge-revisions-with-ancestor (rev1
1499 &optional startup-hooks
)
1500 "Run Ediff by merging with ancestor of two revisions of a file.
1501 The file is the one visited by the current buffer."
1503 "sVersion 1 to merge (default: the latest version): \nsVersion 2 to merge (default: the latest version): \nsAncestor version (default: the latest version): ")
1504 (ediff-load-version-control)
1505 (let (buf1 buf2 ancestor-buf
)
1506 (if (eq ediff-version-control-package
'vc
)
1509 (vc-version-other-window rev1
)
1510 (setq buf1
(current-buffer)))
1512 (vc-version-other-window rev2
)
1513 (setq buf2
(current-buffer)))
1515 (vc-version-other-window ancestor-rev
)
1516 (setq ancestor-buf
(current-buffer)))
1519 (delete-file (, (buffer-file-name buf1
)))
1520 (delete-file (, (buffer-file-name buf2
)))
1521 (delete-file (, (buffer-file-name ancestor-buf
)))
1523 (setq buf1
(rcs-ediff-view-revision rev1
)
1524 buf2
(rcs-ediff-view-revision rev2
)
1525 ancestor-buf
(rcs-ediff-view-revision ancestor-rev
)))
1526 (ediff-merge-buffers-with-ancestor
1527 buf1 buf2 ancestor-buf
1528 startup-hooks
'ediff-merge-revisions-with-ancestor
)))
1535 (defun ediff-patch-buffer (buffer-name &optional startup-hooks
)
1536 "Run Ediff by patching BUFFER-NAME."
1537 (interactive "bBuffer to patch: ")
1539 (let* ((buf-to-patch (get-buffer buffer-name
))
1540 (file-name-ok (if buf-to-patch
(buffer-file-name buf-to-patch
)))
1541 (buf-mod-status (buffer-modified-p buf-to-patch
))
1542 default-dir file-name ctl-buf
)
1544 (setq file-name file-name-ok
)
1545 (ediff-eval-in-buffer buffer-name
1546 (setq default-dir default-directory
)
1547 (setq file-name
(ediff-make-temp-file))
1548 (set-visited-file-name file-name
)
1549 (setq buffer-auto-save-file-name nil
) ; don't create auto-save file
1550 (rename-buffer buffer-name
) ; don't confuse the user with new buf name
1551 (set-buffer-modified-p nil
)
1552 (set-visited-file-modtime) ; sync buffer and temp file
1553 (setq default-directory default-dir
)
1557 (ediff-patch-file file-name startup-hooks
'ediff-patch-buffer
))
1561 (ediff-eval-in-buffer ctl-buf
1562 (delete-file (buffer-file-name ediff-buffer-A
))
1563 (delete-file (buffer-file-name ediff-buffer-B
))
1564 (ediff-eval-in-buffer ediff-buffer-A
1565 (if default-dir
(setq default-directory default-dir
))
1566 (set-visited-file-name nil
)
1567 (rename-buffer buffer-name
)
1568 (set-buffer-modified-p buf-mod-status
))
1569 (ediff-eval-in-buffer ediff-buffer-B
1570 (setq buffer-auto-save-file-name nil
) ; don't create auto-save file
1571 (if default-dir
(setq default-directory default-dir
))
1572 (set-visited-file-name nil
)
1573 (rename-buffer (ediff-unique-buffer-name
1574 (concat buffer-name
"_patched") ""))
1575 (set-buffer-modified-p t
))))
1579 (defun ediff-get-patch-buffer (dir)
1580 "Obtain patch buffer. If patch is already in a buffer---use it.
1581 Else, read patch file into a new buffer."
1582 (if (y-or-n-p "Is the patch file already in a buffer? ")
1583 (setq ediff-patch-buf
1584 (get-buffer (read-buffer "Patch buffer name: " nil t
))) ;must match
1585 (setq ediff-patch-buf
1586 (find-file-noselect (read-file-name "Patch file name: " dir
))))
1588 (setq ediff-patch-diagnostics
1589 (get-buffer-create "*ediff patch diagnostics*"))
1590 (ediff-eval-in-buffer ediff-patch-diagnostics
1591 (insert-buffer ediff-patch-buf
)))
1597 ;;; Versions Control functions
1600 (defun ediff-revision (arg)
1601 "Call `vc.el' or `rcs.el' depending on `ediff-version-control-package'.
1602 Without prefix argument, compares the current buffer with an older version.
1603 With prefix argument, compares two older versions of the current buffer."
1609 "This buffer's version-1 to compare (default: the latest version): ")
1611 (read-string "This buffer's version-2 to compare (default: the latest version): "))
1613 (read-string "Version to compare the current buffer with (default: the latest version): ")))
1614 (ediff-load-version-control)
1616 (intern (format "%S-ediff-internal" ediff-version-control-package
))
1620 ;; Backward compatibility
1625 (with-output-to-temp-buffer ediff-msg-buffer
1627 You have invoked an obsolete function `vc-ediff' or `rcs-ediff'.
1628 Please use `M-x ediff-revision' instead.
1630 Also, please check the variables `ediff-version-control-package'
1631 and `ediff-revision-key' for customization.")))
1633 (defalias 'rcs-ediff
'vc-ediff
)
1635 ;; Test if version control package is loaded and load if not
1636 ;; Is SILENT is non-nil, don't report error if package is not found.
1637 (defun ediff-load-version-control (&optional silent
)
1638 (or (featurep ediff-version-control-package
)
1639 (if (locate-library (symbol-name ediff-version-control-package
))
1641 (message "") ; kill the message from `locate-library'
1642 (require ediff-version-control-package
)
1643 (if ediff-revision-key
1645 (cond ((eq ediff-version-control-package
'vc
) vc-prefix-map
)
1646 ((eq ediff-version-control-package
'rcs
) global-map
)
1648 ediff-revision-key
'ediff-revision
)))
1650 (error "Version control package %S.el not found. Use vc.el instead"
1651 ediff-version-control-package
)))))
1654 (defun vc-ediff-internal (rev1 &optional rev2
)
1655 "Run Ediff on versions of the current buffer.
1656 If both REV1 and REV2 are given then these two versions are compared.
1657 If only REV1 is given then the current buffer is compared against version REV1.
1658 If the current buffer is named `F', the version is named `F.~REV~'.
1659 If `F.~REV~' already exists, it is used instead of being re-created."
1660 (let ((curbuf (current-buffer))
1661 (curwind (selected-window))
1664 (vc-version-other-window rev1
)
1665 (setq rev1buf
(current-buffer)
1666 file1
(buffer-file-name))
1667 (select-window curwind
)
1668 (if (not (stringp rev2
))
1669 (setq rev2buf curbuf
)
1670 (vc-version-other-window rev2
)
1671 (setq rev2buf
(current-buffer)
1672 file2
(buffer-file-name)))
1676 (delete-file (, file1
))
1677 (if (, file2
) (delete-file (, file2
)))
1681 (defun rcs-ediff-view-revision (&optional rev
)
1682 "View previous RCS revision of current file.
1683 With prefix argument, prompts for a revision name."
1684 (interactive (list (if current-prefix-arg
1685 (read-string "Revision: "))))
1686 (let* ((filename (buffer-file-name (current-buffer)))
1687 (switches (append '("-p")
1688 (if rev
(list (concat "-r" rev
)) nil
)))
1689 (buff (concat (file-name-nondirectory filename
) ".~" rev
"~")))
1690 (message "Working ...")
1691 (setq filename
(expand-file-name filename
))
1692 (with-output-to-temp-buffer buff
1693 (let ((output-buffer (ediff-rcs-get-output-buffer filename buff
)))
1694 (delete-windows-on output-buffer
)
1696 (set-buffer output-buffer
)
1697 (apply 'call-process
"co" nil t nil
1698 ;; -q: quiet (no diagnostics)
1699 (append switches rcs-default-co-switches
1700 (list "-q" filename
)))))
1704 (defun ediff-rcs-get-output-buffer (file name
)
1705 ;; Get a buffer for RCS output for FILE, make it writable and clean it up.
1706 ;; Optional NAME is name to use instead of `*RCS-output*'.
1707 ;; This is a modified version from rcs.el v1.1. I use it here to make
1708 ;; Ediff immune to changes in rcs.el
1709 (let* ((default-major-mode 'fundamental-mode
) ; no frills!
1710 (buf (get-buffer-create name
)))
1713 (setq buffer-read-only nil
1714 default-directory
(file-name-directory (expand-file-name file
)))
1718 (defun rcs-ediff-internal (rev1 &optional rev2
)
1719 "Run Ediff on the current buffer, comparing it with previous RCS revision."
1720 (let ((rev2buf (if (stringp rev2
)
1721 (rcs-ediff-view-revision rev2
)
1723 (rev1buf (rcs-ediff-view-revision rev1
)))
1725 ;; rcs.el doesn't create temp version files, so we don't have to delete
1726 ;; anything in startup hooks to ediff-buffers
1727 (ediff-buffers rev1buf rev2buf nil
'ediff-revision
)
1732 ;;; This is split in several parts to avoid
1733 ;;; making a line in loaddefs.el that is too long for patch.
1734 ;;; Note that autoload.el currently looks for cookies
1735 ;;; only at top level in the file.
1736 ;;; So I moved these to top level. But the conditionals on
1737 ;;; purify-flag make these no-ops when you load ediff.
1738 ;;; They only do something in loaddefs.el.
1742 ;; explicit string-match, as ediff-xemacs-p is not defined at build time
1743 (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version
)
1745 (defvar menu-bar-epatch-menu
(make-sparse-keymap "Epatch"))
1746 (fset 'menu-bar-epatch-menu
(symbol-value 'menu-bar-epatch-menu
))
1747 (defvar menu-bar-ediff-merge-menu
(make-sparse-keymap "Ediff merge"))
1748 (fset 'menu-bar-ediff-merge-menu
1749 (symbol-value 'menu-bar-ediff-merge-menu
))
1750 (defvar menu-bar-ediff-menu
(make-sparse-keymap "Ediff"))
1751 (fset 'menu-bar-ediff-menu
(symbol-value 'menu-bar-ediff-menu
))
1754 ;;; These must be placed in menu-bar.el in Emacs
1756 ;; (define-key menu-bar-tools-menu [epatch]
1757 ;; '("Apply Patch" . menu-bar-epatch-menu))
1758 ;; (define-key menu-bar-tools-menu [ediff-merge]
1759 ;; '("Merge" . menu-bar-ediff-merge-menu))
1760 ;; (define-key menu-bar-tools-menu [ediff]
1761 ;; '("Compare" . menu-bar-ediff-menu))
1766 ;; explicit string-match, as ediff-xemacs-p is not defined at build time
1767 (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version
)
1769 (define-key menu-bar-ediff-menu
[ediff-revision
]
1770 '("File with Revision ..." . ediff-revision
))
1771 (define-key menu-bar-ediff-menu
[separator-ediff-files
] '("--"))
1772 (define-key menu-bar-ediff-menu
[ediff-buffers3
]
1773 '("Three Buffers ..." . ediff-buffers3
))
1774 (define-key menu-bar-ediff-menu
[ediff-files3
]
1775 '("Three Files ..." . ediff-files3
))
1776 (define-key menu-bar-ediff-menu
[ediff-buffers
]
1777 '("Two Buffers ..." . ediff-buffers
))
1778 (define-key menu-bar-ediff-menu
[ediff-files
]
1779 '("Two Files ..." . ediff-files
))
1784 ;; explicit string-match, as ediff-xemacs-p is not defined at build time
1785 (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version
)
1787 (define-key menu-bar-ediff-menu
[separator-ediff-regions
] '("--"))
1788 (define-key menu-bar-ediff-menu
[ediff-regions-linewise
]
1789 '("Regions Line-by-line ..." . ediff-regions-linewise
))
1790 (define-key menu-bar-ediff-menu
[ediff-regions-wordwise
]
1791 '("Regions Word-by-word ..." . ediff-regions-wordwise
))
1792 (define-key menu-bar-ediff-menu
[separator-ediff-windows
] '("--"))
1793 (define-key menu-bar-ediff-menu
[ediff-windows-linewise
]
1794 '("Windows Line-by-line ..." . ediff-windows-linewise
))
1795 (define-key menu-bar-ediff-menu
[ediff-windows-wordwise
]
1796 '("Windows Word-by-word ..." . ediff-windows-wordwise
))
1801 ;; explicit string-match, as ediff-xemacs-p is not defined at build time
1802 (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version
)
1805 menu-bar-ediff-merge-menu
[ediff-merge-revisions-with-ancestor
]
1806 '("Revisions with Ancestor ..." . ediff-merge-revisions-with-ancestor
))
1807 (define-key menu-bar-ediff-merge-menu
[ediff-merge-revisions
]
1808 '("Revisions ..." . ediff-merge-revisions
))
1809 (define-key menu-bar-ediff-merge-menu
[separator-ediff-merge
] '("--"))
1810 (define-key menu-bar-ediff-merge-menu
[ediff-merge-buffers-with-ancestor
]
1811 '("Buffers with Ancestor ..." . ediff-merge-buffers-with-ancestor
))
1812 (define-key menu-bar-ediff-merge-menu
[ediff-merge-buffers
]
1813 '("Buffers ..." . ediff-merge-buffers
))
1814 (define-key menu-bar-ediff-merge-menu
[ediff-merge-files-with-ancestor
]
1815 '("Files with Ancestor ..." . ediff-merge-files-with-ancestor
))
1816 (define-key menu-bar-ediff-merge-menu
[ediff-merge-files
]
1817 '("Files ..." . ediff-merge-files
))
1822 ;; explicit string-match, as ediff-xemacs-p is not defined at build time
1823 (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version
)
1825 (define-key menu-bar-epatch-menu
[ediff-patch-buffer
]
1826 '("To a Buffer ..." . ediff-patch-buffer
))
1827 (define-key menu-bar-epatch-menu
[ediff-patch-file
]
1828 '("To a File ..." . ediff-patch-file
))
1834 ;; explicit string-match, as ediff-xemacs-p is not defined at build time
1835 (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version
)
1839 ["Two Files ..." ediff-files t
]
1840 ["Two Buffers ..." ediff-buffers t
]
1841 ["Three Files ..." ediff-files3 t
]
1842 ["Three Buffers ..." ediff-buffers3 t
]
1844 ["File with Revision ..." ediff-revision t
]
1846 ["Windows Word-by-word ..." ediff-windows-wordwise t
]
1847 ["Windows Line-by-line ..." ediff-windows-linewise t
]
1849 ["Regions Word-by-word ..." ediff-regions-wordwise t
]
1850 ["Regions Line-by-line ..." ediff-regions-linewise t
]))
1851 (defvar ediff-merge-menu
1853 ["Files ..." ediff-merge-files t
]
1854 ["Files with Ancestor ..." ediff-merge-files-with-ancestor t
]
1855 ["Buffers ..." ediff-merge-buffers t
]
1856 ["Buffers with Ancestor ..."
1857 ediff-merge-buffers-with-ancestor t
]
1859 ["Revisions ..." ediff-merge-revisions t
]
1860 ["Revisions with Ancestor ..."
1861 ediff-merge-revisions-with-ancestor t
]))
1864 ["To a file ..." ediff-patch-file t
]
1865 ["To a buffer ..." ediff-patch-buffer t
]))
1866 (add-submenu '("Tools") ediff-menu
"VC")
1867 (add-submenu '("Tools") ediff-merge-menu
"VC")
1868 (add-submenu '("Tools") epatch-menu
"VC")
1869 ;; Display a solid horizontal line
1870 (add-menu-button '("Tools") ["---" nil nil
] "VC")
1875 (require 'ediff-util
)
1877 ;;; ediff.el ends here