X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/2ef2d89752a6aa9e5be8079ed5e40a2d46d5c9d9..9a71dcfd6de8329e96fa0c756f0f3a632286f9f1:/lisp/ediff.el diff --git a/lisp/ediff.el b/lisp/ediff.el index 08fdfc6e3b..371a024494 100644 --- a/lisp/ediff.el +++ b/lisp/ediff.el @@ -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.47" "The current version of Ediff") +(defconst ediff-date "October 11, 1995" "Date of last update") ;; This file is part of GNU Emacs. @@ -39,6 +39,11 @@ ;; 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 @@ -52,23 +57,20 @@ ;; 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: ;; ----- @@ -83,640 +85,31 @@ ;; 2. On a monochrome display, the repertoire of faces with which to ;; highlight fine differences is limited. By default, Ediff is using -;; underlining. However, if the region is already underlied by some other +;; underlining. However, if the region is already underlined by some other ;; overlays, there is no simple way to temporarily remove that residual ;; underlining. This problem occurs when a buffer is highlighted with ;; 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 .) -;; -;; 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 for the code -;; that led to ediff-highlight-diff. -;; Also, thanks to Kevin Esler for suggestions -;; regarding highlighting differences on X displays.) -;; -;; Added functions to apply patches. -;; (Thanks to Kevin Broadey for this -;; suggestion.) - -;; Fri Feb 4, 1994 - -;; Added mechanism for toggling vertical/horizontal window split. -;; (Inspired by a suggestion from Allan Gottlieb -;; -- 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 -;; .) -;; 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 -;; 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 -;; 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 -;; for coercing Ediff into working under Lemacs.) -;; Added ediff-kill-buffer-carefully and other suggestions by Boris -;; Goldowsky . -;; 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 -;; 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 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 -;; .) 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 for contributing this -;; function.) - -;; Sun Mar 6, 1994 - -;; Added rcs-ediff, an Ediff interface to RCS via rcs.el. (Thanks to -;; Alastair Burt .) -;; Some minor improvements. - -;; Tue March 15, 1994 - -;; Fixed a buglet in defining ediff-current-diff-face-A/B. -;; (Thanks to Job Ganzevoort .) - -;; Tue March 22, 1994 - -;; Fixed a bug with ediffing narrowed buffers, reported by Kevin -;; Broadey . -;; 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 .) -;; -;; 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 -;; ), ediff-shell and -;; ediff-protect-metachars (thanks to Richard Stanton -;; ). 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 ). - -;; 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 ). - -;; 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 -;; ). - -;; 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 .) -;; 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 .) - -;; 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 ). -;; 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 ). -;; 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 , Kevin Broadey -;; , Harald Boegeholz -;; , Jin S. Choi" , -;; Eric Eide , Kevin Esler , Robert -;; Estes , Eric Freudenthal -;; , -;; Job Ganzevoort , Boris Goldowsky -;; , Allan Gottlieb , -;; Xiaoli Huang , Larry Gouge , -;; Karl Heuer , , -;; , David Karr -;; , Norbert Kiesel -;; , Fritz Knabe , -;; Heinz Knutzen , Ken Laprade -;; , Richard Levitte -;; , Martin Maechler , -;; Richard Mlynarik , Chris Murphy -;; , Eyvind Ness , Ray Nickson -;; , Paul Raines , Tibor -;; Polgar , C.S. Roberson , -;; Kevin Rodgers , Sandy Rutherford -;; , Heribert Schuetz , Andy Scott -;; , Axel Seibert -;; , Richard Stallman -;; , Richard Stanton , -;; Ake Stenhoff , -;; Stig , Peter Stout , -;; Raymond Toy , -;; and Ilya Zakharevich -;; 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 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-mult) -(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,14 +167,15 @@ 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). ;; Check if there is a buffer visiting source-filename and if they are in - ;; synch; arrange for the deletion of temp file. + ;; sync; arrange for the deletion of temp file. (ediff-find-file 'true-source-filename 'buf-to-patch 'ediff-last-dir-patch 'startup-hooks) @@ -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 @@ -1156,7 +833,7 @@ If WIND-B is nil, use window next to WIND-A." (save-excursion (save-window-excursion - (sit-for 0) ; synch before using window-start/end -- a precaution + (sit-for 0) ; sync before using window-start/end -- a precaution (select-window wind-A) (setq beg-A (window-start) end-A (window-end)) @@ -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,50 @@ 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 - -;;; 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)) - )) +(defun generic-sc-get-latest-rev () + (cond ((eq sc-mode 'CCASE) + (eval "main/LATEST")) + (t (eval ""))) + ) -;;;###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)) - )) - +(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))) ;;;###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 ediff-version () + "Return string describing the version of Ediff. +When called interactively, displays the version." + (interactive) + (if (interactive-p) + (message (ediff-version)) + (format "Ediff %s of %s" ediff-version ediff-date))) (provide 'ediff)