mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-25 07:28:20 +00:00
1878 lines
69 KiB
EmacsLisp
1878 lines
69 KiB
EmacsLisp
;;; ediff.el --- a comprehensive visual interface to diff & patch
|
||
;;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
|
||
|
||
;; Author: Michael Kifer <kifer@cs.sunysb.edu>
|
||
;; 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")
|
||
|
||
;; This file is part of GNU Emacs.
|
||
|
||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation; either version 2, or (at your option)
|
||
;; any later version.
|
||
|
||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
||
;;; Commentary:
|
||
;; ----------
|
||
|
||
;; Never read that diff output again!
|
||
;; Apply patch selectively, like a pro!
|
||
;; Merge with ease!
|
||
|
||
;; This package provides a convenient way of simultaneous browsing through
|
||
;; the differences between a pair (or a triple) of files or buffers. The
|
||
;; files being compared, file-A, file-B, and file-C (if applicable) are
|
||
;; shown in separate windows (side by side, one above the another, or in
|
||
;; separate frames), and the differences are highlighted as you step
|
||
;; through them. You can also copy difference regions from one buffer to
|
||
;; another (and recover old differences if you change your mind).
|
||
|
||
;; 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
|
||
;; mail buffer, i.e., patches received by mail don't even have to be saved.
|
||
;; Since Ediff lets you copy differences between buffers, you can, in
|
||
;; effect, apply patches selectively (i.e., you can copy a difference
|
||
;; region from file_orig to file, thereby undoing any particular patch that
|
||
;; you don't like).
|
||
|
||
;; Ediff is aware of version control, which lets the user compare
|
||
;; 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.
|
||
|
||
;; 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.
|
||
|
||
|
||
|
||
;;; Compilation
|
||
;; -----------
|
||
;;
|
||
;; When you byte-compile Ediff, you will get some warnings about functions
|
||
;; being undefined. These can be safely ignored.
|
||
;;
|
||
;;; Bugs:
|
||
;; -----
|
||
|
||
;; 1. The undo command doesn't restore deleted regions well. That is, if
|
||
;; you delete all characters in a difference region and then invoke
|
||
;; `undo', the reinstated text will most likely be inserted outside of
|
||
;; what Ediff thinks is the current difference region. (This problem
|
||
;; doesn't seem to exist with XEmacs.)
|
||
;;
|
||
;; If at any point you feel that difference regions are no longer correct,
|
||
;; you can hit '!' to recompute the differences.
|
||
|
||
;; 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
|
||
;; 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
|
||
;; 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@inse.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.
|
||
|
||
|
||
;;; Code:
|
||
|
||
(require 'ediff-init)
|
||
|
||
(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.")
|
||
|
||
(defvar ediff-last-dir-A nil
|
||
"Last directory used by an Ediff command for file-A.")
|
||
(defvar ediff-last-dir-B nil
|
||
"Last directory used by an Ediff command for file-B.")
|
||
(defvar ediff-last-dir-C nil
|
||
"Last directory used by an Ediff command for file-C.")
|
||
(defvar ediff-last-dir-ancestor nil
|
||
"Last directory used by an Ediff command for the ancestor file.")
|
||
(defvar ediff-last-dir-patch nil
|
||
"Last directory used by an Ediff command for file to patch.")
|
||
|
||
;;; Patching
|
||
|
||
;;;###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)))
|
||
|
||
(setq source-filename (expand-file-name source-filename))
|
||
(ediff-get-patch-buffer
|
||
(if (eq job-name 'ediff-patch-buffer)
|
||
(ediff-eval-in-buffer (get-file-buffer source-filename)
|
||
default-directory)
|
||
(file-name-directory source-filename)))
|
||
|
||
(let* ((backup-extension
|
||
;; if the user specified a -b option, extract the backup
|
||
;; extension from there; else use `_orig'
|
||
(substring ediff-patch-options
|
||
(if (string-match "-b[ \t]+" ediff-patch-options)
|
||
(match-end 0) 0)
|
||
(if (string-match "-b[ \t]+[^ \t]+" ediff-patch-options)
|
||
(match-end 0) 0)))
|
||
(shell-file-name ediff-shell)
|
||
;; ediff-find-file may use a temp file to do the patch
|
||
;; so, we save source-filename and true-source-filename as a var
|
||
;; that initially is source-filename but may be changed to a temp
|
||
;; file for the purpose of patching.
|
||
(true-source-filename source-filename)
|
||
(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 (string= backup-extension "")
|
||
(setq backup-extension "_orig"))
|
||
|
||
;; 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.
|
||
(ediff-find-file 'true-source-filename 'buf-to-patch
|
||
'ediff-last-dir-patch 'startup-hooks)
|
||
|
||
;; Check if source file name has triggered black magic, such as file name
|
||
;; handlers or auto mode alist, and make a note of it.
|
||
;; true-source-filename should be either the original name or a
|
||
;; temporary file where we put the after-product of the file handler.
|
||
(setq file-name-magic-p (not (equal (file-truename true-source-filename)
|
||
(file-truename source-filename))))
|
||
|
||
;; Checkout orig file, if necessary, so that the patched file could be
|
||
;; checked back in.
|
||
(if (ediff-file-checked-in-p (buffer-file-name buf-to-patch))
|
||
(ediff-toggle-read-only buf-to-patch))
|
||
|
||
(ediff-eval-in-buffer ediff-patch-diagnostics
|
||
(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)
|
||
(format "%s -f %s -b %s %s"
|
||
ediff-patch-program ediff-patch-options
|
||
backup-extension
|
||
(expand-file-name true-source-filename))
|
||
t))
|
||
(message "Applying patch ... done")(sit-for 0)
|
||
(switch-to-buffer ediff-patch-diagnostics)
|
||
(sit-for 0) ; synchronize
|
||
|
||
(or (file-exists-p (concat true-source-filename backup-extension))
|
||
(error "Patch failed or didn't modify the original file"))
|
||
|
||
;; If black magic is involved, apply patch to a temp copy of the
|
||
;; file. Otherwise, apply patch to the orig copy. If patch is applied
|
||
;; to temp copy, we name the result old-name_patched for local files
|
||
;; and temp-copy_patched for remote files. The orig file name isn't
|
||
;; changed, and the temp copy of the original is later deleted.
|
||
;; Without magic, the original file is renamed (usually into
|
||
;; old-name_orig) and the result of patching will have the same name as
|
||
;; the original.
|
||
(if (not file-name-magic-p)
|
||
(ediff-eval-in-buffer buf-to-patch
|
||
(set-visited-file-name (concat source-filename backup-extension))
|
||
(set-buffer-modified-p nil))
|
||
|
||
;; Black magic in effect.
|
||
;; If orig file was remote, put the patched file in the temp directory.
|
||
;; If orig file is local, put the patched file in the directory of
|
||
;; the orig file.
|
||
(setq target-filename
|
||
(concat
|
||
(if (ediff-file-remote-p (file-truename source-filename))
|
||
true-source-filename
|
||
source-filename)
|
||
"_patched"))
|
||
|
||
(rename-file true-source-filename target-filename t)
|
||
|
||
;; arrange that the temp copy of orig will be deleted
|
||
(rename-file (concat true-source-filename backup-extension)
|
||
true-source-filename t))
|
||
|
||
;; make orig buffer read-only
|
||
(setq startup-hooks
|
||
(cons 'ediff-set-read-only-in-buf-A startup-hooks))
|
||
|
||
;; set up a buf for the patched file
|
||
(setq target-buf (find-file-noselect target-filename))
|
||
|
||
(setq ctl-buf
|
||
(ediff-buffers-internal
|
||
buf-to-patch target-buf nil
|
||
startup-hooks '(or job-name ediff-patch-file)))
|
||
|
||
(bury-buffer ediff-patch-diagnostics)
|
||
(message "Patch diagnostics are available in buffer %s"
|
||
(buffer-name ediff-patch-diagnostics))
|
||
ctl-buf))
|
||
|
||
(defun ediff-set-read-only-in-buf-A ()
|
||
"Used as a startup hook to set `_orig' patch file read-only."
|
||
(ediff-eval-in-buffer ediff-buffer-A
|
||
(toggle-read-only 1)))
|
||
|
||
;;;###autoload
|
||
(defalias 'epatch 'ediff-patch-file)
|
||
;;;###autoload
|
||
(defalias 'epatch-buffer 'ediff-patch-buffer)
|
||
|
||
;;; Compare files/buffers
|
||
|
||
;;;###autoload
|
||
(defun ediff-files (file-A file-B &optional startup-hooks)
|
||
"Run Ediff on a pair of files, FILE-A and FILE-B."
|
||
(interactive
|
||
(let ((dir-A (if ediff-use-last-dir
|
||
ediff-last-dir-A
|
||
default-directory))
|
||
dir-B f)
|
||
(list (setq f (ediff-read-file-name "File A to compare" dir-A nil))
|
||
(ediff-read-file-name "File B to compare"
|
||
(setq dir-B
|
||
(if ediff-use-last-dir
|
||
ediff-last-dir-B
|
||
(file-name-directory f)))
|
||
(progn
|
||
(setq file-name-history
|
||
(cons (abbreviate-file-name
|
||
(expand-file-name
|
||
(file-name-nondirectory f)
|
||
dir-B))
|
||
file-name-history))
|
||
f))
|
||
)))
|
||
(ediff-files-internal file-A
|
||
(if (file-directory-p file-B)
|
||
(expand-file-name
|
||
(file-name-nondirectory file-A) file-B)
|
||
file-B)
|
||
nil ; file-C
|
||
startup-hooks
|
||
'ediff-files))
|
||
|
||
;;;###autoload
|
||
(defun ediff-files3 (file-A file-B file-C &optional startup-hooks)
|
||
"Run Ediff on three files, FILE-A, FILE-B, and FILE-C."
|
||
(interactive
|
||
(let ((dir-A (if ediff-use-last-dir
|
||
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))
|
||
(setq ff (ediff-read-file-name "File B to compare"
|
||
(setq dir-B
|
||
(if ediff-use-last-dir
|
||
ediff-last-dir-B
|
||
(file-name-directory f)))
|
||
(progn
|
||
(setq file-name-history
|
||
(cons
|
||
(abbreviate-file-name
|
||
(expand-file-name
|
||
(file-name-nondirectory f)
|
||
dir-B))
|
||
file-name-history))
|
||
f)))
|
||
(ediff-read-file-name "File C to compare"
|
||
(setq dir-C (if ediff-use-last-dir
|
||
ediff-last-dir-C
|
||
(file-name-directory ff)))
|
||
(progn
|
||
(setq file-name-history
|
||
(cons (abbreviate-file-name
|
||
(expand-file-name
|
||
(file-name-nondirectory ff)
|
||
dir-C))
|
||
file-name-history))
|
||
ff))
|
||
)))
|
||
(ediff-files-internal file-A
|
||
(if (file-directory-p file-B)
|
||
(expand-file-name
|
||
(file-name-nondirectory file-A) file-B)
|
||
file-B)
|
||
(if (file-directory-p file-C)
|
||
(expand-file-name
|
||
(file-name-nondirectory file-A) file-C)
|
||
file-C)
|
||
startup-hooks
|
||
'ediff-files3))
|
||
|
||
;;;###autoload
|
||
(defalias 'ediff3 'ediff-files3)
|
||
|
||
|
||
(defun ediff-find-file (file-var buffer-name &optional last-dir hooks-var)
|
||
"Visit FILE and arrange its buffer to Ediff's liking.
|
||
FILE is actually a variable symbol that must contain a true file name.
|
||
BUFFER-NAME is a variable symbol, which will get the buffer object into which
|
||
FILE is read. LAST-DIR is the directory variable symbol where FILE's
|
||
directory name should be returned. HOOKS is a variable symbol that will be
|
||
assigned the hook to be executed after `ediff-startup' is finished.
|
||
`ediff-find-file' arranges that the temp files it might create will be
|
||
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))
|
||
|
||
;; some of the command, below, require full file name
|
||
(setq file (expand-file-name file))
|
||
|
||
;; Record the directory of the file
|
||
(if last-dir
|
||
(set last-dir (expand-file-name (file-name-directory file))))
|
||
|
||
;; Setup the buffer
|
||
(set buffer-name (find-file-noselect file))
|
||
|
||
(ediff-eval-in-buffer (symbol-value buffer-name)
|
||
(widen) ; Make sure the entire file is seen
|
||
(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))
|
||
(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))
|
||
(set hooks-var (cons (` (lambda () (delete-file (, file))))
|
||
(symbol-value hooks-var))))
|
||
(t ;; plain file---just check that the file matches the buffer
|
||
(ediff-verify-file-buffer))))
|
||
(set file-var file)))
|
||
|
||
(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)
|
||
(ediff-find-file 'file-A 'buf-A 'ediff-last-dir-A 'startup-hooks)
|
||
(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))
|
||
(progn
|
||
(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)
|
||
'ediff-last-dir-ancestor 'ediff-last-dir-C)
|
||
'startup-hooks)))
|
||
(ediff-setup buf-A file-A
|
||
buf-B file-B
|
||
buf-C file-C
|
||
startup-hooks
|
||
(list (cons 'ediff-job-name job-name)))))
|
||
|
||
|
||
;;;###autoload
|
||
(defalias 'ediff 'ediff-files)
|
||
|
||
|
||
;;;###autoload
|
||
(defun ediff-buffers (buffer-A buffer-B &optional startup-hooks job-name)
|
||
"Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B."
|
||
(interactive
|
||
(let (bf)
|
||
(list (setq bf (read-buffer "Buffer A to compare: "
|
||
(ediff-other-buffer "") t))
|
||
(read-buffer "Buffer B to compare: "
|
||
(progn
|
||
;; realign buffers so that two visible bufs will be
|
||
;; at the top
|
||
(save-window-excursion (other-window 1))
|
||
(ediff-other-buffer bf))
|
||
t))))
|
||
|
||
(or job-name (setq job-name 'ediff-buffers))
|
||
(ediff-buffers-internal buffer-A buffer-B nil startup-hooks job-name))
|
||
|
||
;;;###autoload
|
||
(defun ediff-buffers3 (buffer-A buffer-B buffer-C
|
||
&optional startup-hooks job-name)
|
||
"Run Ediff on three buffers, BUFFER-A, BUFFER-B, and BUFFER-C."
|
||
(interactive
|
||
(let (bf bff)
|
||
(list (setq bf (read-buffer "Buffer A to compare: "
|
||
(ediff-other-buffer "") t))
|
||
(setq bff (read-buffer "Buffer B to compare: "
|
||
(progn
|
||
;; realign buffers so that two visible
|
||
;; bufs will be at the top
|
||
(save-window-excursion (other-window 1))
|
||
(ediff-other-buffer bf))
|
||
t))
|
||
(read-buffer "Buffer C to compare: "
|
||
(progn
|
||
;; realign buffers so that three visible
|
||
;; bufs will be at the top
|
||
(save-window-excursion (other-window 1))
|
||
(ediff-other-buffer (list bf bff)))
|
||
t)
|
||
)))
|
||
|
||
(or job-name (setq job-name 'ediff-buffers3))
|
||
(ediff-buffers-internal buffer-A buffer-B buffer-C startup-hooks job-name))
|
||
|
||
|
||
|
||
(defun ediff-buffers-internal (buf-A buf-B buf-C startup-hooks job-name)
|
||
(let* ((buf-A-file-name (buffer-file-name (get-buffer buf-A)))
|
||
(buf-B-file-name (buffer-file-name (get-buffer buf-B)))
|
||
(buf-C-is-alive (ediff-buffer-live-p buf-C))
|
||
(buf-C-file-name (if buf-C-is-alive
|
||
(buffer-file-name (get-buffer buf-B))))
|
||
file-A file-B file-C)
|
||
(if (not (ediff-buffer-live-p buf-A))
|
||
(error "Buffer %S doesn't exist" buf-A))
|
||
(if (not (ediff-buffer-live-p buf-B))
|
||
(error "Buffer %S doesn't exist" buf-B))
|
||
(let ((ediff-job-name job-name))
|
||
(if (and ediff-3way-comparison-job
|
||
(not buf-C-is-alive))
|
||
(error "Buffer %S doesn't exist" buf-C)))
|
||
(if (stringp buf-A-file-name)
|
||
(setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
|
||
(if (stringp buf-B-file-name)
|
||
(setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
|
||
(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)))
|
||
(if buf-C-is-alive
|
||
(ediff-eval-in-buffer buf-C
|
||
(setq file-C (ediff-make-temp-file buf-C-file-name))))
|
||
|
||
(ediff-setup (get-buffer buf-A) file-A
|
||
(get-buffer buf-B) file-B
|
||
(if buf-C-is-alive (get-buffer buf-C))
|
||
file-C
|
||
(cons (` (lambda ()
|
||
(delete-file (, file-A))
|
||
(delete-file (, file-B))
|
||
(if (stringp (, file-C)) (delete-file (, file-C)))
|
||
))
|
||
startup-hooks)
|
||
(list (cons 'ediff-job-name job-name))
|
||
)))
|
||
|
||
|
||
|
||
;;; Compare regions and windows
|
||
|
||
;;;###autoload
|
||
(defun ediff-windows-wordwise (dumb-mode &optional wind-A wind-B startup-hooks)
|
||
"Compare WIND-A and WIND-B, which are selected by clicking, wordwise.
|
||
With prefix argument, DUMB-MODE, or on a non-windowing display, works as
|
||
follows:
|
||
If WIND-A is nil, use selected window.
|
||
If WIND-B is nil, use window next to WIND-A."
|
||
(interactive "P")
|
||
(ediff-windows dumb-mode wind-A wind-B
|
||
startup-hooks 'ediff-windows-wordwise 'word-mode))
|
||
|
||
;;;###autoload
|
||
(defun ediff-windows-linewise (dumb-mode &optional wind-A wind-B startup-hooks)
|
||
"Compare WIND-A and WIND-B, which are selected by clicking, linewise.
|
||
With prefix argument, DUMB-MODE, or on a non-windowing display, works as
|
||
follows:
|
||
If WIND-A is nil, use selected window.
|
||
If WIND-B is nil, use window next to WIND-A."
|
||
(interactive "P")
|
||
(ediff-windows dumb-mode wind-A wind-B
|
||
startup-hooks 'ediff-windows-linewise nil))
|
||
|
||
;; Compare WIND-A and WIND-B, which are selected by clicking.
|
||
;; With prefix argument, DUMB-MODE, or on a non-windowing display,
|
||
;; works as follows:
|
||
;; If WIND-A is nil, use selected window.
|
||
;; If WIND-B is nil, use window next to WIND-A.
|
||
(defun ediff-windows (dumb-mode wind-A wind-B startup-hooks job-name word-mode)
|
||
(if (or dumb-mode (not (ediff-window-display-p)))
|
||
(setq wind-A (ediff-get-next-window wind-A nil)
|
||
wind-B (ediff-get-next-window wind-B wind-A))
|
||
(setq wind-A (ediff-get-window-by-clicking wind-A nil 1)
|
||
wind-B (ediff-get-window-by-clicking wind-B wind-A 2)))
|
||
|
||
(let ((buffer-A (window-buffer wind-A))
|
||
(buffer-B (window-buffer wind-B))
|
||
beg-A end-A beg-B end-B)
|
||
|
||
(save-excursion
|
||
(save-window-excursion
|
||
(sit-for 0) ; synch before using window-start/end -- a precaution
|
||
(select-window wind-A)
|
||
(setq beg-A (window-start)
|
||
end-A (window-end))
|
||
(select-window wind-B)
|
||
(setq beg-B (window-start)
|
||
end-B (window-end))))
|
||
(ediff-regions-internal
|
||
buffer-A beg-A end-A buffer-B beg-B end-B
|
||
startup-hooks job-name word-mode)))
|
||
|
||
;;;###autoload
|
||
(defun ediff-regions-wordwise (buffer-A buffer-B &optional startup-hooks)
|
||
"Run Ediff on a pair of regions in two different buffers.
|
||
Regions \(i.e., point and mark\) are assumed to be set in advance.
|
||
This function is effective only for relatively small regions, up to 200
|
||
lines. For large regions, use `ediff-regions-linewise'."
|
||
(interactive
|
||
(let (bf)
|
||
(list (setq bf (read-buffer "Region's A buffer: "
|
||
(ediff-other-buffer "") t))
|
||
(read-buffer "Region's B buffer: "
|
||
(progn
|
||
;; realign buffers so that two visible bufs will be
|
||
;; at the top
|
||
(save-window-excursion (other-window 1))
|
||
(ediff-other-buffer bf))
|
||
t))))
|
||
(if (not (ediff-buffer-live-p buffer-A))
|
||
(error "Buffer %S doesn't exist" buffer-A))
|
||
(if (not (ediff-buffer-live-p buffer-B))
|
||
(error "Buffer %S doesn't exist" buffer-B))
|
||
|
||
|
||
(let (reg-A-beg reg-A-end reg-B-beg reg-B-end)
|
||
(save-excursion
|
||
(set-buffer buffer-A)
|
||
(setq reg-A-beg (region-beginning)
|
||
reg-A-end (region-end))
|
||
(set-buffer buffer-B)
|
||
(setq reg-B-beg (region-beginning)
|
||
reg-B-end (region-end)))
|
||
|
||
(ediff-regions-internal
|
||
(get-buffer buffer-A) reg-A-beg reg-A-end
|
||
(get-buffer buffer-B) reg-B-beg reg-B-end
|
||
startup-hooks 'ediff-regions-wordwise 'word-mode)))
|
||
|
||
;;;###autoload
|
||
(defun ediff-regions-linewise (buffer-A buffer-B &optional startup-hooks)
|
||
"Run Ediff on a pair of regions in two different buffers.
|
||
Regions \(i.e., point and mark\) are assumed to be set in advance.
|
||
Each region is enlarged to contain full lines.
|
||
This function is effective for large regions, over 100-200
|
||
lines. For small regions, use `ediff-regions-wordwise'."
|
||
(interactive
|
||
(let (bf)
|
||
(list (setq bf (read-buffer "Region A's buffer: "
|
||
(ediff-other-buffer "") t))
|
||
(read-buffer "Region B's buffer: "
|
||
(progn
|
||
;; realign buffers so that two visible bufs will be
|
||
;; at the top
|
||
(save-window-excursion (other-window 1))
|
||
(ediff-other-buffer bf))
|
||
t))))
|
||
(if (not (ediff-buffer-live-p buffer-A))
|
||
(error "Buffer %S doesn't exist" buffer-A))
|
||
(if (not (ediff-buffer-live-p buffer-B))
|
||
(error "Buffer %S doesn't exist" buffer-B))
|
||
|
||
(let (reg-A-beg reg-A-end reg-B-beg reg-B-end)
|
||
(save-excursion
|
||
(set-buffer buffer-A)
|
||
(setq reg-A-beg (region-beginning)
|
||
reg-A-end (region-end))
|
||
;; enlarge the region to hold full lines
|
||
(goto-char reg-A-beg)
|
||
(beginning-of-line)
|
||
(setq reg-A-beg (point))
|
||
(goto-char reg-A-end)
|
||
(end-of-line)
|
||
(or (eobp) (forward-char)) ; include the newline char
|
||
(setq reg-A-end (point))
|
||
|
||
(set-buffer buffer-B)
|
||
(setq reg-B-beg (region-beginning)
|
||
reg-B-end (region-end))
|
||
;; enlarge the region to hold full lines
|
||
(goto-char reg-A-beg)
|
||
(goto-char reg-B-beg)
|
||
(beginning-of-line)
|
||
(setq reg-B-beg (point))
|
||
(goto-char reg-B-end)
|
||
(end-of-line)
|
||
(or (eobp) (forward-char)) ; include the newline char
|
||
(setq reg-B-end (point))
|
||
) ; save excursion
|
||
|
||
(ediff-regions-internal
|
||
(get-buffer buffer-A) reg-A-beg reg-A-end
|
||
(get-buffer buffer-B) reg-B-beg reg-B-end
|
||
startup-hooks 'ediff-regions-linewise nil))) ; no word mode
|
||
|
||
;; compare region beg-A to end-A of buffer-A
|
||
;; to regions beg-B -- end-B in buffer-B.
|
||
(defun ediff-regions-internal (buffer-A beg-A end-A buffer-B beg-B end-B
|
||
startup-hooks job-name word-mode)
|
||
(let ((tmp-buffer (get-buffer-create ediff-tmp-buffer))
|
||
overl-A overl-B
|
||
file-A file-B)
|
||
|
||
;; in case beg/end-A/B aren't markers--make them into markers
|
||
(ediff-eval-in-buffer buffer-A
|
||
(setq beg-A (move-marker (make-marker) beg-A)
|
||
end-A (move-marker (make-marker) end-A)))
|
||
(ediff-eval-in-buffer buffer-B
|
||
(setq beg-B (move-marker (make-marker) beg-B)
|
||
end-B (move-marker (make-marker) end-B)))
|
||
|
||
(if (and (eq buffer-A buffer-B)
|
||
(or (and (< beg-A end-B) (<= beg-B beg-A)) ; b-B b-A e-B
|
||
(and (< beg-B end-A) (<= end-A end-B)))) ; b-B e-A e-B
|
||
(progn
|
||
(with-output-to-temp-buffer ediff-msg-buffer
|
||
(princ "
|
||
You have requested to compare overlapping regions of the same buffer.
|
||
|
||
In this case, Ediff's highlighting may be confusing---in the same window,
|
||
you may see highlighted regions that belong to different regions.
|
||
|
||
Continue anyway? (y/n) "))
|
||
|
||
(if (y-or-n-p "Continue anyway? ")
|
||
()
|
||
(error "%S aborted" job-name))))
|
||
|
||
;; make file-A
|
||
(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")))
|
||
|
||
;; 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 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))
|
||
(ediff-setup buffer-A file-A
|
||
buffer-B file-B
|
||
nil nil ; buffer & file C
|
||
(cons (` (lambda ()
|
||
(delete-file (, file-A))
|
||
(delete-file (, file-B))))
|
||
startup-hooks)
|
||
(list (cons 'ediff-word-mode word-mode)
|
||
(cons 'ediff-narrow-bounds (list overl-A overl-B))
|
||
(cons 'ediff-job-name job-name))
|
||
)
|
||
))
|
||
|
||
|
||
;;; Merge files and buffers
|
||
|
||
;;;###autoload
|
||
(defalias 'ediff-merge 'ediff-merge-files)
|
||
|
||
(defsubst ediff-merge-on-startup ()
|
||
(ediff-do-merge 0)
|
||
(ediff-eval-in-buffer ediff-buffer-C
|
||
(set-buffer-modified-p nil)))
|
||
|
||
;;;###autoload
|
||
(defun ediff-merge-files (file-A file-B &optional startup-hooks)
|
||
"Merge two files without ancestor."
|
||
(interactive
|
||
(let ((dir-A (if ediff-use-last-dir
|
||
ediff-last-dir-A
|
||
default-directory))
|
||
dir-B f)
|
||
(list (setq f (ediff-read-file-name "File A to merge" dir-A nil))
|
||
(ediff-read-file-name "File B to merge"
|
||
(setq dir-B
|
||
(if ediff-use-last-dir
|
||
ediff-last-dir-B
|
||
(file-name-directory f)))
|
||
(progn
|
||
(setq file-name-history
|
||
(cons (abbreviate-file-name
|
||
(expand-file-name
|
||
(file-name-nondirectory f)
|
||
dir-B))
|
||
file-name-history))
|
||
f))
|
||
)))
|
||
(setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
|
||
(ediff-files-internal file-A
|
||
(if (file-directory-p file-B)
|
||
(expand-file-name
|
||
(file-name-nondirectory file-A) file-B)
|
||
file-B)
|
||
nil ; file-C
|
||
startup-hooks
|
||
'ediff-merge-files))
|
||
|
||
;;;###autoload
|
||
(defun ediff-merge-files-with-ancestor (file-A file-B file-ancestor
|
||
&optional startup-hooks)
|
||
"Merge two files with ancestor."
|
||
(interactive
|
||
(let ((dir-A (if ediff-use-last-dir
|
||
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))
|
||
(setq ff (ediff-read-file-name "File B to merge"
|
||
(setq dir-B
|
||
(if ediff-use-last-dir
|
||
ediff-last-dir-B
|
||
(file-name-directory f)))
|
||
(progn
|
||
(setq file-name-history
|
||
(cons
|
||
(abbreviate-file-name
|
||
(expand-file-name
|
||
(file-name-nondirectory f)
|
||
dir-B))
|
||
file-name-history))
|
||
f)))
|
||
(ediff-read-file-name "Ancestor file"
|
||
(setq dir-ancestor
|
||
(if ediff-use-last-dir
|
||
ediff-last-dir-ancestor
|
||
(file-name-directory ff)))
|
||
(progn
|
||
(setq file-name-history
|
||
(cons (abbreviate-file-name
|
||
(expand-file-name
|
||
(file-name-nondirectory ff)
|
||
dir-ancestor))
|
||
file-name-history))
|
||
ff))
|
||
)))
|
||
(setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
|
||
(ediff-files-internal file-A
|
||
(if (file-directory-p file-B)
|
||
(expand-file-name
|
||
(file-name-nondirectory file-A) file-B)
|
||
file-B)
|
||
file-ancestor
|
||
startup-hooks
|
||
'ediff-merge-files-with-ancestor))
|
||
|
||
;;;###autoload
|
||
(defalias 'ediff-merge-with-ancestor 'ediff-merge-files-with-ancestor)
|
||
|
||
;;;###autoload
|
||
(defun ediff-merge-buffers (buffer-A buffer-B &optional startup-hooks job-name)
|
||
"Merge buffers without ancestor."
|
||
(interactive
|
||
(let (bf)
|
||
(list (setq bf (read-buffer "Buffer A to merge: "
|
||
(ediff-other-buffer "") t))
|
||
(read-buffer "Buffer B to merge: "
|
||
(progn
|
||
;; realign buffers so that two visible bufs will be
|
||
;; at the top
|
||
(save-window-excursion (other-window 1))
|
||
(ediff-other-buffer bf))
|
||
t))))
|
||
|
||
(setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
|
||
(or job-name (setq job-name 'ediff-merge-buffers))
|
||
(ediff-buffers-internal
|
||
buffer-A buffer-B nil startup-hooks job-name))
|
||
|
||
;;;###autoload
|
||
(defun ediff-merge-buffers-with-ancestor (buffer-A
|
||
buffer-B buffer-ancestor
|
||
&optional startup-hooks job-name)
|
||
"Merge buffers with ancestor."
|
||
(interactive
|
||
(let (bf bff)
|
||
(list (setq bf (read-buffer "Buffer A to merge: "
|
||
(ediff-other-buffer "") t))
|
||
(setq bff (read-buffer "Buffer B to merge: "
|
||
(progn
|
||
;; realign buffers so that two visible
|
||
;; bufs will be at the top
|
||
(save-window-excursion (other-window 1))
|
||
(ediff-other-buffer bf))
|
||
t))
|
||
(read-buffer "Ancestor buffer: "
|
||
(progn
|
||
;; realign buffers so that three visible
|
||
;; bufs will be at the top
|
||
(save-window-excursion (other-window 1))
|
||
(ediff-other-buffer (list bf bff)))
|
||
t)
|
||
)))
|
||
|
||
(setq startup-hooks (cons 'ediff-merge-on-startup startup-hooks))
|
||
(or job-name (setq job-name 'ediff-merge-buffers-with-ancestor))
|
||
(ediff-buffers-internal
|
||
buffer-A buffer-B buffer-ancestor startup-hooks job-name))
|
||
|
||
|
||
;;;###autoload
|
||
(defun ediff-merge-revisions (rev1 rev2 &optional 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): ")
|
||
(ediff-load-version-control)
|
||
(let (buf1 buf2)
|
||
(if (eq ediff-version-control-package 'vc)
|
||
(progn
|
||
(save-excursion
|
||
(vc-version-other-window rev1)
|
||
(setq buf1 (current-buffer)))
|
||
(save-excursion
|
||
(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)))
|
||
(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): ")
|
||
(ediff-load-version-control)
|
||
(let (buf1 buf2 ancestor-buf)
|
||
(if (eq ediff-version-control-package 'vc)
|
||
(progn
|
||
(save-excursion
|
||
(vc-version-other-window rev1)
|
||
(setq buf1 (current-buffer)))
|
||
(save-excursion
|
||
(vc-version-other-window rev2)
|
||
(setq buf2 (current-buffer)))
|
||
(save-excursion
|
||
(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)))
|
||
(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)
|
||
"Run Ediff by patching BUFFER-NAME."
|
||
(interactive "bBuffer to patch: ")
|
||
|
||
(let* ((buf-to-patch (get-buffer buffer-name))
|
||
(file-name-ok (if buf-to-patch (buffer-file-name buf-to-patch)))
|
||
(buf-mod-status (buffer-modified-p buf-to-patch))
|
||
default-dir file-name ctl-buf)
|
||
(if file-name-ok
|
||
(setq file-name file-name-ok)
|
||
(ediff-eval-in-buffer buffer-name
|
||
(setq default-dir default-directory)
|
||
(setq file-name (ediff-make-temp-file))
|
||
(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
|
||
(set-buffer-modified-p nil)
|
||
(set-visited-file-modtime) ; sync buffer and temp file
|
||
(setq default-directory default-dir)
|
||
))
|
||
|
||
(setq ctl-buf
|
||
(ediff-patch-file file-name startup-hooks 'ediff-patch-buffer))
|
||
|
||
(if file-name-ok
|
||
()
|
||
(ediff-eval-in-buffer ctl-buf
|
||
(delete-file (buffer-file-name ediff-buffer-A))
|
||
(delete-file (buffer-file-name ediff-buffer-B))
|
||
(ediff-eval-in-buffer ediff-buffer-A
|
||
(if default-dir (setq default-directory default-dir))
|
||
(set-visited-file-name nil)
|
||
(rename-buffer buffer-name)
|
||
(set-buffer-modified-p buf-mod-status))
|
||
(ediff-eval-in-buffer ediff-buffer-B
|
||
(setq buffer-auto-save-file-name nil) ; don't create auto-save file
|
||
(if default-dir (setq default-directory default-dir))
|
||
(set-visited-file-name nil)
|
||
(rename-buffer (ediff-unique-buffer-name
|
||
(concat buffer-name "_patched") ""))
|
||
(set-buffer-modified-p t))))
|
||
))
|
||
|
||
|
||
(defun ediff-get-patch-buffer (dir)
|
||
"Obtain patch buffer. If patch is already in a buffer---use it.
|
||
Else, read patch file into a new buffer."
|
||
(if (y-or-n-p "Is the patch file already in a buffer? ")
|
||
(setq ediff-patch-buf
|
||
(get-buffer (read-buffer "Patch buffer name: " nil t))) ;must match
|
||
(setq ediff-patch-buf
|
||
(find-file-noselect (read-file-name "Patch file name: " dir))))
|
||
|
||
(setq ediff-patch-diagnostics
|
||
(get-buffer-create "*ediff patch diagnostics*"))
|
||
(ediff-eval-in-buffer ediff-patch-diagnostics
|
||
(insert-buffer ediff-patch-buf)))
|
||
|
||
|
||
|
||
|
||
|
||
;;; 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."
|
||
(interactive "P")
|
||
(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): ")))
|
||
(ediff-load-version-control)
|
||
(funcall
|
||
(intern (format "%S-ediff-internal" ediff-version-control-package))
|
||
rev1 rev2)
|
||
))
|
||
|
||
;; 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.
|
||
(defun ediff-load-version-control (&optional silent)
|
||
(or (featurep ediff-version-control-package)
|
||
(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)))
|
||
(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)
|
||
"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 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)
|
||
(setq rev2buf (current-buffer)
|
||
file2 (buffer-file-name)))
|
||
(ediff-buffers
|
||
rev1buf rev2buf
|
||
(list (` (lambda ()
|
||
(delete-file (, file1))
|
||
(if (, file2) (delete-file (, file2)))
|
||
)))
|
||
'ediff-revision)))
|
||
|
||
(defun rcs-ediff-view-revision (&optional rev)
|
||
"View previous RCS revision of current file.
|
||
With prefix argument, prompts for a revision name."
|
||
(interactive (list (if current-prefix-arg
|
||
(read-string "Revision: "))))
|
||
(let* ((filename (buffer-file-name (current-buffer)))
|
||
(switches (append '("-p")
|
||
(if rev (list (concat "-r" rev)) nil)))
|
||
(buff (concat (file-name-nondirectory filename) ".~" rev "~")))
|
||
(message "Working ...")
|
||
(setq filename (expand-file-name filename))
|
||
(with-output-to-temp-buffer buff
|
||
(let ((output-buffer (ediff-rcs-get-output-buffer filename buff)))
|
||
(delete-windows-on output-buffer)
|
||
(save-excursion
|
||
(set-buffer output-buffer)
|
||
(apply 'call-process "co" nil t nil
|
||
;; -q: quiet (no diagnostics)
|
||
(append switches rcs-default-co-switches
|
||
(list "-q" filename)))))
|
||
(message "")
|
||
buff)))
|
||
|
||
(defun ediff-rcs-get-output-buffer (file name)
|
||
;; Get a buffer for RCS output for FILE, make it writable and clean it up.
|
||
;; Optional NAME is name to use instead of `*RCS-output*'.
|
||
;; This is a modified version from rcs.el v1.1. I use it here to make
|
||
;; Ediff immune to changes in rcs.el
|
||
(let* ((default-major-mode 'fundamental-mode) ; no frills!
|
||
(buf (get-buffer-create name)))
|
||
(save-excursion
|
||
(set-buffer buf)
|
||
(setq buffer-read-only nil
|
||
default-directory (file-name-directory (expand-file-name file)))
|
||
(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)))
|
||
(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)
|
||
))
|
||
|
||
;;; 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))
|
||
))
|
||
|
||
;;;###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")
|
||
)))
|
||
|
||
|
||
(provide 'ediff)
|
||
(require 'ediff-util)
|
||
|
||
;;; ediff.el ends here
|