]> git.eshelyaron.com Git - emacs.git/commitdiff
(ediff-files,ediff-merge-files): better file-name defaults.
authorMichael Kifer <kifer@cs.stonybrook.edu>
Fri, 6 Oct 1995 01:01:08 +0000 (01:01 +0000)
committerMichael Kifer <kifer@cs.stonybrook.edu>
Fri, 6 Oct 1995 01:01:08 +0000 (01:01 +0000)
(ediff-split-string): new function.
(ediff-exec-process): now handles diff args separated by space.
(ediff-backup-extension): new variable.
Replaced -hooks with -hook.
(ediff-revision-key): variable deleted.
Moved menubar definitions to a new file, ediff-hook.el

lisp/ediff.el

index bee087450ad023ca6b3249f80b60b8549e881684..d0a41a33be9662c87e78db54421c08f831fe7ec5 100644 (file)
@@ -5,8 +5,8 @@
 ;; Created: February 2, 1994
 ;; Keywords: comparing, merging, patching, version control.
 
-(defconst ediff-version "2.26" "The current version of Ediff")
-(defconst ediff-date "June 3, 1995" "Date of last update")  
+(defconst ediff-version "2.46" "The current version of Ediff")
+(defconst ediff-date "September 28, 1995" "Date of last update")  
 
 ;; This file is part of GNU Emacs.
 
 ;; through them.  You can also copy difference regions from one buffer to
 ;; another (and recover old differences if you change your mind).
 
+;; Ediff also supports merging operations on files and buffers, including
+;; merging using ancestor versions. Both comparison and merging operations can
+;; be performed on directories, i.e., by pairwise comparison of files in those
+;; directories.
+
 ;; In addition, Ediff can apply a patch to a file and then let you step
 ;; though both files, the patched and the original one, simultaneously,
 ;; difference-by-difference.  You can even apply a patch right out of a
 ;; files with their older versions. Ediff can also work with remote and
 ;; compressed files. Details are given below.
 
-;; This package builds upon the ideas borrowed from emerge.el and
-;; several Ediff's functions are adaptations from emerge.el. 
-;; Much of the functionality of Ediff is also influenced by emerge.el.
+;; Finally, Ediff supports directory-level comparison and merging operations.
+;; See the on-line manual for details.
 
-;; The present version of Ediff supersedes Emerge. It provides a superior
-;; user interface and has many features not found in Emerge. In particular,
-;; it can do patching and 2-way and 3-way file comparison in addition to
-;; merging.
+;; This package builds upon the ideas borrowed from emerge.el and several
+;; Ediff's functions are adaptations from emerge.el. Much of the functionality
+;; Ediff provides is also influenced by emerge.el.
+
+;; The present version of Ediff supersedes Emerge. It provides a superior user
+;; interface and has numerous major features not found in Emerge. In
+;; particular, it can do patching, and 2-way and 3-way file comparison,
+;; merging, and directory operations.
 
 
 
-;;; Compilation
-;;  -----------
-;;
-;; When you byte-compile Ediff, you will get some warnings about functions
-;; being undefined.  These can be safely ignored.
-;;
 ;;; Bugs:
 ;;  -----
 
 ;;  hilit19.el or font-lock.el packages. If this residual highlighting gets
 ;;  in the way, you can do the following. Both font-lock.el and hilit19.el
 ;;  provide commands for unhighlighting buffers. You can either place these
-;;  commands in `ediff-prepare-buffer-hooks' (which will unhighlight every
+;;  commands in `ediff-prepare-buffer-hook' (which will unhighlight every
 ;;  buffer used by Ediff) or you can execute them interactively, at any time
 ;;  and on any buffer.
 ;;
 
-;;; Change Log:
-;;  ----------
-
-;; Thu Feb  3, 1994 
-
-;;     Fixed a bug in ediff-setup-windows that caused control window to
-;;     appear in a wrong place when split-window-keep-point is nil
-;;     (Thanks to Kevin Broadey <KevinB@bartley.demon.co.uk>.)
-;;
-;;     Added mechanism for using faces instead of before/after flags.  This
-;;     looks much better on an X display, especially on a color one.
-;;     (Thanks to Boris Goldowsky <boris@cs.rochester.edu> for the code
-;;     that led to ediff-highlight-diff.
-;;     Also, thanks to Kevin Esler <esler@ch.hp.com> for suggestions
-;;     regarding highlighting differences on X displays.)
-;;
-;;     Added functions to apply patches.
-;;     (Thanks to Kevin Broadey <KevinB@bartley.demon.co.uk> for this
-;;     suggestion.)
-
-;; Fri Feb  4, 1994 
-
-;;     Added mechanism for toggling vertical/horizontal window split.
-;;     (Inspired by a suggestion from Allan Gottlieb
-;;     <gottlieb@allan.ultra.nyu.edu> -- thanks.)
-;;
-;;     Added mechanism for toggling between highlighting using faces and
-;;     highlighting using ASCII flags.
-;;
-;;     Fixed a problem with undo.  Now, Ediff has smartened up and doesn't
-;;     keep undo info on ASCII flags inserted in buffer-A and buffer-B.
-;;     So, if you edit the files while browsing through them, undo behaves
-;;     as you would expect, i.e., faces/flags don't get in the way.
-
-;; Sun Feb  6, 1994 
-
-;;     Added horizontal scrolling.  Added ediff-position-region to ensure
-;;     that difference regions in buffer-A and buffer-B are aligned with
-;;     each other.  Disabled ediff-toggle-split when buffers are displayed
-;;     in different frames.
-;;
-;;     Added toggle-window help (Suggested by Boris Goldowsky
-;;     <boris@cs.rochester.edu>.)
-;;     Added functions to copy differences from one buffer to another and to
-;;     recover old differences.
-;;     Added prefix arguments to ediff-next-difference and
-;;     ediff-previous-difference.
-
-;; Tue Feb  8, 1994
-
-;;     Replaced text properties with overlays.  Fixed ediff-setup-windows.
-;;     Added ediff-save-buffer to local-write-file-hooks to prevent user
-;;     from saving corrupted states. (Thanks to <boris@cs.rochester.edu>
-;;     for suggestion.)  Instead, Ediff now has a pair of functions for
-;;     safe saving of buffers. 
-;;     Changed ediff-read-file-name to be more intuitive on ediff-files.
-;;     Added ediff-prepare-buffer-hooks. (Thanks to Kevin Esler
-;;     <esler@ch.hp.com> for the idea.)
-;;
-;;     Cleanups in ediff-patch-file.  Protected ediff-copy-diff against
-;;     a bug that Emacs has in kill-region.
-;;
-;;     Added support for Lemacs. (Thanks to Alastair Burt
-;;     <burt@dfki.uni-kl.de> for coercing Ediff into working under Lemacs.)
-;;     Added ediff-kill-buffer-carefully and other suggestions by Boris
-;;     Goldowsky <boris@cs.rochester.edu>.
-;;     Refined the protection against interference with highlighting caused
-;;     by Hilit19.  Added the variable ediff-third-party-highlighting.
-;;     Added mechanisn for unhighlighting regions highlighted with Hilit19
-;;     before hightlighting them with Ediff's overlays. (And for
-;;     rehighlighting them with Hilit19, when the current difference moves on.)
-
-;; Sun Feb 13, 1994
-
-;;     Added ediff-place-flags-in-buffer and ediff-remote-exit, which are
-;;     modifications of Emerge's similar functions.  The difference is that
-;;     in Ediff they make ediff-before-flag and ediff-after-flag into
-;;     read-only regions, so the user can't change them by mistake.
-;;
-;;     Adopted a suggestion by Boris Goldowsky <boris@cs.rochester.edu>
-;;     that led to a more elegant treatment of faces.
-;;
-;;     Added protection against interference with Font-Lock highlighting
-;;     similar to that of Hilit19's protection.
-
-;; Tue Feb 15, 1994
-
-;;     Deleted spurious (auto-save-mode 1) in ediff-control-buffer, which
-;;     was causing this buffer to be auto-saved for no good reason.
-;;     Added read-only protection to ediff-before/after-flags in Lemacs.
-;;     (Thanks to Alastair Burt <burt@dfki.uni-kl.de> for help in testing.)
-;;
-;;     Further fixes in the XEmacs part.  Changed highlighted region in
-;;     ediff-highlight-diff so that an extra character will be highlighted
-;;     only if a difference is empty (thereby allowing the user to see where an
-;;     insertion or a deletion has taken place).
-;;
-;;     Simplified interaction with other highlighting packages by giving
-;;     Ediff overlays the highest priority. (Taking a cue from
-;;     ediff-highlight-diff-lemacs written by Alastair Burt
-;;     <burt@dfki.uni-kl.de>.) Zapped ediff-third-party-highlighting
-;;     variable and hooks that were previously used to
-;;     unhighlight/rehighlight buffers when hilit19/font-lock are on.
-
-;; Fri Feb 18, 1994
-
-;;     Added a bit more sophistication to ediff-read-file-name.  Now,
-;;     ediff-files remembers both, the file-A and the file-B directories.
-;;     They are offered as defaults when ediff-use-last-dir is set to t.
-
-;; Fri Feb 22, 1994
-
-;;     Added ediff-before-change-guard to remove ASCII highlighting when
-;;     the user attempts to change buffer-A/B.  This is needed because
-;;     otherwise the undo info may become screwed up in those buffers.
-;;     Hitting `h' (ediff-toggle-hilit) on a dumb terminal will toggle
-;;     between ASCII highlighting and no highlighting.
-
-;; Fri Feb 24, 1994
-
-;;     Fixed problems with multiple Ediff sessions running simultaneously.
-
-;; Tue Mar 1, 1994
-
-;;     Added vc-ediff, the Ediff interface to vc.el. (Thanks to Eric
-;;     Freudenthal <freudent@jan.ultra.nyu.edu> for contributing this
-;;     function.) 
-
-;; Sun Mar 6, 1994
-
-;;     Added rcs-ediff, an Ediff interface to RCS via rcs.el. (Thanks to
-;;     Alastair Burt  <burt@dfki.uni-kl.de>.)
-;;     Some minor improvements.
-
-;; Tue March 15, 1994
-
-;;     Fixed a buglet in defining ediff-current-diff-face-A/B.
-;;     (Thanks to Job Ganzevoort  <Job.Ganzevoort@cwi.nl>.) 
-
-;; Tue March 22, 1994
-
-;;     Fixed a bug with ediffing narrowed buffers, reported by Kevin
-;;     Broadey <KevinB@bartley.demon.co.uk>.
-;;     Made Ediff to work with files that have incomplete last line.
-;;     Made Ediff execute diff and patch using Bourne Shell, which
-;;     should eliminate problems with $prompt that some people had.
-
-;; Thu March 24, 1994
-
-;;     Achieved quadratic speedup in the size of the file by replacing the
-;;     slow goto-line by forward-line.
-;;     Converted demarkation of difference regions
-;;     from markers to overlays.  This will later allow us to highlight all
-;;     diffs, not just the current one.
-
-;; Wed March 30, 1994
-
-;;     Under X, Ediff now highlights all differences in dim colors and the
-;;     current difference in bright colors. Improved XEmacs support.
-;;     Changed toggle hilit to cycle through 3 states: highlighting all
-;;     diffs, highlighting only the current diff, and highlighting using
-;;     ASCII flags.
-;;     Added support for difference regions that are not full lines.
-
-;; Fri April 1, 1994
-
-;;     Fixed bugs related to writing buffers A and B.
-;;     Added commands `ga', `gb' to jump directly to the closest diff in
-;;     buffer A and B, respectively.
-
-;; Fri April 11, 1994
-
-;;     Added `ediff-update-diffs', a function that lets the user recompute
-;;     difference regions after extensive editing done to buffers A and B
-;;     (bound to `!').
-
-;; Wed April 13, 1994
-
-;;     Added the new feature: refining the current difference region.
-;;     This would highlight the precise differences between the regions in
-;;     buffer A and B. (A way to implement this was suggested by Boris
-;;     Goldowsky <boris@cs.rochester.edu>.)
-;;
-;;     Fixed Ediff to be immune to several different versions of rcs.el
-;;     that are currently in distribution.
-
-;; Thu April 14, 1994
-
-;;     Ediff now respects X resources for the faces it uses. It no longer
-;;     barks when the colormap has no colors it is using; or when face
-;;     fonts can't be italicized, etc.
-
-;; Fri April 15, 1994
-
-;;     Changed `ediff-setup-windows' to minimize the need to delete and
-;;     create windows. Now jumps faster from diff to diff.
-;;     Added Ediff to the File menu on the menu bar (FSF's version).
-
-;; Mon April 18, 1994
-
-;;     Fixed to work with OS/2's PM-Emacs.
-
-;; Thu April 21, 1994
-
-;;     Lemacs' menus added (thanks to Alastair Burt for the help).
-
-;; Wed April 28, 1994
-
-;;     Fixed ediff-keep-window-config (thanks to Norbert Kiesel 
-;;     <norbert@i3.informatik.rwth-aachen.de>), ediff-shell and
-;;     ediff-protect-metachars (thanks to Richard Stanton
-;;     <stanton@haas.berkeley.edu>). Made access to difference
-;;     overlays structure-independent, making it less bug-prone.
-;;     Patched ediff-read-file-name to work more intuitively with directory
-;;     names (thanks to Kevin Broadey <KevinB@bartley.demon.co.uk>).
-
-;; Mon May 2, 1994
-
-;;     Added `ediff-frame-has-menubar' to guard against the possibility that
-;;     the current frame has no menu bar.
-
-;; Fri May 6, 1994
-
-;;     Fixed buglet in vc-ediff (thanks to Ray Nickson <nickson@cs.uq.oz.au>).
-
-;; Wed May 18, 1994
-
-;;     Modified ediff-read-file-name to not put long file names in the
-;;     default prompt area, as suggested by KevinB@bartley.demon.co.uk.
-;;     Applied patch supplied by burt@dfki.uni-kl.de, fixing a problem with
-;;     ediff-diff-to-diff in Lemacs.
-
-;; Tue May 31, 1994
-
-;;     Added ediff-forward-word-function (as suggested by Job Ganzevoort
-;;     <Job.Ganzevoort@cwi.nl>).
-
-;; Thu Jun 2, 1994
-
-;;     Added `ediff-toggle-regexp-match', which allows the user to step
-;;     through only those difference regions that match some regexp; or,
-;;     vice versa, to skip over regions that match a regexp. (This feature
-;;     was suggested by Andy Scott <ascott@pcocd2.intel.com>.)
-;;     Added ediff-eval-in-buffer, which is a modified emerge-eval-in-buffer.
-;;     The function ediff-status-info, bound to `i', now replaces and extends
-;;     ediff-file-names and ediff-line-numbers, which were bound to `f'
-;;     and `i', respectively.
-
-
-;; Wed Jun 10, 1994
-
-;;     Improved `ediff-read-file-name' and `ediff-buffers' so they are now
-;;     providing more intuitive defaults. Modified `ediff-read-file-name'
-;;     so it won't cause problems under OS/2.
-
-;; Fri Jun 24, 1994
-
-;;     Modified ediff-find-file, ediff-files-internal, and made
-;;     emerge-verify-file-buffer into ediff-verify-file-buffer so that
-;;     Ediff will work correctly with remote and compressed
-;;     files. (Suggested by Sandy Rutherford <sandy@ibm550.sissa.it>.)
-
-;; Fri Jun 28, 1994
-
-;;     Fixed ediff-patch-files to work with remote and compressed files.
-
-;; Wed July 20, 1994
-
-;;     Changed menu bar items per RMS's suggestion. Changed odd/even faces
-;;     in Lemacs to italic.  Changed ediff-*-face-* variables so that they
-;;     will contain names of faces instead of the face internal
-;;     representation.  (Copy-face works better with face names than with
-;;     face internal representation.  With face internal representation, if
-;;     a face vector mentions a font explicitly, copy-face may attempt to
-;;     copy this font, which would cause an error if the font has a wrong
-;;     size for one of the existing frames.)  Improved the way
-;;     mode-line-buffer-identification is set in ediff-setup so that Ediff
-;;     will accommodate the way buffers are identified in mode-line.el and
-;;     uniquify.el.
-
-;; Fri August 5, 1994
-
-;;     Ediff can now automatically skip over regions that differ only in
-;;     the white space and line breaks. This is controled with the variable
-;;     `ediff-ignore-similar-regions' and can be toggled on/off by typing
-;;     `##'.
-
-;; Mon August 8, 1994
-
-;;     If ediff-save-buffer is invoked with `wd', it'll save the diff
-;;     output in a file.
-
-;; Wed August 24, 1994
-
-;;     Fixed ediff-toggle-read-only and ediff-patch-file so that they will
-;;     check out version-controled files before modifying them. This will
-;;     permit checking the modified versions back in. In earlier
-;;     versions, such modifications could be lost, unless the user takes
-;;     special care of preserving them.
-
-;; Tue August 30, 1994
-
-;;     Added ediff-submit-report.
-;;     Introduced ediff-revision as a uniform way of calling vc.el and
-;;     rcs.el. This is controled by ediff-version-control-package
-;;     variable. Functions vc-ediff, rcs-ediff are replaced by their
-;;     internal versions.
-
-;; Thu September 1, 1994
-
-;;     Made ediff-overlay-put and ediff-move-overlay into bona fide
-;;     functions (rather than fset symbols). These now check if overlay's
-;;     buffer is alive. If not, overlay is deleted. This overcomes some of
-;;     the problems with Lemacs.
-
-;; Thu September 8, 1994
-
-;;     Added ediff-revision-key, ediff-load-version-control and streamlined
-;;     vc/rcs-ediff[-internal].  Eliminated dependency on emerge.el.
-
-;; Fri September 23, 1994
-
-;;     Added ediff-windows and ediff-regions.
-;;     Changed ediff-setup-windows and related procedures to create
-;;     a separate dedicated control frame for each invocation of Ediff.
-
-;; Tue September 27, 1994
-
-;;     Added redraw-display everywhere before creating or deleting
-;;     frames. It appears that this cures Emacs' bug where it trashes some
-;;     fonts which leads to crashes. Also, some code cleanups and bug fixes.
-
-;; Fri September 30, 1994
-
-;;     Fixed ediff-update-diffs so it'll work correctly with
-;;     ediff-windows and ediff-regions. Added narrowing and widening to the
-;;     suite of commands available for ediff-windows and ediff-regions.
-
-;; Fri October 7, 1994
-
-;;     Changed ediff-setup-windows to funcall the actual window setting
-;;     function, which is either ediff-setup-windows-multiframe or
-;;     ediff-setup-windows-plain. Changed all temp file names to use `_'
-;;     instead of `.'. Presumably, this makes VMS happier.
-;;     Ported to VMS (thanks to Richard Levitte <levitte@e.kth.se>).
-;;     Added ediff-prefer-long-help-message and changed defaults.
-;;     Fighting with XEmacs bugs. Made it possible to switch between plain
-;;     and multiframe display easier, but XEmacs is still getting confused
-;;     at times. Added ediff-check-version and ediff-set-help-message.
-;;     Made more sensible temp file names, which is important when
-;;     generating context diffs. Added ediff-make-frame-position and
-;;     ediff-control-frame-position-function.
-
-;; Wed October 12, 1994
-
-;;     ediff-window-visible-p now makes a call to frame-visible-p
-;;     only when window-system is non-nil. Rearranged the block of fset's
-;;     so that the wrong things won't be defined when window-system is nil.
-;;     Added ediff-revert-buffers-then-recompute-diffs function.
-;;     Removed flag-argument from a background call to shell-command.
-;;     Added ediff-shell-command to enable custom diff execute in the
-;;     background and insert output in ediff-custom-diff-buffer.
-;;     Added ediff-shell-command-filter, because XEmacs doesn't have it.
-;;     Made ediff-revision set up ediff-job-name to `ediff-revision'.
-;;     This enables users do ediff-revision-specific actions on exiting
-;;     Ediff using ediff-quit-hooks.
-;;     Reshaffled some fset's so that functions for checking color and
-;;     faces won't be touched on a non-windowing display.
-
-;; Thu October 20, 1994
-
-;;     Modified ediff-make-fine-diffs so that no fine diffs are computed if
-;;     one of the diff regions is empty. Saves time and also works around
-;;     the buggy diff program in AIX.
-;;     ediff no longer loads the version control package
-;;     automatically---only when ediff-revision is called.
-;;     Enabled focusing/hiding diff regions that match both or just one of the
-;;     regexps. 
-;;     Changed ediff-regions to ediff-small-regions. Added ediff-large-regions.
-;;     Modified ediff-next/previous-difference to work right when both
-;;     skipping regexp matches and skipping similar regions is enabled.
-;;     Fixed bugs in positioning the control frame.
-
-;; Fri October 28, 1994
-
-;;     Fixed bugs in ediff-next/previous-difference, ediff-set-visible-region
-;;     Changed/added ediff-word-[1-4].
-
-;; Tue November 1, 1994
-
-;;     Made ediff-revision delete the temporary version files it creates.
-
-;; Tue November 29, 1994
-
-;;     Added ediff-swap-buffers. Split ediff-difference-vector into
-;;     ediff-difference-vector-A and ediff-difference-vector-B, which
-;;     allowed to factor out a lot of stuff.
-;;     Made the code buffer-C ready.
-
-;; Thu December 1, 1994
-
-;;     Lotsa bug fixes. Further rationalized the code.
-;;     Added ediff-display-help-hooks, ediff-mode-hooks.
-;;     Replaced almost identical ediff-scroll-up/down with
-;;     ediff-scroll-vertically.
-;;     Replaced almost identical ediff-scroll-left/right with
-;;     ediff-scroll-horizontally.
-;;     Made the code buffer-C ready.
-
-;; Thu December 8, 1994
-
-;;     Added ediff-toggle-wide-display. In plain display, help message is
-;;     now centered correctly.
-
-;; Fri December 9, 1994
-
-;;     Added ediff-toggle-multiframe.
-;;     Fixed ediff-pop-diff and ediff-copy-diff, so that they will
-;;     invoke auto-refining, if necessary.
-
-;; Mon December 12, 1994
-
-;;     Modified ediff-toggle-wide-display so it would funcall
-;;     ediff-make-wide-display-function.
-
-;; Tue December 13, 1994
-
-;;     Ediff now chooses its surrogate minibuffer from frame A.
-
-;; Mon December 20, 1994
-
-;;     Added ediff-keymap-setup-hooks.
-
-;; Fri December 23, 1994
-
-;;     Changed the representation in ediff-killed-diffs-alist so that
-;;     ediff-save-diff-region and ediff-pop-diff won't be confused when the
-;;     user swaps buffers.
-
-;; Mon December 26, 1994
-
-;;     Placated OS/2 by making Ediff to synchronize the call to startup
-;;     hooks with the acynchronous process that computes custom diffs.
-;;     This has no effect on Unix installations (and VMS?), but
-;;     may increase Ediff's startup time under OS/2 by 1 or 2 seconds.
-
-;; Thu December 29, 1994
-
-;;     ediff-recenter now deactivates the mark, so that transient mark mode
-;;     highlighting won't interfere with Ediff's highlighting.
-;;     Also, ediff-recenter tries to not deiconify control frame, if it is
-;;     not needed.
-
-;; Fri December 30, 1994
-
-;;     Small bugs. Worked around the OS/2 bug where
-;;     modify-frame-parameters has no effect on iconified frames.  Ediff
-;;     now remembers the iconification status of the control frame and uses
-;;     it as a preferred way of displaying it when help is toggled
-;;     off. (This can be observed only in Emacs (not XEmacs) and only if
-;;     the window manager lets icons accept keyboard input.)
-
-;; Tue January 3, 1995
-
-;;     Some futher work on incorporating buffer C in ediff-extract-diffs,
-;;     ediff-focus/hide-on-regexp-matches, and
-;;     ediff-setup-windows-plain/multiframe. The preceding two functions
-;;     now dispatch the appropriate setup function depending on whether the
-;;     current job is comparison or merge.
-
-;; Wed January 4, 1995
-
-;;     Made it work under Emacs built without the X support.
-
-;; Fri January 6, 1995
-
-;;     Slightly changed the prompting behavior of ediff-files. Bug fix in
-;;     mode-line-buffer-identification.
-
-;; Wed January 18, 1995
-
-;;     Added 3way comparison and support for diff3. Ported to NeXTStep
-;;     
-;; Fri January 20, 1995
-
-;;     Added ediff-merge-files, ediff-merge-buffers,
-;;     ediff-merge-files-with-ancestor, ediff-merge-buffers-with-ancestor,
-;;     ediff-merge-revisions, ediff-merge-revisions-with-ancestor.
-
-;; Tue January 24, 1995
-
-;;     Bug fixes. Split into several files.
-
-;; Thu January 26, 1995
-
-;;     `*' is now bound to ediff-make-or-kill-fine-diffs. This lets the
-;;     user to kill fine diffs for the current region (by providing a
-;;     negative prefix arg), if there are so many of them as to hamper
-;;     the viewing.
-
-;; Mon January 30, 1995
-
-;;     Changed ediff-selective-display to ediff-set-visible-region,
-;;     ediff-toggle-selective-display to ediff-toggle-narrow-region.
-;;     Ediff now turns selective display off before starting. Restores 
-;;     selective display on exit.
-;;     In 2-way comparison, `a' now copies to buf `b' and `b' to buf `a'.
-;;     Previously, the bindings were `ab' and `ba'.
-
-;; Wed February 1, 1995
-
-;;     Added ediff-undo-selective-display (thanks to Stig <stig@hackvan.com>).
-;;     Rearranged autoloads. Renamed ediff-entry.el into ediff.el and
-;;     ediff.el into ediff-util.el.
-
-;; Fri February 3
-
-;;     Added ediff-toggle-show-clashes-only, which is bound to `$'.
-
-;; Fri February 19
-
-;;     Some minor patches from Stig. Also, made ediff-xemacs-p and
-;;     ediff-*-job into variables for better performance.
-;;     In ediff-setup, diff regions are now computed after buffers A/B/C
-;;     are set up. Previously, it didn't work right with selective display.
-;;     Also, added ediff-profile to time Ediff commands and
-;;     ediff-debug-info for civilized display of the difference vectors
-;;     (and possibly more in the future).
-
-;; Tue March 18
-
-;;     Fixed ediff-diff-at-point and ediff-toggle-multiframe.
-;;     Added ediff-destroy-control-frame, ediff-window-display-p. The latter
-;;      replaces window-system in many cases. Needed because in XEmacs 19.12
-;;      window-system returns 'tty on a tty display.
-;;     Converted xemacs *screen* nomenclature to *frame*.
-;;     Made ediff-patch-buffer cope with buffers that don't visit any file.
-;;     Fixed ediff-toggle-read-only so it knows the difference between
-;;     version-controlled files and others. It also knows whether we are using
-;;     patch or not.
-;;     Renamed ediff-windows to ediff-windows-wordwise, added
-;;     ediff-windows-linewise. Changed ediff-small/large-regions to
-;;      ediff-regions-wordwise/linewise 
-
-;; Tue May 2
-
-;;     Added ediff-documentation. Fixes for XEmacs 19.12.
-;;     Merge buffer now assumes the major mode of ediff-default-variant.
-
-;; Mon May 31, 1995
-
-;;     Ediff-revision now takes a prefix argument. Can compare two versions of
-;;     the same file. Cleaned up ediff-make-control-frame.
-;;     Fixed a bug in ediff-get-visible-buffer-window.
-;;     Added ediff-cleanup-hooks, ediff-janitor.
-;;     ediff-cleanup-hooks is called before ediff-quit-hooks.
-
-
-;;; TO DO:
-;;  ------
-;;
-;; 1. Add support for multiple sessions. (At present, one can run
-;; multiple Ediff sessions, but they won't be related.) The idea is to
-;; have vars local to each control buffer, which will tell which buffer is
-;; the next and which is the previous one. The user could then go forward
-;; and backward by typing C-SPC and C-DEL (or C-n and C-p).
-;; This will probably entail some minor modifications to ediff-setup.
-;; The primary use of this feature would be comparing directories of
-;; similarly named files and multi-file patch. For the latter, Ediff will
-;; have to parse patches to extract the names of files.
-
 
 ;;; Acknowledgements:
 
-;; Special thanks to Alastair Burt <burt@dfki.uni-kl.de>, Kevin Broadey
-;; <KevinB@bartley.demon.co.uk>, Harald Boegeholz
-;; <hwb@machnix.mathematik.uni-stuttgart.de>, Jin S. Choi" <jin@atype.com>,
-;;  Eric Eide <eeide@asylum.cs.utah.edu>, Kevin Esler <esler@ch.hp.com>, Robert
-;;  Estes <estes@ece.ucdavis.edu>, Eric Freudenthal
-;;  <freudent@jan.ultra.nyu.edu>, 
-;; Job Ganzevoort <Job.Ganzevoort@cwi.nl>, Boris Goldowsky
-;; <boris@cs.rochester.edu>, Allan Gottlieb <gottlieb@allan.ultra.nyu.edu>,
-;; Xiaoli Huang <hxl@epic.com>, Larry Gouge <larry@itginc.com>,
-;; Karl Heuer <kwzh@gnu.ai.mit.edu>, <irvine@lks.csi.com>,
-;; <jaffe@chipmunk.cita.utoronto.ca>, David Karr
-;; <dkarr@nmo.gtegsc.com>, Norbert Kiesel
-;; <norbert@i3.informatik.rwth-aachen.de>, Fritz Knabe <Fritz.Knabe@ecrc.de>,
-;; Heinz Knutzen <hk@informatik.uni-kiel.d400.de>, Ken Laprade
-;; <laprade@dw3f.ess.harris.com>, Richard Levitte
-;; <levitte@e.kth.se>, Martin Maechler <maechler@stat.math.ethz.ch>,
-;; Richard Mlynarik <mly@adoc.xerox.com>, Chris Murphy
-;; <murphycm@sun.aston.ac.uk>, Eyvind Ness <Eyvind.Ness@hrp.no>, Ray Nickson
-;; <nickson@cs.uq.oz.au>, Paul Raines <raines@slac.stanford.edu>, Tibor
-;; Polgar <tlp00@spg.amdahl.com>, C.S. Roberson <roberson@aur.alcatel.com>,
-;; Kevin Rodgers <kevin.rodgers@ihs.com>, Sandy Rutherford
-;; <sandy@ibm550.sissa.it>, Heribert Schuetz <schuetz@ecrc.de>, Andy Scott
-;; <ascott@pcocd2.intel.com>, Axel Seibert
-;; <axel@tumbolia.ppp.informatik.uni-muenchen.de>, Richard Stallman
-;; <rms@gnu.ai.mit.edu>, Richard Stanton <stanton@haas.berkeley.edu>,
-;; Ake Stenhoff <etxaksf@aom.ericsson.se>,
-;; Stig <stig@hackvan.com>, Peter Stout <Peter_Stout@cs.cmu.edu>,
-;; Raymond Toy <toy@rtp.ericsson.se>,
-;; and Ilya Zakharevich <ilya@math.ohio-state.edu> 
-;; for contributing ideas, patches, and bug reports.
-;;
-;; Thanks also to many others who felt obliged to drop a thank you note.
+;; Ediff was inspired by Dale R. Worley's <drw@math.mit.edu> emerge.el.
+;; Ediff would not have been possible without the help and encouragement of
+;; its many users. See Ediff on-line Info for the full list of those who
+;; helped. Improved defaults in Ediff file-name reading commands.
 
 
 ;;; Code:
 
 (require 'ediff-init)
+(require 'ediff-meta)
 
-(defvar ediff-version-control-package 'vc
-  "Version control package used.
-Currently, Ediff supports vc.el and rcs.el. Set this to `rcs' if you have
-rcs.el and want to use it instead of the standard vc.el.
-
-Note: both packages provide access to RCS, but only vc.el comes with Emacs
-distribution.")
-
-(defvar ediff-revision-key nil
-  "Key to which `ediff-revision' is to be bound.")
-  
 (defvar ediff-use-last-dir nil
   "*If t, Ediff uses previous directory as default when reading file name.")
   
@@ -733,16 +126,22 @@ distribution.")
 
 ;;; Patching
 
+(defvar ediff-backup-extension 
+  (if (memq system-type '(vax-vms axp-vms emx ms-dos windows-nt windows-95))
+      "_orig" ".orig")
+  "Default backup extension for the patch program.")
+
 ;;;###autoload
 (defun ediff-patch-file (source-filename &optional startup-hooks job-name)
   "Run Ediff by patching FILE-TP-PATCH."
   ;; This now returns the control buffer
   (interactive 
-   (list (ediff-read-file-name "File to patch"
-                              (if ediff-use-last-dir
-                                  ediff-last-dir-patch
-                                default-directory)
-                              nil)))
+   (list (ediff-read-file-name
+         "File to patch"
+         (if ediff-use-last-dir
+             ediff-last-dir-patch
+           default-directory)
+         (ediff-get-default-file-name))))
   
   (setq source-filename (expand-file-name source-filename))
   (ediff-get-patch-buffer
@@ -753,7 +152,7 @@ distribution.")
   
   (let* ((backup-extension 
          ;; if the user specified a -b option, extract the backup
-         ;; extension from there; else use `_orig'
+         ;; extension from there; else use ediff-backup-extension
          (substring ediff-patch-options
                     (if (string-match "-b[ \t]+" ediff-patch-options)
                         (match-end 0) 0)
@@ -768,9 +167,10 @@ distribution.")
         (target-filename source-filename)
         target-buf buf-to-patch file-name-magic-p ctl-buf)
          
-    ;; if the user didn't specify a backup extension, use _orig
+    ;; if the user didn't specify a backup extension, use
+    ;; ediff-backup-extension 
     (if (string= backup-extension "")
-       (setq backup-extension "_orig"))
+       (setq backup-extension ediff-backup-extension))
                                        
     ;; Make a temp file, if source-filename has a magic file handler (or if
     ;; it is handled via auto-mode-alist and similar magic).
@@ -792,7 +192,8 @@ distribution.")
        (ediff-toggle-read-only buf-to-patch))
     
     (ediff-eval-in-buffer ediff-patch-diagnostics
-      (message "Applying patch ... ")(sit-for 0)
+      (message "Applying patch ... ")
+      ;;(sit-for 0)
       ;; always pass patch the -f option, so it won't ask any questions
       (shell-command-on-region 
        (point-min) (point-max)
@@ -801,9 +202,9 @@ distribution.")
               backup-extension
               (expand-file-name true-source-filename))
        t))
-    (message "Applying patch ... done")(sit-for 0)
+    ;;(message "Applying patch ... done")(sit-for 0)
     (switch-to-buffer ediff-patch-diagnostics)
-    (sit-for 0) ; synchronize
+    (sit-for 0) ; synchronize - let the user see diagnostics
     
     (or (file-exists-p (concat true-source-filename backup-extension))
        (error "Patch failed or didn't modify the original file"))
@@ -848,7 +249,7 @@ distribution.")
     (setq ctl-buf
          (ediff-buffers-internal
           buf-to-patch target-buf nil
-          startup-hooks '(or job-name ediff-patch-file)))
+          startup-hooks (or job-name 'ediff-patch-file)))
   
     (bury-buffer ediff-patch-diagnostics)
     (message "Patch diagnostics are available in buffer %s"
@@ -860,6 +261,18 @@ distribution.")
   (ediff-eval-in-buffer ediff-buffer-A
     (toggle-read-only 1)))
 
+;; Return a plausible default for ediff's first file:
+;; In dired, return the file name under the point, unless it is a directory
+;; If the buffer has a file name, return that file name.
+(defun ediff-get-default-file-name ()
+  (cond ((eq major-mode 'dired-mode)
+        (let ((f (dired-get-filename nil 'no-error)))
+          (if (and (stringp f) (not (file-directory-p f)))
+              f)))
+       ((buffer-file-name (current-buffer))
+        (file-name-nondirectory (buffer-file-name (current-buffer))))
+       ))
+
 ;;;###autoload
 (defalias 'epatch 'ediff-patch-file)
 ;;;###autoload
@@ -875,7 +288,9 @@ distribution.")
                    ediff-last-dir-A
                  default-directory))
         dir-B f)
-     (list (setq f (ediff-read-file-name "File A to compare" dir-A nil))
+     (list (setq f (ediff-read-file-name
+                   "File A to compare" dir-A 
+                   (ediff-get-default-file-name)))
           (ediff-read-file-name "File B to compare" 
                                 (setq dir-B
                                       (if ediff-use-last-dir
@@ -883,7 +298,7 @@ distribution.")
                                         (file-name-directory f)))
                                 (progn
                                   (setq file-name-history
-                                        (cons (abbreviate-file-name
+                                        (cons (ediff-abbreviate-file-name
                                                (expand-file-name
                                                 (file-name-nondirectory f)
                                                 dir-B))
@@ -907,7 +322,9 @@ distribution.")
                    ediff-last-dir-A
                  default-directory))
         dir-B dir-C f ff)
-     (list (setq f (ediff-read-file-name "File A to compare" dir-A nil))
+     (list (setq f (ediff-read-file-name
+                   "File A to compare" dir-A
+                   (ediff-get-default-file-name)))
           (setq ff (ediff-read-file-name "File B to compare" 
                                          (setq dir-B
                                                (if ediff-use-last-dir
@@ -916,7 +333,7 @@ distribution.")
                                          (progn
                                            (setq file-name-history
                                                  (cons
-                                                  (abbreviate-file-name
+                                                  (ediff-abbreviate-file-name
                                                    (expand-file-name
                                                     (file-name-nondirectory f)
                                                     dir-B))
@@ -928,7 +345,7 @@ distribution.")
                                               (file-name-directory ff)))
                                 (progn
                                   (setq file-name-history
-                                        (cons (abbreviate-file-name
+                                        (cons (ediff-abbreviate-file-name
                                                (expand-file-name
                                                 (file-name-nondirectory ff)
                                                 dir-C))
@@ -963,8 +380,10 @@ deleted."
   (let* ((file (symbol-value file-var))
         (file-magic (find-file-name-handler file 'find-file-noselect))
         (temp-file-name-prefix (file-name-nondirectory file)))
-    (if (not (file-readable-p file))
-       (error "File `%s' does not exist or is not readable" file))
+    (cond ((not (file-readable-p file))
+          (error "File `%s' does not exist or is not readable" file))
+         ((file-directory-p file)
+          (error "File `%s' is a directory" file)))
        
     ;; some of the command, below, require full file name
     (setq file (expand-file-name file))
@@ -981,13 +400,17 @@ deleted."
       (cond (file-magic  ;; file has handler, such as jka-compr-handler or
             ;; ange-ftp-hook-function--arrange for temp file
             (ediff-verify-file-buffer 'magic)
-            (setq file (ediff-make-temp-file temp-file-name-prefix))
+            (setq file
+                  (ediff-make-temp-file
+                   (current-buffer) temp-file-name-prefix))
             (set hooks-var (cons (` (lambda () (delete-file (, file))))
                                  (symbol-value hooks-var))))
            ;; file processed via auto-mode-alist, a la uncompress.el
            ((not (equal (file-truename file)
                         (file-truename (buffer-file-name))))
-            (setq file (ediff-make-temp-file temp-file-name-prefix))
+            (setq file
+                  (ediff-make-temp-file
+                   (current-buffer) temp-file-name-prefix))
             (set hooks-var (cons (` (lambda () (delete-file (, file))))
                                  (symbol-value hooks-var))))
            (t ;; plain file---just check that the file matches the buffer
@@ -996,13 +419,16 @@ deleted."
 
 (defun ediff-files-internal (file-A file-B file-C startup-hooks job-name)
   (let (buf-A buf-B buf-C)
-    (message "Reading file %s ... " file-A)(sit-for 0)
+    (message "Reading file %s ... " file-A)
+    ;;(sit-for 0)
     (ediff-find-file 'file-A 'buf-A 'ediff-last-dir-A 'startup-hooks)
-    (message "Reading file %s ... " file-B)(sit-for 0)
+    (message "Reading file %s ... " file-B)
+    ;;(sit-for 0)
     (ediff-find-file 'file-B 'buf-B 'ediff-last-dir-B 'startup-hooks)
-    (if (and (stringp file-C) (not ediff-merge-job))
+    (if (stringp file-C)
        (progn
-         (message "Reading file %s ... " file-C)(sit-for 0)
+         (message "Reading file %s ... " file-C)
+         ;;(sit-for 0)
          (ediff-find-file
           'file-C 'buf-C
           (if (eq job-name 'ediff-merge-files-with-ancestor)
@@ -1088,16 +514,10 @@ deleted."
     (if (stringp buf-C-file-name)
        (setq buf-C-file-name (file-name-nondirectory buf-C-file-name)))
        
-    ;; these three need to be evaluated in their buffers, since
-    ;; ediff-make-temp-file checks the current buffer when assigning file
-    ;; names
-    (ediff-eval-in-buffer buf-A
-      (setq file-A (ediff-make-temp-file buf-A-file-name)))
-    (ediff-eval-in-buffer buf-B
-      (setq file-B (ediff-make-temp-file buf-B-file-name)))
+    (setq file-A (ediff-make-temp-file buf-A buf-A-file-name))
+    (setq file-B (ediff-make-temp-file buf-B buf-B-file-name))
     (if buf-C-is-alive
-       (ediff-eval-in-buffer buf-C
-         (setq file-C (ediff-make-temp-file buf-C-file-name))))
+       (setq file-C (ediff-make-temp-file buf-C buf-C-file-name)))
          
     (ediff-setup (get-buffer buf-A) file-A
                 (get-buffer buf-B) file-B
@@ -1111,7 +531,264 @@ deleted."
                       startup-hooks)
                 (list (cons 'ediff-job-name job-name))
                 )))
-                
+
+
+;;; Directory and file group operations
+
+;; Get appropriate default name for directory:
+;; If ediff-use-last-dir, use ediff-last-dir-A.
+;; In dired mode, use the directory that is under the point (if any);
+;; otherwise, use default-directory
+(defun ediff-get-default-directory-name ()
+  (cond (ediff-use-last-dir ediff-last-dir-A)
+       ((eq major-mode 'dired-mode)
+        (let ((f (dired-get-filename nil 'noerror)))
+          (if (and (stringp f) (file-directory-p f))
+              f
+            default-directory)))
+       (t default-directory)))
+
+
+;;;###autoload
+(defun ediff-directories (dir1 dir2 regexp)
+  "Run Ediff on a pair of directories, DIR1 and DIR2, comparing files that have
+the same name in both. The third argument, REGEXP, is a regular expression that
+further filters the file names."
+  (interactive
+   (let ((dir-A (ediff-get-default-directory-name))
+        f)
+     (list (setq f (ediff-read-file-name "Directory A to compare" dir-A nil))
+          (ediff-read-file-name "Directory B to compare" 
+                                (if ediff-use-last-dir
+                                    ediff-last-dir-B 
+                                  (ediff-strip-last-dir f))
+                                nil)
+          (read-string "Filter through regular expression: "
+                       nil ediff-filtering-regexp-history)
+          )))
+  (ediff-directories-internal
+   dir1 dir2 nil regexp 'ediff-files 'ediff-directories
+   ))
+
+;;;###autoload
+(defalias 'edirs 'ediff-directories)
+
+
+;;;###autoload
+(defun ediff-directory-revisions (dir1 regexp)
+  "Run Ediff on a directory, DIR1, comparing its files with their revisions.
+The second argument, REGEXP, is a regular expression that filters the file
+names. Only the files that are under revision control are taken into account."
+  (interactive
+   (let ((dir-A (ediff-get-default-directory-name)))
+     (list (ediff-read-file-name
+           "Directory to compare with revision" dir-A nil)
+          (read-string "Filter through regular expression: "
+                       nil ediff-filtering-regexp-history)
+          )))
+  (ediff-directory-revisions-internal
+   dir1 regexp 'ediff-revision 'ediff-directory-revisions
+   ))
+
+;;;###autoload
+(defalias 'edir-revisions 'ediff-directory-revisions)
+
+
+;;;###autoload
+(defun ediff-directories3 (dir1 dir2 dir3 regexp)
+  "Run Ediff on three directories, DIR1, DIR2, and DIR3, comparing files that
+have the same name in all three. The last argument, REGEXP, is a regular
+expression that further filters the file names."
+  (interactive
+   (let ((dir-A (ediff-get-default-directory-name))
+        f)
+     (list (setq f (ediff-read-file-name "Directory A to compare" dir-A nil))
+          (setq f (ediff-read-file-name "Directory B to compare" 
+                                        (if ediff-use-last-dir
+                                            ediff-last-dir-B 
+                                          (ediff-strip-last-dir f))
+                                        nil))
+          (ediff-read-file-name "Directory C to compare" 
+                                (if ediff-use-last-dir
+                                    ediff-last-dir-C 
+                                  (ediff-strip-last-dir f))
+                                nil)
+          (read-string "Filter through regular expression: "
+                       nil ediff-filtering-regexp-history)
+          )))
+  (ediff-directories-internal
+   dir1 dir2 dir3 regexp 'ediff-files3 'ediff-directories3
+   ))
+
+;;;###autoload
+(defalias 'edirs3 'ediff-directories3)
+
+;;;###autoload
+(defun ediff-merge-directories (dir1 dir2 regexp)
+  "Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have
+the same name in both. The third argument, REGEXP, is a regular expression that
+further filters the file names."
+  (interactive
+   (let ((dir-A (ediff-get-default-directory-name))
+        f)
+     (list (setq f (ediff-read-file-name "Directory A to merge" dir-A nil))
+          (ediff-read-file-name "Directory B to merge" 
+                                (if ediff-use-last-dir
+                                    ediff-last-dir-B 
+                                  (ediff-strip-last-dir f))
+                                nil)
+          (read-string "Filter through regular expression: "
+                       nil ediff-filtering-regexp-history)
+          )))
+  (ediff-directories-internal
+   dir1 dir2 nil regexp 'ediff-merge-files 'ediff-merge-directories
+   ))
+
+;;;###autoload
+(defalias 'edirs-merge 'ediff-merge-directories)
+
+;;;###autoload
+(defun ediff-merge-directories-with-ancestor (dir1 dir2 dir3 regexp)
+  "Run Ediff on a pair of directories, DIR1 and DIR2, merging files that have
+the same name in both. The third argument, REGEXP, is a regular expression that
+further filters the file names."
+  (interactive
+   (let ((dir-A (ediff-get-default-directory-name))
+        f)
+     (list (setq f (ediff-read-file-name "Directory A to merge" dir-A nil))
+          (setq f (ediff-read-file-name "Directory B to merge" 
+                                (if ediff-use-last-dir
+                                    ediff-last-dir-B 
+                                  (ediff-strip-last-dir f))
+                                nil))
+          (ediff-read-file-name "Ancestor directory: "
+                                (if ediff-use-last-dir
+                                    ediff-last-dir-C 
+                                  (ediff-strip-last-dir f))
+                                nil)
+          (read-string "Filter through regular expression: "
+                       nil ediff-filtering-regexp-history)
+          )))
+  (ediff-directories-internal
+   dir1 dir2 dir3 regexp
+   'ediff-merge-files-with-ancestor 'ediff-merge-directories-with-ancestor
+   ))
+
+;;;###autoload
+(defun ediff-merge-directory-revisions (dir1 regexp)
+  "Run Ediff on a directory, DIR1, merging its files with their revisions.
+The second argument, REGEXP, is a regular expression that filters the file
+names. Only the files that are under revision control are taken into account."
+  (interactive
+   (let ((dir-A (ediff-get-default-directory-name)))
+     (list (ediff-read-file-name
+           "Directory to merge with revisions" dir-A nil)
+          (read-string "Filter through regular expression: "
+                       nil ediff-filtering-regexp-history)
+          )))
+  (ediff-directory-revisions-internal
+   dir1 regexp 'ediff-merge-revisions 'ediff-merge-directory-revisions
+   ))
+
+;;;###autoload
+(defalias 'edir-merge-revisions 'ediff-merge-directory-revisions)
+
+;;;###autoload
+(defun ediff-merge-directory-revisions-with-ancestor (dir1 regexp)
+  "Run Ediff on a directory, DIR1, merging its files with their revisions and ancestors.
+The second argument, REGEXP, is a regular expression that filters the file
+names. Only the files that are under revision control are taken into account."
+  (interactive
+   (let ((dir-A (ediff-get-default-directory-name)))
+     (list (ediff-read-file-name
+           "Directory to merge with revisions and ancestors" dir-A nil)
+          (read-string "Filter through regular expression: "
+                       nil ediff-filtering-regexp-history)
+          )))
+  (ediff-directory-revisions-internal
+   dir1 regexp 'ediff-merge-revisions-with-ancestor
+   'ediff-merge-directory-revisions-with-ancestor
+   ))
+
+;;;###autoload
+(defalias
+  'edir-merge-revisions-with-ancestor
+  'ediff-merge-directory-revisions-with-ancestor) 
+
+;;;###autoload
+(defalias 'edirs-merge-with-ancestor 'ediff-merge-directories-with-ancestor)
+
+;; Run ediff-action (ediff-files, ediff-merge, ediff-merge-with-ancestors)
+;; on a pair of directories (three directories, in case of ancestor).
+;; The third argument, REGEXP, is a regular expression that further filters the
+;; file names.
+;; JOBNAME is the symbol indicating the meta-job to be performed.
+(defun ediff-directories-internal (dir1 dir2 dir3 regexp 
+                                       action jobname 
+                                       &optional startup-hooks)
+  ;; ediff-read-file-name is set to attach a previously entered file name if
+  ;; the currently entered file is a directory. This code takes care of that.
+  (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1))
+       dir2 (if (file-directory-p dir2) dir2 (file-name-directory dir2)))
+
+  (if (stringp dir3)
+      (setq dir3 (if (file-directory-p dir3) dir3 (file-name-directory dir3))))
+
+  (cond ((string= dir1 dir2)
+        (error "Directories A and B are the same: %s" dir1))
+       ((and (eq jobname 'ediff-directories3)
+             (string= dir1 dir3))
+        (error "Directories A and C are the same: %s" dir1))
+       ((and (eq jobname 'ediff-directories3)
+             (string= dir2 dir3))
+        (error "Directories B and C are the same: %s" dir1)))
+
+  (let (diffs ; var where ediff-intersect-directories returns the diff list
+       file-list meta-buf)
+    (setq file-list (ediff-intersect-directories 
+                    jobname 'diffs regexp dir1 dir2 dir3))
+    (setq startup-hooks
+         ;; this sets various vars in the meta buffer inside
+         ;; ediff-prepare-meta-buffer
+         (cons (` (lambda ()
+                    ;; tell what to do if the user clicks on a session record
+                    (setq ediff-session-action-function (quote (, action)))
+                    ;; set ediff-dir-difference-list 
+                    (setq ediff-dir-difference-list (quote (, diffs)))))
+               startup-hooks))
+    (setq meta-buf (ediff-prepare-meta-buffer 
+                   'ediff-dir-action
+                   file-list
+                   "*Ediff Session Group Panel"
+                   'ediff-redraw-directory-group-buffer
+                   jobname
+                   startup-hooks))
+    (ediff-show-meta-buffer meta-buf)
+    ))
+
+(defun ediff-directory-revisions-internal (dir1 regexp action jobname 
+                                               &optional startup-hooks)
+  (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1)))
+  (let (file-list meta-buf)
+    (setq file-list
+         (ediff-get-directory-files-under-revision jobname regexp dir1))
+    (setq startup-hooks
+         ;; this sets various vars in the meta buffer inside
+         ;; ediff-prepare-meta-buffer
+         (cons (` (lambda ()
+                    ;; tell what to do if the user clicks on a session record
+                    (setq ediff-session-action-function (quote (, action)))
+                    ))
+               startup-hooks))
+    (setq meta-buf (ediff-prepare-meta-buffer 
+                   'ediff-dir-action
+                   file-list
+                   "*Ediff Session Group Panel"
+                   'ediff-redraw-directory-group-buffer
+                   jobname
+                   startup-hooks))
+    (ediff-show-meta-buffer meta-buf)
+    ))
 
 
 ;;; Compare regions and windows
@@ -1297,15 +974,13 @@ Continue anyway? (y/n) "))
     (if word-mode
        (ediff-wordify beg-A end-A buffer-A tmp-buffer)
       (ediff-copy-to-buffer beg-A end-A buffer-A tmp-buffer))
-    (ediff-eval-in-buffer tmp-buffer
-      (setq file-A (ediff-make-temp-file "regA")))
+    (setq file-A (ediff-make-temp-file tmp-buffer "regA"))
     
     ;; make file-B
     (if word-mode
        (ediff-wordify beg-B end-B buffer-B tmp-buffer)
       (ediff-copy-to-buffer beg-B end-B buffer-B tmp-buffer))
-    (ediff-eval-in-buffer tmp-buffer
-      (setq file-B (ediff-make-temp-file "regB")))
+    (setq file-B (ediff-make-temp-file tmp-buffer "regB"))
      
     (setq overl-A (ediff-make-bullet-proof-overlay beg-A end-A buffer-A))
     (setq overl-B (ediff-make-bullet-proof-overlay beg-B end-B buffer-B))
@@ -1341,7 +1016,9 @@ Continue anyway? (y/n) "))
                    ediff-last-dir-A
                  default-directory))
         dir-B f)
-     (list (setq f (ediff-read-file-name "File A to merge" dir-A nil))
+     (list (setq f (ediff-read-file-name
+                   "File A to merge" dir-A
+                   (ediff-get-default-file-name)))
           (ediff-read-file-name "File B to merge" 
                                 (setq dir-B
                                       (if ediff-use-last-dir
@@ -1349,7 +1026,7 @@ Continue anyway? (y/n) "))
                                         (file-name-directory f)))
                                 (progn
                                   (setq file-name-history
-                                        (cons (abbreviate-file-name
+                                        (cons (ediff-abbreviate-file-name
                                                (expand-file-name
                                                 (file-name-nondirectory f)
                                                 dir-B))
@@ -1375,7 +1052,9 @@ Continue anyway? (y/n) "))
                    ediff-last-dir-A
                  default-directory))
         dir-B dir-ancestor f ff)
-     (list (setq f (ediff-read-file-name "File A to merge" dir-A nil))
+     (list (setq f (ediff-read-file-name
+                   "File A to merge" dir-A
+                   (ediff-get-default-file-name)))
           (setq ff (ediff-read-file-name "File B to merge" 
                                          (setq dir-B
                                                (if ediff-use-last-dir
@@ -1384,7 +1063,7 @@ Continue anyway? (y/n) "))
                                          (progn
                                            (setq file-name-history
                                                  (cons
-                                                  (abbreviate-file-name
+                                                  (ediff-abbreviate-file-name
                                                    (expand-file-name
                                                     (file-name-nondirectory f)
                                                     dir-B))
@@ -1397,7 +1076,7 @@ Continue anyway? (y/n) "))
                                         (file-name-directory ff)))
                                 (progn
                                   (setq file-name-history
-                                        (cons (abbreviate-file-name
+                                        (cons (ediff-abbreviate-file-name
                                                (expand-file-name
                                                 (file-name-nondirectory ff)
                                                 dir-ancestor))
@@ -1469,67 +1148,137 @@ Continue anyway? (y/n) "))
       
 
 ;;;###autoload
-(defun ediff-merge-revisions (rev1 rev2 &optional startup-hooks)
+(defun ediff-merge-revisions (&optional file startup-hooks)
   "Run Ediff by merging two revisions of a file.
-The file is the one visited by the current buffer."
-  (interactive
-   "sVersion 1 to merge (default is the latest version): \nsVersion 2 to merge (default is the latest version): ")
+The file is the optional FILE argument or the file visited by the current
+buffer."
+  (interactive)
   (ediff-load-version-control)
-  (let (buf1 buf2)
-    (if (eq ediff-version-control-package 'vc)
-        (progn
+  (if (stringp file) (find-file file))
+  (let (rev1 rev2 buf1 buf2)
+    (setq rev1
+         (read-string
+          (format
+           "Version 1 to merge (default: %s's latest version): "
+           (if (stringp file)
+               (file-name-nondirectory file) "current buffer")))
+         rev2
+         (read-string
+          (format
+           "Version 2 to merge (default: %s): "
+           (if (stringp file)
+               (file-name-nondirectory file) "current buffer"))))
+    (cond ((eq ediff-version-control-package 'vc)
           (save-excursion
             (vc-version-other-window rev1)
             (setq buf1 (current-buffer)))
           (save-excursion
-            (vc-version-other-window rev2)
+            (or (string= rev2 "")
+                (vc-version-other-window rev2))
             (setq buf2 (current-buffer)))
           (setq startup-hooks 
-                (list (` (lambda () 
-                           (delete-file (, (buffer-file-name buf1)))
-                           (delete-file (, (buffer-file-name buf2))))))))
-      (setq buf1 (rcs-ediff-view-revision rev1)
-           buf2 (rcs-ediff-view-revision rev2)))
+                (cons 
+                 (` (lambda () 
+                      (delete-file (, (buffer-file-name buf1)))
+                      (or (, (string= rev2 ""))
+                          (delete-file (, (buffer-file-name buf2))))))
+                 startup-hooks)))
+         ((eq ediff-version-control-package 'rcs)
+          (setq buf1 (rcs-ediff-view-revision rev1)
+                buf2 (if (string= rev2 "")
+                         (current-buffer)
+                       (rcs-ediff-view-revision rev2))))
+         ((eq ediff-version-control-package 'generic-sc)
+          (save-excursion
+            (if (string= rev1 "")
+                (setq rev1 (generic-sc-get-latest-rev)))
+            (sc-visit-previous-revision rev1)
+            (setq buf1 (current-buffer)))
+          (save-excursion
+            (or (string= rev2 "")
+                (sc-visit-previous-revision rev2))
+            (setq buf2 (current-buffer))))
+         ) ; cond
     (ediff-merge-buffers buf1 buf2 startup-hooks 'ediff-merge-revisions)))
     
 
 ;;;###autoload
-(defun ediff-merge-revisions-with-ancestor (rev1
-                                           rev2 ancestor-rev
-                                           &optional startup-hooks)
-  "Run Ediff by merging with ancestor of two revisions of a file.
-The file is the one visited by the current buffer."
-  (interactive
-   "sVersion 1 to merge (default: the latest version): \nsVersion 2 to merge (default: the latest version): \nsAncestor version (default: the latest version): ")
+(defun ediff-merge-revisions-with-ancestor (&optional file startup-hooks)
+  "Run Ediff by merging two revisions of a file with a common ancestor.
+The file is the the optional FILE argument or the file visited by the current
+buffer."
+  (interactive)
   (ediff-load-version-control)
-  (let (buf1 buf2 ancestor-buf)
-    (if (eq ediff-version-control-package 'vc)
-        (progn
+  (if (stringp file) (find-file file))
+  (let (rev1 rev2 ancestor-rev buf1 buf2 ancestor-buf)
+    (setq rev1
+         (read-string
+          (format
+           "Version 1 to merge (default: %s's latest version): "
+           (if (stringp file)
+               (file-name-nondirectory file) "current buffer")))
+         rev2
+         (read-string
+          (format
+           "Version 2 to merge (default: %s): "
+           (if (stringp file)
+               (file-name-nondirectory file) "current buffer")))
+         ancestor-rev
+         (read-string
+          (format
+           "Ancestor version (default: %s): "
+           (if (stringp file)
+               (file-name-nondirectory file) "current buffer"))))
+    (cond ((eq ediff-version-control-package 'vc)
           (save-excursion
             (vc-version-other-window rev1)
             (setq buf1 (current-buffer)))
           (save-excursion
-            (vc-version-other-window rev2)
+            (or (string= rev2 "")
+                (vc-version-other-window rev2))
             (setq buf2 (current-buffer)))
           (save-excursion
-            (vc-version-other-window ancestor-rev)
+            (or (string= ancestor-rev "")
+                (vc-version-other-window ancestor-rev))
             (setq ancestor-buf (current-buffer)))
           (setq startup-hooks 
-                (list (` (lambda () 
-                           (delete-file (, (buffer-file-name buf1)))
-                           (delete-file (, (buffer-file-name buf2)))
-                           (delete-file (, (buffer-file-name ancestor-buf)))
-                           )))))
-      (setq buf1 (rcs-ediff-view-revision rev1)
-           buf2 (rcs-ediff-view-revision rev2)
-           ancestor-buf (rcs-ediff-view-revision ancestor-rev)))
+                (cons
+                 (` (lambda () 
+                      (delete-file (, (buffer-file-name buf1)))
+                      (or (, (string= rev2 ""))
+                          (delete-file (, (buffer-file-name buf2))))
+                      (or (, (string= ancestor-rev ""))
+                          (delete-file (, (buffer-file-name ancestor-buf))))))
+                 startup-hooks)))
+         ((eq ediff-version-control-package 'rcs)
+          (setq buf1 (rcs-ediff-view-revision rev1)
+                buf2 (if (string= rev2 "")
+                         (current-buffer)
+                       (rcs-ediff-view-revision rev2))
+                ancestor-buf (if (string= ancestor-rev "")
+                                 (current-buffer)
+                               (rcs-ediff-view-revision ancestor-rev))))
+         ((eq ediff-version-control-package 'generic-sc)
+          (save-excursion
+            (if (string= rev1 "")
+                (setq rev1 (generic-sc-get-latest-rev)))
+            (sc-visit-previous-revision rev1)
+            (setq buf1 (current-buffer)))
+          (save-excursion
+            (or (string= rev2 "")
+                (sc-visit-previous-revision rev2))
+            (setq buf2 (current-buffer)))
+          (save-excursion
+            (or (string= ancestor-rev "")
+                (sc-visit-previous-revision ancestor-rev))
+            (setq ancestor-buf (current-buffer))))
+         ) ; cond
     (ediff-merge-buffers-with-ancestor
      buf1 buf2 ancestor-buf
      startup-hooks 'ediff-merge-revisions-with-ancestor)))
      
      
 ;;; Apply patch
-          
     
 ;;;###autoload
 (defun ediff-patch-buffer (buffer-name &optional startup-hooks)                  
@@ -1544,7 +1293,7 @@ The file is the one visited by the current buffer."
        (setq file-name file-name-ok)
       (ediff-eval-in-buffer buffer-name
        (setq default-dir default-directory)
-       (setq file-name (ediff-make-temp-file))
+       (setq file-name (ediff-make-temp-file buffer-name))
        (set-visited-file-name file-name)
        (setq buffer-auto-save-file-name nil) ; don't create auto-save file
        (rename-buffer buffer-name) ; don't confuse the user with new buf name
@@ -1597,40 +1346,30 @@ Else, read patch file into a new buffer."
 ;;; Versions Control functions      
       
 ;;;###autoload
-(defun ediff-revision (arg)
-  "Call `vc.el' or `rcs.el' depending on `ediff-version-control-package'.
-Without prefix argument, compares the current buffer with an older version.
-With prefix argument, compares two older versions of the current buffer."
+(defun ediff-revision (&optional file startup-hooks)
+  "Run Ediff by comparing versions of a file.
+The file is an optional FILE argument or the file visited by the current
+buffer. Use `vc.el' or `rcs.el' depending on `ediff-version-control-package'."
+  ;; if buffer is non-nil, use that buffer instead of the current buffer
   (interactive "P")
+  (if (stringp file) (find-file file))
   (let (rev1 rev2)
-    (if arg
-       (setq rev1
-             (read-string
-              "This buffer's version-1 to compare (default: the latest version): ")
-             rev2
-             (read-string "This buffer's version-2 to compare (default: the latest version): "))
-      (setq rev1
-           (read-string "Version to compare the current buffer with (default: the latest version): ")))
+    (setq rev1
+         (read-string
+          (format "Version 1 to compare (default: %s's latest version): "
+                  (if (stringp file)
+                      (file-name-nondirectory file) "current buffer")))
+         rev2
+         (read-string 
+          (format "Version 2 to compare (default: %s): "
+                  (if (stringp file)
+                      (file-name-nondirectory file) "current buffer"))))
     (ediff-load-version-control)
     (funcall
      (intern (format "%S-ediff-internal" ediff-version-control-package))
-     rev1 rev2)
+     rev1 rev2 startup-hooks)
     ))
    
-;; Backward compatibility
-;;;###autoload
-(defun vc-ediff ()
-  (interactive)
-  (beep 1)
-  (with-output-to-temp-buffer ediff-msg-buffer
-    (princ "
-You have invoked an obsolete function `vc-ediff' or `rcs-ediff'.
-Please use `M-x ediff-revision' instead.
-
-Also, please check the variables `ediff-version-control-package'
-and `ediff-revision-key' for customization.")))
-
-(defalias 'rcs-ediff 'vc-ediff)
    
 ;; Test if version control package is loaded and load if not
 ;; Is SILENT is non-nil, don't report error if package is not found.
@@ -1639,43 +1378,36 @@ and `ediff-revision-key' for customization.")))
       (if (locate-library (symbol-name ediff-version-control-package))
          (progn
            (message "") ; kill the message from `locate-library'
-           (require ediff-version-control-package)
-           (if ediff-revision-key
-               (define-key
-                 (cond ((eq ediff-version-control-package 'vc) vc-prefix-map)
-                       ((eq ediff-version-control-package 'rcs) global-map)
-                       (t  global-map))
-                 ediff-revision-key 'ediff-revision)))
+           (require ediff-version-control-package))
        (or silent
            (error "Version control package %S.el not found. Use vc.el instead"
                   ediff-version-control-package)))))
-  
+
       
-(defun vc-ediff-internal (rev1 &optional rev2)
+(defun vc-ediff-internal (rev1 rev2 &optional startup-hooks)
   "Run Ediff on versions of the current buffer.
-If both REV1 and REV2 are given then these two versions are compared.
-If only REV1 is given then the current buffer is compared against version REV1.
+If REV2 is \"\" then compare current buffer with REV1.
 If the current buffer is named `F', the version is named `F.~REV~'.
 If `F.~REV~' already exists, it is used instead of being re-created."
-  (let ((curbuf (current-buffer))
-       (curwind (selected-window))
-       file1 file2
-       rev1buf rev2buf)
-    (vc-version-other-window rev1)
-    (setq rev1buf (current-buffer)
-         file1 (buffer-file-name))
-    (select-window curwind)
-    (if (not (stringp rev2))
-       (setq rev2buf curbuf)
-      (vc-version-other-window rev2)
+  (let (file1 file2 rev1buf rev2buf)
+    (save-excursion
+      (vc-version-other-window rev1)
+      (setq rev1buf (current-buffer)
+           file1 (buffer-file-name)))
+    (save-excursion
+      (or (string= rev2 "")            ; use current buffer
+         (vc-version-other-window rev2))
       (setq rev2buf (current-buffer)
            file2 (buffer-file-name)))
+    (setq startup-hooks
+         (cons (` (lambda ()
+                    (delete-file (, file1))
+                    (or (, (string= rev2 "")) (delete-file (, file2)))
+                    ))
+               startup-hooks))
     (ediff-buffers
      rev1buf rev2buf
-     (list (` (lambda ()
-               (delete-file (, file1))
-               (if (, file2) (delete-file (, file2)))
-               )))
+     startup-hooks
      'ediff-revision)))
     
 (defun rcs-ediff-view-revision (&optional rev)
@@ -1715,160 +1447,41 @@ With prefix argument, prompts for a revision name."
       (erase-buffer))
     buf))
 
-(defun rcs-ediff-internal (rev1 &optional rev2)
-  "Run Ediff on the current buffer, comparing it with previous RCS revision."
-  (let ((rev2buf (if (stringp rev2)
-                    (rcs-ediff-view-revision rev2)
-                  (current-buffer)))
+(defun rcs-ediff-internal (rev1 rev2 &optional startup-hooks)
+  "Run Ediff on versions of the current buffer.
+If REV2 is \"\" then use current buffer."
+  (let ((rev2buf (if (string= rev2 "")
+                    (current-buffer)
+                  (rcs-ediff-view-revision rev2)))
        (rev1buf (rcs-ediff-view-revision rev1)))
        
     ;; rcs.el doesn't create temp version files, so we don't have to delete
     ;; anything in startup hooks to ediff-buffers
-    (ediff-buffers rev1buf rev2buf nil 'ediff-revision)
+    (ediff-buffers rev1buf rev2buf startup-hooks 'ediff-revision)
     ))
 
-;;; Menu bar
+(defun generic-sc-get-latest-rev ()
+  (cond ((eq sc-mode 'CCASE)
+        (eval "main/LATEST"))
+       (t (eval "")))
+  )
 
-;;; This is split in several parts to avoid
-;;; making a line in loaddefs.el that is too long for patch.
-;;; Note that autoload.el currently looks for cookies
-;;; only at top level in the file.
-;;; So I moved these to top level.  But the conditionals on
-;;; purify-flag make these no-ops when you load ediff.
-;;; They only do something in loaddefs.el.
-
-;;;###autoload
-(if purify-flag
-    ;; explicit string-match, as ediff-xemacs-p is not defined at build time
-    (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version)
-       ()
-      (defvar menu-bar-epatch-menu (make-sparse-keymap "Epatch"))
-      (fset 'menu-bar-epatch-menu (symbol-value 'menu-bar-epatch-menu))
-      (defvar menu-bar-ediff-merge-menu (make-sparse-keymap "Ediff merge"))
-      (fset 'menu-bar-ediff-merge-menu 
-           (symbol-value 'menu-bar-ediff-merge-menu))
-      (defvar menu-bar-ediff-menu (make-sparse-keymap "Ediff"))
-      (fset 'menu-bar-ediff-menu (symbol-value 'menu-bar-ediff-menu))
-      ))
-
-;;;   These must be placed in menu-bar.el in Emacs
-;;
-;;      (define-key menu-bar-tools-menu [epatch]
-;;     '("Apply Patch" . menu-bar-epatch-menu))
-;;      (define-key menu-bar-tools-menu [ediff-merge]
-;;     '("Merge" . menu-bar-ediff-merge-menu))
-;;      (define-key menu-bar-tools-menu [ediff]
-;;     '("Compare" . menu-bar-ediff-menu))
-
-
-;;;###autoload
-(if purify-flag
-    ;; explicit string-match, as ediff-xemacs-p is not defined at build time
-    (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version)
-       ()
-      (define-key menu-bar-ediff-menu [ediff-revision]
-       '("File with Revision ..." . ediff-revision))
-      (define-key menu-bar-ediff-menu [separator-ediff-files] '("--"))
-      (define-key menu-bar-ediff-menu [ediff-buffers3]
-       '("Three Buffers ..." . ediff-buffers3))
-      (define-key menu-bar-ediff-menu [ediff-files3]
-       '("Three Files ..." . ediff-files3))
-      (define-key menu-bar-ediff-menu [ediff-buffers]
-       '("Two Buffers ..." . ediff-buffers))
-      (define-key menu-bar-ediff-menu [ediff-files]
-       '("Two Files ..." . ediff-files))
-      ))
-
-;;;###autoload
-(if purify-flag
-    ;; explicit string-match, as ediff-xemacs-p is not defined at build time
-    (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version)
-       ()
-      (define-key menu-bar-ediff-menu [separator-ediff-regions] '("--"))
-      (define-key menu-bar-ediff-menu [ediff-regions-linewise]
-       '("Regions Line-by-line ..." . ediff-regions-linewise))
-      (define-key menu-bar-ediff-menu [ediff-regions-wordwise]
-       '("Regions Word-by-word ..." . ediff-regions-wordwise))
-      (define-key menu-bar-ediff-menu [separator-ediff-windows] '("--"))
-      (define-key menu-bar-ediff-menu [ediff-windows-linewise]
-       '("Windows Line-by-line ..." . ediff-windows-linewise))
-      (define-key menu-bar-ediff-menu [ediff-windows-wordwise]
-       '("Windows Word-by-word ..." . ediff-windows-wordwise))
-      ))
-
-;;;###autoload
-(if purify-flag
-    ;; explicit string-match, as ediff-xemacs-p is not defined at build time
-    (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version)
-       ()
-      (define-key
-       menu-bar-ediff-merge-menu [ediff-merge-revisions-with-ancestor]
-       '("Revisions with Ancestor ..." . ediff-merge-revisions-with-ancestor))
-      (define-key menu-bar-ediff-merge-menu [ediff-merge-revisions]
-       '("Revisions ..." . ediff-merge-revisions))
-      (define-key menu-bar-ediff-merge-menu [separator-ediff-merge] '("--"))
-      (define-key menu-bar-ediff-merge-menu [ediff-merge-buffers-with-ancestor]
-       '("Buffers with Ancestor ..." . ediff-merge-buffers-with-ancestor))
-      (define-key menu-bar-ediff-merge-menu [ediff-merge-buffers]
-       '("Buffers ..." . ediff-merge-buffers))
-      (define-key menu-bar-ediff-merge-menu [ediff-merge-files-with-ancestor]
-       '("Files with Ancestor ..." . ediff-merge-files-with-ancestor))
-      (define-key menu-bar-ediff-merge-menu [ediff-merge-files]
-       '("Files ..." . ediff-merge-files))
-      ))
-      
-;;;###autoload
-(if purify-flag
-    ;; explicit string-match, as ediff-xemacs-p is not defined at build time
-    (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version)
-       ()
-      (define-key menu-bar-epatch-menu [ediff-patch-buffer]
-       '("To a Buffer ..." . ediff-patch-buffer))
-      (define-key menu-bar-epatch-menu [ediff-patch-file]
-       '("To a File ..." . ediff-patch-file))
-      ))
-       
-
-;;;###autoload
-(if purify-flag
-    ;; explicit string-match, as ediff-xemacs-p is not defined at build time
-    (if (string-match "\\(Lucid\\|Xemacs\\)" emacs-version)
-       (progn
-         (defvar ediff-menu
-           '("Compare"
-             ["Two Files ..."  ediff-files t]
-             ["Two Buffers ..." ediff-buffers t]
-             ["Three Files ..."  ediff-files3 t]
-             ["Three Buffers ..." ediff-buffers3 t]
-             "---"
-             ["File with Revision ..."  ediff-revision t]
-             "---"
-             ["Windows Word-by-word ..." ediff-windows-wordwise t]
-             ["Windows Line-by-line ..." ediff-windows-linewise t]
-             "---"
-             ["Regions Word-by-word ..." ediff-regions-wordwise t]
-             ["Regions Line-by-line ..." ediff-regions-linewise t]))
-         (defvar ediff-merge-menu
-           '("Merge"
-             ["Files ..."  ediff-merge-files t]
-             ["Files with Ancestor ..." ediff-merge-files-with-ancestor t]
-             ["Buffers ..."  ediff-merge-buffers t]
-             ["Buffers with Ancestor ..."
-              ediff-merge-buffers-with-ancestor t]
-             "---"
-             ["Revisions ..."  ediff-merge-revisions t]
-             ["Revisions with Ancestor ..."
-              ediff-merge-revisions-with-ancestor t]))
-         (defvar epatch-menu
-           '("Apply Patch"
-             ["To a file ..."  ediff-patch-file t]
-             ["To a buffer ..." ediff-patch-buffer t]))
-         (add-submenu '("Tools") ediff-menu "VC")
-         (add-submenu '("Tools") ediff-merge-menu "VC")
-         (add-submenu '("Tools") epatch-menu "VC")
-         ;; Display a solid horizontal line 
-         (add-menu-button '("Tools") ["---" nil nil] "VC")
-         )))
+(defun generic-sc-ediff-internal (rev1 rev2 &optional startup-hooks)
+  "Run Ediff on versions of the current buffer.
+If REV2 is \"\" then compare current buffer with REV1.
+If the current buffer is named `F', the version is named `F.~REV~'.
+If `F.~REV~' already exists, it is used instead of being re-created."
+  (let (rev1buf rev2buf)
+    (save-excursion
+      (if (or (not rev1) (string= rev1 ""))
+         (setq rev1 (generic-sc-get-latest-rev)))
+      (sc-visit-previous-revision rev1)
+      (setq rev1buf (current-buffer)))
+    (save-excursion
+      (or (string= rev2 "")            ; use current buffer
+         (sc-visit-previous-revision rev2))
+      (setq rev2buf (current-buffer)))
+    (ediff-buffers rev1buf rev2buf startup-hooks 'ediff-revision)))
 
 
 (provide 'ediff)