Mercurial > emacs
changeset 7424:9169ca1bcb95
New version from Kifer.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Tue, 10 May 1994 00:48:00 +0000 |
parents | 4a5d0d109242 |
children | eb4b69bf2d4e |
files | lisp/ediff.el |
diffstat | 1 files changed, 1302 insertions(+), 483 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ediff.el Mon May 09 23:08:26 1994 +0000 +++ b/lisp/ediff.el Tue May 10 00:48:00 1994 +0000 @@ -3,8 +3,8 @@ ;; Author: Michael Kifer <kifer@cs.sunysb.edu> ;; Created: February 2, 1994 -;; Version: 1.31 -;; Keywords: comparing, merging, patching, version control. +;; Version: 1.52 +;; Keywords: tools ;; This file is part of GNU Emacs. @@ -46,23 +46,30 @@ ;; region from file.orig to file, thereby undoing any particular patch that ;; you don't like). -;; This package is based on emerge.el. It uses a few utilities and -;; variables defined there and several other Ediff's functions are -;; adaptations from emerge.el. - -;; Ediff is complimentary to Emerge. While Emerge is better at heavy-duty -;; tasks that involve merging of files, Ediff is by far superior -;; for browsing through files compared via diff and for patching files -;; with patch. Furthermore, I feel that Ediff is more convenient for -;; merging tasks where one of the files is a designated output. This -;; situation arises while patching files or when comparing an old version -;; of a file with a newer version (in such cases, it is often desirable to -;; selectively revert some portions of the new file to its old state). - -;; This version of Ediff is much faster than the previous ones and than -;; Emerge (in Emacs 19.23, Emerge will become much faster as well). -;; The difference in startup time is dramatic for large files with many -;; differences. +;; This package builds upon the ideas borrowed from emerge.el. It is still +;; using half a dozen of functions defined there. Several other Ediff's +;; functions are adaptations from emerge.el. Ediff requires, at least, +;; Version 5 of emerge.el. This version comes with standard distributions +;; of Emacs and Lemacs. Make sure you don't have some stray old copy of +;; Emerge on your load path. + +;; Ediff is complimentary to Emerge. While Emerge is primarily intended +;; for merging of files, Ediff is by far superior for browsing through +;; files compared via diff and for patching files with patch. +;; Furthermore, Ediff is more convenient even for merging, when one of the +;; files is a designated output. This situation arises while patching +;; files or when comparing an old version of a file with a newer version +;; (in such cases, it is often desirable to selectively revert some +;; portions of the new file to its old state). + +;; Ediff also supports version control via vc.el (in the standard +;; distribution of Emacs 19) and rcs.el. The latter is a package written by +;; Sebastian Kremer <sk@thp.Uni-Koeln.DE>, which is available in +;; +;; ftp.cs.buffalo.edu:pub/Emacs/rcs.tar.Z +;; ftp.uni-koeln.de:/pub/gnu/emacs/rcs.tar.Z +;; + ;; Window configuration: ;; ---------------------- @@ -89,7 +96,7 @@ ;; the multi-frame mode. -;; A note to heavy-duty users: +;; To those who like to go where noone has gone before: ;; Ediff lets the user run multiple sessions at once, i.e., you can invoke ;; Ediff on different functions several times in a row, without exiting @@ -112,21 +119,17 @@ ;; have any ASCII Ediff flags in it. (Highlighting with faces is OK.) If ;; flags are not removed, difference overlays won't be set correctly ;; for the second invocation of Ediff. The simplest way to remove ASCII -;; flags from an Ediff buffer is to switch to that buffer and try to insert -;; or delete something. If ASCII flags have been inserted by an Ediff -;; session, Ediff will ignore this first editing operation, but it will -;; remove all flags and notify you that this buffer can now be edited. -;; -;; To rehighlight Ediff buffers, hit 'c' in ediff-control buffer. +;; flags from an Ediff buffer is to hit `h' and thus switch to highlighting +;; with faces (unhighlighting on a dumb terminal). ;;; Remarks: ;; ------- -;; 1. Ediff is unlikely to run under Emacs 18 without some further work. +;; 1. Ediff is heavily dependent on the new features of Emacs 19. +;; It won't run under Emacs 18 at all. ;; 2. If running Lucid Emacs, Ediff requires at least version 19.9. -;; 3. I didn't test Ediff on Emacs versions older than 19.19. -;; 4. The function vc-ediff requires the vc.el version that comes with +;; 3. The function vc-ediff requires the vc.el version that comes with ;; Emacs 19.22. @@ -139,8 +142,9 @@ ;; ediff (alias for ediff-files) ;; ediff-files - compare files ;; ediff-patch-file - patch file then compare -;; epatch (alias for ediff-patch-file) +;; epatch - alias for ediff-patch-file ;; ediff-patch-buffer - patch buffer then compare +;; epatch-buffer - alias for ediff-patch-buffer ;; vc-ediff - compare buffer & version ;; using vc.el package ;; (Emacs 19.22 and up). @@ -156,10 +160,10 @@ ;; (autoload 'ediff-buffers "ediff" "Visual interface to diff" t) ;; (autoload 'ediff "ediff" "Visual interface to diff" t) ;; (autoload 'ediff-files "ediff" "Visual interface to diff" t) -;; (autoload 'ediff-files-remote "ediff" "Visual interface to diff") ;; (autoload 'epatch "ediff" "Visual interface to patch" t) ;; (autoload 'ediff-patch-file "ediff" "Visual interface to patch" t) ;; (autoload 'ediff-patch-buffer "ediff" "Visual interface to patch" t) +;; (autoload 'epatch-buffer "ediff" "Visual interface to patch" t) ;; (autoload 'vc-ediff "ediff" ;; "Interface to diff & version control via vc.el" t) ;; (autoload 'rcs-ediff "ediff" @@ -180,10 +184,28 @@ ;; ;; When you byte-compile Ediff, you will get some warnings about functions ;; being undefined. These can be safely ignored. +;; +;; Important: +;; ========= +;; +;; If you are using advice.el (directly or indirectly, via one of the +;; other packages), Ediff may not compile properly. In this case, you +;; should do: +;; +;; M-x ad-deactivate-all RET +;; +;; M-x byte-compile-file RET ediff.el RET +;; +;; M-x ad-activate-all RET +;; +;; This precaution will not be needed starting with GNU Emacs 19.23 and +;; Lucid Emacs 19.10, due to fixing a bug in advice.el. ;;; Customization: ;; ------------- +;; Hooks: +;; ----- ;; If you don't like the default setting, you can change it through the ;; various variables and hooks. In particular, the following hooks are ;; available: @@ -208,6 +230,8 @@ ;; The hooks in ediff-prepare-buffer-hooks are executed for each Ediff buffer ;; (A and B) right after these buffers are arranged. ;; +;; Highlighting of difference regions +;; ---------------------------------- ;; The second group of Ediff variables that could be changed, if you so ;; wish, is: ;; @@ -218,6 +242,8 @@ ;; ;; ediff-current-diff-face-A ;; ediff-current-diff-face-B +;; ediff-fine-diff-face-A +;; ediff-fine-diff-face-B ;; ediff-even-diff-face-A ;; ediff-even-diff-face-B ;; ediff-odd-diff-face-A @@ -231,12 +257,15 @@ ;; The rest are the faces used to highlight text on X displays. On X ;; displays, Ediff uses ediff-current-diff-face-A and ;; ediff-current-diff-face-B to highlight the current difference regions. +;; The faces ediff-fine-diff-face-A and ediff-fine-diff-face-B +;; are used to show the fine differences between the current differences +;; regions in buffer A and B. ;; Other (non-current) difference regions are displayed in alternating ;; faces: ediff-even/odd-diff-face-A/B. The odd and the even ;; faces are actually identical on monochrome displays, because it is -;; rather poor in what you can do on such a display. So, I chose to use -;; italics to highlight other differences. Any ideas would be welcome. -;; +;; rather poor in what you can do on such a display. So, I chose to use +;; italics to highlight other differences. Any ideas would be welcome. (In +;; Lucid Emacs, the faces are different because it supports pixmaps.) ;; There are two ways to change the default setting for highlighting faces: ;; either change the variables, as in ;; @@ -254,18 +283,27 @@ ;; You may also want to take a look at how the above faces are defined in ;; Ediff. ;; -;; The last pair of variables in this group, +;; The last group of variables in this group, ;; ;; ediff-want-faces -;; ediff-highlight-selected-only +;; ediff-highlight-all-diffs +;; ediff-want-default-menus ;; ;; indicate whether---on a window system---you want differences to be ;; marked using ASCII strings (like on a dumb terminal) or using colors and ;; highlighting. If ediff-want-faces is t, then highlighting with faces is ;; used. Normally, Ediff highlights all differences, but the selected -;; difference is highlighted more visibly. If you prefer that unselected -;; differences won't be highlighted, you can set -;; ediff-highlight-selected-only to t. +;; difference is highlighted more visibly. You can cycle through various +;; modes of highlighting by hitting `h'. By default, Ediff starts in the +;; mode where all difference regions are highlighted. If you prefer to +;; start in the mode where unselected differences are not highlighted, you +;; should set ediff-highlight-all-diffs to nil. +;; You will still be able to turn on highlighting of all differences by +;; hitting `h'. +;; The variable `ediff-want-default-menus', if true, will cause Ediff to +;; set up a pair of menues in the menu bar, so you can invoke it from there. +;; If you don't like the look of the default menus, set this variable to +;; nil and design your own menus. ;; ;; If you plan on changing these variables, they must be set ;; BEFORE ediff.el is loaded. @@ -276,7 +314,51 @@ ;; effect only on a window system. On a dumb terminal or in an xterm ;; window, the only available option is highlighting with ASCII flags. ;; -;; The third group of variables controls miscellaneous functions: +;; Refining difference regions +;; --------------------------- +;; There are also variables that control the way fine differences are +;; highlighted. This feature lets the user highlight the exact words that +;; make the difference regions in buffer A and B different. This process +;; ignores spaces, tabs, and newlines. +;; +;; ediff-auto-refine +;; ediff-auto-refine-limit +;; +;; By default, `ediff-auto-refine' is `'on', which means that fine differences +;; within regions will be highlighted automatically. On a slow system, this +;; feature may be undesirable. In any case, the user can always toggle +;; auto-refining on/off/nix by hitting `@'. When auto-refining is off, fine +;; differences will be shown only for regions for which these differences +;; have been computed and saved before. If auto-refining is nixed, fine +;; differences will not be shown at all. Hitting `*' will compute and +;; display fine differences for the current difference region regardless of +;; whether auto-refining is on, off, or nixed. +;; If auto-refining is on, the variable `ediff-auto-refine-limit' limits +;; the size of the regions to be auto-refined. This variable guards against +;; possible slow-down that may be caused by an extraordinary large +;; difference region. However, the user can always force refining by +;; hitting `*'. +;; +;; ediff-fine-diff-program +;; ediff-fine-diff-options +;; ediff-wordify-function +;; +;; These variables let the user control how fine differences are computed. +;; `ediff-fine-diff-program' is diff, by default. However, you can use +;; any function as long as it produces output consistent with diff. +;; `ediff-wordify-function' is a lisp function that determines how the +;; current difference region is split into words. (Fine diferences are +;; computed by first splitting the current difference region into words and +;; then passing this along to `ediff-fine-diff-program'. For the default +;; wordify function, `ediff-wordify', a word is a string consisting of +;; letters, `-', or `_', or a string consisting of symbols that are neither +;; space, nor a letter.) +;; +;; Patch and diff programs +;; ----------------------- +;; The next group of variables determines the programs to be used for +;; applying patches and for computing the main difference regions (not the +;; fine difference regions): ;; ;; ediff-patch-program ;; ediff-patch-options @@ -295,14 +377,16 @@ ;; The output from diff is found in *ediff-diff* buffer. However, this ;; makes sense only if you also intend to use Ediff to browse through the ;; diff'ed files before sending the patch. This is because diff.el is much -;; faster in yielding the output of diff ;; (Ediff is a big gun, if used +;; faster in yielding the output of diff (Ediff is a big gun, if used ;; for this simple purpose). ;; +;; Miscellaneous +;; ------------- ;; The last set of variables that can be modified is ;; ;; ediff-split-window-function ;; ediff-use-last-dir -;; ediff-nix-help-in-control-buffer +;; ediff-no-help-in-control-buffer ;; ;; ediff-split-window-function controls the way you want the window be ;; split between file-A and file-B. It defaults to vertical split, but you @@ -327,7 +411,7 @@ ;; prompts the user for file names. Otherwise, it will use the ;; directories it had previously used for file-A and file-B. ;; -;; The ediff-nix-help-in-control-buffer, if set to t, makes C-h behave like +;; The ediff-no-help-in-control-buffer, if set to t, makes C-h behave like ;; the DEL key, i.e., it will move you back to the previous difference ;; rather than invoking help. This is useful when, in an xterm window or on ;; a dumb terminal, the Backspace key is bound to C-h and is positioned @@ -342,11 +426,11 @@ ;; '?' again. ;; ;; Many Ediff commands take numeric prefix arguments. For instance, if you -;; hit a number, n, and then 'j' (ediff-jump-to-difference), Ediff will -;; take you to Nth difference. Hitting a number, n, and then 'ab' +;; hit a number, N, and then 'j' (ediff-jump-to-difference), Ediff will +;; take you to Nth difference. Hitting a number, N, and then 'ab' ;; (ediff-diff-to-diff) will copy Nth difference from buffer A to buffer B. ;; Hitting 'ba' does copying in the other direction. -;; Likewise, a number, n, followed by 'ra' will restore the Nth difference +;; Likewise, a number, N, followed by 'ra' will restore the Nth difference ;; region in buffer A (if it was previously saved as a result of copying ;; from B to A). ;; @@ -388,14 +472,32 @@ ;; 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 reinserted text will most likely be reinserted outside of -;; what Ediff thinks is the current difference region. - -;; 2. You may get an error if your colormap doesn't have the colors requested -;; by Ediff (on a color display). If this happens, you should create your -;; own faces using available colors. See `ediff-current-diff-face-A', -;; ediff-current-diff-face-B, ediff-even-diff-face-A, ediff-even-diff-face-B, -;; ediff-odd-diff-face-A, and ediff-odd-diff-face-B to get an idea on how -;; to do this. +;; what Ediff thinks is the current difference region. (This problem +;; doesn't seem to exist with Lucid Emacs.) +;; +;; If at any point you feel that difference regions are no longer correct, +;; you can hit '!' to recompute the differences. + +;; 2. Emacs 19.xx, where xx < 23, has several bugs related to overlays and +;; faces. Somethimes, these may cause highlighting of the refinements or +;; of the unselected differences to disappear. Hitting `!' will bring them +;; back. In version 19.23, these problems no longer occur. + +;; 3. 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. + +;; 4. In Lucid Emacs (statically linked with Motif libraries), emerge.el +;; and hence ediff.el won't start, unless you set (setq scrollbar-width 0). +;; This is a Motif-related bug, I was told. ;;; Change Log: @@ -582,20 +684,144 @@ ;; Added commands 'ga', 'gb' to jump directly to the closest diff in ;; buffer A and B, respectively. +;; Fri April 11, 1994 + +;; Added `ediff-recompute-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. + +;; Sat April 16, 1994 + +;; 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-leave-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>). + + +;;; Acknowledgements: + +;; Special thanks to Alastair Burt <burt@dfki.uni-kl.de>, Kevin Esler +;; <esler@ch.hp.com>, Kevin Broadey <KevinB@bartley.demon.co.uk>, +;; 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>, irvine@lks.csi.com, jaffe@chipmunk.cita.utoronto.ca, +;; David Karr, <dkarr@nmo.gtegsc.com>, Norbert Kiesel +;; <norbert@i3.informatik.rwth-aachen.de>, Heinz Knutzen +;; <hk@informatik.uni-kiel.d400.de>, Martin Maechler +;; <maechler@stat.math.ethz.ch>, Richard Mlynarik <mly@adoc.xerox.com>, +;; Ray Nickson <nickson@cs.uq.oz.au>, Andy Scott <ascott@pcocd2.intel.com>, +;; Richard Stanton <stanton@haas.berkeley.edu>, for contributing ideas, +;; patches and bug reports. +;; +;; Thanks also to many others who felt obliged to drop a thanks note. + + ;;; Code: -(require 'emerge) ;; Ediff is based on emerge +(require 'emerge) ;; Ediff uses some functions defined in emerge.el ;;; Macros (defmacro ediff-if-lucid () (` (string-match "Lucid" emacs-version))) + (defmacro ediff-odd-p (arg) (` (eq (logand (, arg) 1) 1))) + (defmacro ediff-buffer-live-p (buf) (` (and (, buf) (get-buffer (, buf)) (buffer-name (get-buffer (, buf)))))) +(defmacro ediff-get-buffer (arg) + (` (cond ((eq (, arg) 'A) ediff-A-buffer) + ((eq (, arg) 'B) ediff-B-buffer) + ) + )) + +(defmacro ediff-char-to-buftype (arg) + (` (cond ((eq (, arg) ?a) 'A) + ((eq (, arg) ?b) 'B) + ) + )) + +(defmacro ediff-get-difference (n) + (` (aref ediff-difference-vector (, n)))) + +(defmacro ediff-get-diff-overlay-from-vector (vec buf-type) + (` (aref (, vec) + (cond ((eq (, buf-type) 'A) 0) + ((eq (, buf-type) 'B) 1) + ) + ))) + +(defmacro ediff-get-diff-overlay (n buf-type) + (` (ediff-get-diff-overlay-from-vector + (ediff-get-difference (, n)) + (, buf-type)))) + +(defmacro ediff-get-fine-diff-vector-from-vec (current-diff-vec) + (` (aref (, current-diff-vec) 2))) + +(defmacro ediff-set-fine-diff-vector (n fine-vec) + (` (aset (ediff-get-difference (, n)) 2 (, fine-vec)))) + +(defmacro ediff-get-fine-diff-vector (n) + (` (ediff-get-fine-diff-vector-from-vec (ediff-get-difference (, n))))) + +(defmacro ediff-frame-has-menubar () + (if (ediff-if-lucid) + current-menubar + (< 0 (cdr (assq 'menu-bar-lines (frame-parameters (selected-frame))))) + )) + + +;;; Functions (defun ediff-mode () "Ediff mode is used by the Ediff file-difference package. @@ -606,6 +832,7 @@ `epatch' `ediff-patch-file' `ediff-patch-buffer' + `epatch-buffer' `vc-ediff' `rcs-ediff' or through a non-interactive Emacs Lisp function @@ -618,7 +845,7 @@ (setq major-mode 'ediff-mode) (setq mode-name "Ediff")) -(defvar ediff-version "1.31" +(defvar ediff-version "1.52" "The current version of Ediff.") (defun ediff-version () @@ -633,10 +860,9 @@ ;; Hook variables (defvar ediff-before-setup-windows-hooks nil - "* Hooks to run before Ediff sets its own window config. -This can be used to save the previous window config, which can be -restored by `ediff-quit' or `ediff-suspend'.") - + "*Hooks to run before Ediff sets its own window config. +This can be used to save the previous window config, which can be restored +on ediff-quit or ediff-suspend.") (defvar ediff-startup-hooks nil "*Hooks to run in the control buffer after Ediff has been set up.") (defvar ediff-select-hooks nil @@ -648,9 +874,9 @@ (defvar ediff-load-hooks nil "*Hook run after Ediff is loaded. Can be used to change defaults.") -(defvar ediff-suspend-hooks 'ediff-default-suspend-hook +(defvar ediff-suspend-hooks (list 'ediff-default-suspend-hook) "*Hooks to run in the Ediff control buffer when Ediff is suspended.") -(defvar ediff-quit-hooks 'ediff-default-quit-hook +(defvar ediff-quit-hooks (list 'ediff-default-quit-hook) "*Hooks to run in the Ediff control buffer after finishing Ediff.") (make-variable-buffer-local 'local-write-file-hooks) @@ -659,25 +885,53 @@ ;; Help messages (defconst ediff-help-message-long -"p,DEL - prev diff c - recenter ab - diff A to B l - line numbers -n,SPC - next diff v/V - scroll up/dn ba - diff B to A f - file names - j - jump to diff </> - scroll lt/rt ra - restore A z - suspend Ediff - ga - goto pt in A s - toggle split rb - restore B q - quit Ediff - gb - goto pt in B h - toggle hilit -wa/wb - save buf A/B A/B - toggle read-only buf A/B ? - toggle help") + "p,DEL - prev diff v/V - scroll up/dn * - refine diff ! - recomp diffs +n,SPC - next diff </> - scroll lt/rt ab - diff A to B l - line numbers + j - jump to diff s - toggle split ba - diff B to A f - file names +ga/gb - goto pt in A/B h - toggle hilit ra - restore A z - suspend Ediff + c - recenter @ - toggle refine rb - restore B q - quit Ediff +wa/wb - save buf A/B A/B - toggle read-only in buffers A/B ? - toggle help") (defconst ediff-help-message-short -" ? - toggle help window") + " ? - toggle help window") (defvar ediff-help-message ediff-help-message-long "*The actual help message.") - +;; diff stuff. (defvar ediff-diff-program "diff" "*Name of the program that compares two files.") (defvar ediff-diff-options "" "*Options to pass to `ediff-diff-program'.") +;; Find diff stuff. +(defvar ediff-wordify-function 'ediff-wordify + "*Function to call to split current diff region into separate words.") + +(defvar ediff-fine-diff-program "diff" + "*Name of the program that compares the current diff regions for fine differences. + +This program should produce output in the format of diff. One could +possibly use `spiff' here if appropriate options are set.") + +(defvar ediff-fine-diff-options "" + "*Options to pass to `ediff-fine-diff-program'.") + +(defvar ediff-whitespace " \n\t\j" + "*White space. Used to split strings into words.") + +(defvar ediff-word-1 "a-zA-Z---_`'.?!:" + "*Characters constituting type 1 words. + +Ediff is using a very simple schema for splitting text into words, which is +used to determine fine differences between regions. There are two types of +words. One consists entirely out of characters in `ediff-word-1' and +another out of characters matching `ediff-word-1'.") + +(defvar ediff-word-2 "^a-zA-Z---_`'.?!: \t\n\j" + "*Characters matching this regexp constitute words of type 2. +See `ediff-word-1' for more details.") + ;; Support for patches @@ -686,14 +940,14 @@ (defvar ediff-patch-options "" "*Options to pass to ediff-patch-program.") -(defvar ediff-shell "sh" - "*The shell used to run diff and patch. -If user's .profile or .cshrc files are set up correctly, any shell will do. -However, some people set `$prompt' or other things incorrectly, which -leads to undesirable output messages. These may cause Ediff to fail. -In such a case, set `ediff-shell' to a shell that you are not using or, -better, fix your shell's startup file.") - +(defvar ediff-shell (cond ((eq system-type 'emx) "cmd") ;; OS/2 + (t "sh")) ;; unix + "*The shell used to run diff and patch. If user's .profile or +.cshrc files are set up correctly, any shell will do. However, some people +set $prompt or other things incorrectly, which leads to undesirable output +messages. These may cause Ediff to fail. In such a case, set ediff-shell +to a shell that you are not using or, better, fix your shell's startup file.") + (defvar ediff-diff-ok-lines-regexp "^\\([0-9,]+[acd][0-9,]+$\\|[<>] \\|---\\|Warning:\\)" "*Regexp that matches normal output lines from `ediff-diff-program'. @@ -701,6 +955,13 @@ 'Missing newline' message to be 'normal output.' Lines that do not match are assumed to be error messages.") +(defvar ediff-fine-diff-ok-lines-regexp + "^\\([0-9,]+[acd][0-9,]+$\\|[<>] \\|---\\|Warning:\\)" + "*Regexp that matches normal output lines from `ediff-fine-diff-program'. +This is mostly lifted from Emerge, except that Ediff also considers the +'Missing newline' message to be 'normal output.' +Lines that do not match are assumed to be error messages.") + (defvar ediff-match-diff-line (let ((x "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)")) (concat "^" x "\\([acd]\\)" x "$")) "*Pattern to match lines produced by diff that describe differences.") @@ -714,10 +975,10 @@ ;; Copying diffs betw buffers. (emerge-defvar-local ediff-killed-diffs-alist nil - "A list of killed diffs. + "A list of killed diffs. A diff is saved here if it is replaced by a diff from another buffer. This alist has the form: -\((num (A . diff) (B . diff)) ...), +((num (A . diff) (B . diff)) ...), where A or B parts may be missing.") @@ -725,15 +986,13 @@ (defvar ediff-before-flag-bol ;"vvvvvvvvvvvvvvvv---- ediff ----vvvvvvvvvvvvvvv\n" ">>--->>>\n" - "*Flag placed above the highlighted block of differences. -Must end with newline. Must be set before Ediff is loaded. -nil means use a default flag string.") + "*Flag placed above the highlighted block of differences. +Must end with newline. Must be set before Ediff is loaded.") (defvar ediff-after-flag-bol ;"^^^^^^^^^^^^^^^^---- ediff ----^^^^^^^^^^^^^^^\n" "<<<---<<\n" "*Flag placed below the highlighted block of differences. -Must end with newline. Must be set before Ediff is loaded. -nil means use a default flag string.") +Must end with newline. Must be set before Ediff is loaded.") (defvar ediff-before-flag-mol ">>--->>>" "*Like ediff-before-flag, used when a difference starts in mid-line.") @@ -768,13 +1027,30 @@ and ediff-after-flag. On a non-window system, differences are always highlighted using ASCII flags. -This is not a user option. Can be set either in .emacs or toggled -interactively, using ediff-toggle-hilit.") - -(emerge-defvar-local ediff-highlight-selected-only nil - "If t, only the selected differences are highlighted. -This is not a user option. Can be set either in `.emacs' or toggled -interactively, using `ediff-toggle-hilit'.") +This variable can be set either in .emacs or toggled interactively, using +ediff-toggle-hilit.") + +(emerge-defvar-local ediff-want-default-menus t + "If t, Ediff will set up menus in the menu bar. +This variable must be set before Ediff is loaded. If you don't like the +look of the default menus, set this variable to nil and make your own +menus.") + +(emerge-defvar-local ediff-auto-refine 'on + "If `'on', Ediff auto-highlights fine diffs for the current diff region. +If `off', auto-highlighting is not used. If `'nix', no fine diffs are shown +at all, unless the user force-refines the region by hitting `*'. + +This variable can be set either in .emacs or toggled interactively, using +ediff-toggle-hilit.") + +(emerge-defvar-local ediff-auto-refine-limit 700 + "Auto-refine only those regions that are smaller than this number of bytes.") + +(emerge-defvar-local ediff-highlight-all-diffs t + "If nil, only the selected differences are highlighted. +This variable can be set either in .emacs or toggled interactively, using +ediff-toggle-hilit.") (emerge-defvar-local ediff-highlighting-style nil "A var local to each ediff-control buffer. @@ -795,11 +1071,14 @@ (emerge-defvar-local ediff-control-buffer nil "The control buffer of ediff. ") -(emerge-defvar-local ediff-control-buffer-suffix nil - "The suffix of the control buffer name. ") +;(emerge-defvar-local ediff-control-buffer-suffix nil +; "The suffix of the control buffer name. ") -(defvar ediff-control-window nil +(emerge-defvar-local ediff-control-window nil "The control window.") +(emerge-defvar-local ediff-window-config-saved "" + "Ediff's window configuration. +Used to minimize the need to rearrange windows.") (emerge-defvar-local ediff-A-buffer-values nil @@ -813,11 +1092,11 @@ "Remembers ediff-saved-variables for ediff-B-buffer as they were at setup.") (emerge-defvar-local ediff-difference-vector nil - "Vector of differences between the variants. + "Vector of differences between the variants. Each difference is represented by a vector of two overlays. The first -overlays the difference section in the A buffer and the second -overlays the diff in the B buffer. If a difference section is empty, -the corresponding overlay's endpoints councide. ") +overlays the difference section in the A buffer and the second overlays the +diff in the B buffer. If a difference section is empty, the corresponding +overlay's endpoints coincide. ") (emerge-defvar-local ediff-current-difference -1 "The difference that is currently selected.") @@ -825,10 +1104,13 @@ "Number of differences found.") (emerge-defvar-local ediff-diff-buffer nil - "Buffer containing the output of diff, used by Ediff to step through files.") -(emerge-defvar-local ediff-diff-error-buffer nil - "Buffer containing the output of diff, when diff returns errors.") - + "Buffer containing the output of diff, which is used by Ediff to step +through files.") +(emerge-defvar-local ediff-tmp-buffer nil + "Temporary buffer used for computing fine differences.") +(emerge-defvar-local ediff-error-buffer nil + "Buffer containing the output of diff when diff returns errors.") + (emerge-defvar-local ediff-this-buffer-control-sessions nil "List of ediff-control buffers associated with each buffer A/B.") @@ -869,10 +1151,20 @@ (fset 'ediff-select-frame (symbol-function 'select-screen)) (fset 'ediff-window-frame (symbol-function 'window-screen)) (fset 'ediff-display-color-p (symbol-function 'x-color-display-p)) + (fset 'ediff-valid-color-p (symbol-function 'x-valid-color-name-p)) (fset 'ediff-get-face (symbol-function 'get-face))) (fset 'ediff-window-frame (symbol-function 'window-frame)) (fset 'ediff-select-frame (symbol-function 'select-frame)) (fset 'ediff-display-color-p (symbol-function 'x-display-color-p)) + + ;; This is a temporary fix for OS/2 users + ;; pm-win.el in PM-Emacs should be fixed. + (if (eq window-system 'pm) + (fset 'ediff-valid-color-p + (function (lambda (color) (assoc color pm-color-alist)))) + (fset 'ediff-valid-color-p (symbol-function 'x-color-defined-p)) + ) + (fset 'ediff-get-face (symbol-function 'internal-get-face))) ;; not a window system (fset 'ediff-window-frame (function (lambda (wind) (if wind 1 nil)) )) @@ -883,92 +1175,151 @@ (if (not window-system) () + (defun ediff-set-face (ground face color) + "Sets face foreground/background. If color unavailable, guides the user." + (if (ediff-valid-color-p color) + (if (eq ground 'foreground) + (set-face-foreground face color) + (set-face-background face color)) + (cond ((memq face + '(ediff-current-diff-face-A ediff-current-diff-face-B)) + (copy-face 'highlight face)) + ((memq face + '(ediff-fine-diff-face-A ediff-fine-diff-face-B)) + (copy-face 'secondary-selection face) + (set-face-underline-p face t)) + ((memq face + '(ediff-odd-diff-face-A ediff-odd-diff-face-B + ediff-even-diff-face-A ediff-even-diff-face-B)) + (copy-face 'secondary-selection face))))) + (defvar ediff-current-diff-face-A (progn (make-face 'ediff-current-diff-face-A) - (cond ((ediff-display-color-p) - (set-face-foreground 'ediff-current-diff-face-A "firebrick") - (set-face-background 'ediff-current-diff-face-A "pale green")) - (t - (if (ediff-if-lucid) - (copy-face 'modeline 'ediff-current-diff-face-A) - (copy-face 'highlight 'ediff-current-diff-face-A)) - )) + (or (face-differs-from-default-p 'ediff-current-diff-face-A) + (cond ((ediff-display-color-p) + (ediff-set-face + 'foreground 'ediff-current-diff-face-A "firebrick") + (ediff-set-face + 'background 'ediff-current-diff-face-A "pale green")) + (t + (if (ediff-if-lucid) + (copy-face 'modeline 'ediff-current-diff-face-A) + (copy-face 'highlight 'ediff-current-diff-face-A)) + ))) (ediff-get-face 'ediff-current-diff-face-A)) - "Face for highlighting the currently selected difference in buffer A of -the Ediff display") + "Face for highlighting the selected difference in buffer A.") (defvar ediff-current-diff-face-B (progn (make-face 'ediff-current-diff-face-B) - (cond ((ediff-display-color-p) - (set-face-foreground 'ediff-current-diff-face-B "DarkOrchid") - (set-face-background 'ediff-current-diff-face-B "Yellow")) - (t - (if (ediff-if-lucid) - (copy-face 'modeline 'ediff-current-diff-face-B) - (copy-face 'highlight 'ediff-current-diff-face-B)) - )) + (or (face-differs-from-default-p 'ediff-current-diff-face-B) + (cond ((ediff-display-color-p) + (ediff-set-face + 'foreground 'ediff-current-diff-face-B "DarkOrchid") + (ediff-set-face + 'background 'ediff-current-diff-face-B "Yellow")) + (t + (if (ediff-if-lucid) + (copy-face 'modeline 'ediff-current-diff-face-B) + (copy-face 'highlight 'ediff-current-diff-face-B)) + ))) (ediff-get-face 'ediff-current-diff-face-B)) - "Face for highlighting the currently selected difference in buffer B of -the Ediff display") + "Face for highlighting the selected difference in buffer B.") + + (defvar ediff-fine-diff-face-A + (progn + (make-face 'ediff-fine-diff-face-A) + (or (face-differs-from-default-p 'ediff-fine-diff-face-A) + (cond ((ediff-display-color-p) + (ediff-set-face 'foreground 'ediff-fine-diff-face-A + "Navy") + (ediff-set-face 'background 'ediff-fine-diff-face-A + "sky blue")) + (t (set-face-underline-p 'ediff-fine-diff-face-A t)))) + (ediff-get-face 'ediff-fine-diff-face-A)) + "Face for highlighting the refinement of the selected diff in buffer A.") + + (defvar ediff-fine-diff-face-B + (progn + (make-face 'ediff-fine-diff-face-B) + (or (face-differs-from-default-p 'ediff-fine-diff-face-B) + (cond ((ediff-display-color-p) + (ediff-set-face 'foreground 'ediff-fine-diff-face-B "Black") + (ediff-set-face 'background 'ediff-fine-diff-face-B "cyan")) + (t (set-face-underline-p 'ediff-fine-diff-face-B t)))) + (ediff-get-face 'ediff-fine-diff-face-B)) + "Face for highlighting the refinement of the selected diff in buffer B.") + (defvar ediff-even-diff-face-A (progn (make-face 'ediff-even-diff-face-A) - (cond ((ediff-display-color-p) - (set-face-background 'ediff-even-diff-face-A "light grey")) - (t - (if (ediff-if-lucid) - (progn - (copy-face 'highlight 'ediff-even-diff-face-A) - (invert-face 'ediff-even-diff-face-A)) - (make-face-italic 'ediff-even-diff-face-A)))) + (or (face-differs-from-default-p 'ediff-even-diff-face-A) + (cond ((ediff-display-color-p) + (ediff-set-face + 'foreground 'ediff-even-diff-face-A "black") + (ediff-set-face + 'background 'ediff-even-diff-face-A "light grey")) + (t + (if (ediff-if-lucid) + (progn + (copy-face 'highlight 'ediff-even-diff-face-A) + (invert-face 'ediff-even-diff-face-A)) + (copy-face 'italic 'ediff-even-diff-face-A))))) (ediff-get-face 'ediff-even-diff-face-A)) "Face used to highlight even-numbered differences in buffer A.") (defvar ediff-even-diff-face-B (progn (make-face 'ediff-even-diff-face-B) - (cond ((ediff-display-color-p) - (set-face-foreground 'ediff-even-diff-face-B "White") - (set-face-background 'ediff-even-diff-face-B "Gray")) - (t - (if (ediff-if-lucid) - (copy-face 'highlight 'ediff-even-diff-face-B) - (make-face-italic 'ediff-even-diff-face-B)))) + (or (face-differs-from-default-p 'ediff-even-diff-face-B) + (cond ((ediff-display-color-p) + (ediff-set-face + 'foreground 'ediff-even-diff-face-B "White") + (ediff-set-face + 'background 'ediff-even-diff-face-B "Gray")) + (t + (if (ediff-if-lucid) + (copy-face 'highlight 'ediff-even-diff-face-B) + (copy-face 'italic 'ediff-even-diff-face-B))))) (ediff-get-face 'ediff-even-diff-face-B)) "Face used to highlight even-numbered differences in buffer B.") - + (defvar ediff-odd-diff-face-A (progn (make-face 'ediff-odd-diff-face-A) - (cond ((ediff-display-color-p) - (set-face-foreground 'ediff-odd-diff-face-A "White") - (set-face-background 'ediff-odd-diff-face-A "Gray")) - (t - (if (ediff-if-lucid) - (copy-face 'highlight 'ediff-odd-diff-face-A) - (make-face-italic 'ediff-odd-diff-face-A)))) - (ediff-get-face 'ediff-odd-diff-face-A)) + (or (face-differs-from-default-p 'ediff-odd-diff-face-A) + (cond ((ediff-display-color-p) + (ediff-set-face + 'foreground 'ediff-odd-diff-face-A "White") + (ediff-set-face + 'background 'ediff-odd-diff-face-A "Gray")) + (t + (if (ediff-if-lucid) + (copy-face 'highlight 'ediff-odd-diff-face-A) + (copy-face 'italic 'ediff-odd-diff-face-A))))) + (ediff-get-face 'ediff-odd-diff-face-A)) "Face used to highlight odd-numbered differences in buffer A.") (defvar ediff-odd-diff-face-B (progn (make-face 'ediff-odd-diff-face-B) - (cond ((ediff-display-color-p) - (set-face-foreground 'ediff-odd-diff-face-B "Black") - (set-face-background 'ediff-odd-diff-face-B "light grey")) - (t - (if (ediff-if-lucid) - (progn - (copy-face 'highlight 'ediff-odd-diff-face-B) - (invert-face 'ediff-odd-diff-face-B)) - (make-face-italic 'ediff-odd-diff-face-B)))) + (or (face-differs-from-default-p 'ediff-odd-diff-face-B) + (cond ((ediff-display-color-p) + (ediff-set-face + 'foreground 'ediff-odd-diff-face-B "Black") + (ediff-set-face + 'background 'ediff-odd-diff-face-B "light grey")) + (t + (if (ediff-if-lucid) + (progn + (copy-face 'highlight 'ediff-odd-diff-face-B) + (invert-face 'ediff-odd-diff-face-B)) + (copy-face 'italic 'ediff-odd-diff-face-B))))) (ediff-get-face 'ediff-odd-diff-face-B)) "Face used to highlight odd-numbered differences in buffer B.") - - + ;; Create *-var faces. These are the actual faces used to highlight ;; odd-numbered difference regions. ;; They are used as follows: when highlighting is turned on, @@ -984,16 +1335,16 @@ ;; initialize *-var faces (defun ediff-init-var-faces () - (copy-face (if (and ediff-want-faces (null ediff-highlight-selected-only)) + (copy-face (if (and ediff-want-faces ediff-highlight-all-diffs) ediff-even-diff-face-A 'default) 'ediff-even-diff-face-A-var) - (copy-face (if (and ediff-want-faces (null ediff-highlight-selected-only)) + (copy-face (if (and ediff-want-faces ediff-highlight-all-diffs) ediff-even-diff-face-B 'default) 'ediff-even-diff-face-B-var) - (copy-face (if (and ediff-want-faces (null ediff-highlight-selected-only)) + (copy-face (if (and ediff-want-faces ediff-highlight-all-diffs) ediff-odd-diff-face-A 'default) 'ediff-odd-diff-face-A-var) - (copy-face (if (and ediff-want-faces (null ediff-highlight-selected-only)) + (copy-face (if (and ediff-want-faces ediff-highlight-all-diffs) ediff-odd-diff-face-B 'default) 'ediff-odd-diff-face-B-var)) @@ -1009,7 +1360,7 @@ (let ((overlay (if (eq type 'A) 'ediff-current-diff-overlay-A 'ediff-current-diff-overlay-B)) - (buffer (if (eq type 'A) ediff-A-buffer ediff-B-buffer)) + (buffer (ediff-get-buffer type)) (face (if (eq type 'A) (face-name ediff-current-diff-face-A) (face-name ediff-current-diff-face-B)))) @@ -1049,7 +1400,7 @@ (defvar ediff-split-window-function 'split-window-vertically "*The function to split the main window between buffer-A and buffer-B. You can set it to be split horizontally instead of the -default verstical split by setting this variable to +default vertical split by setting this variable to 'split-window-horizontally. You can also have your own function for fancy splits. This variable has no effect when buffer-A and buffer-B are shown in different frames. In this case, Ediff will use those frames to display @@ -1085,6 +1436,11 @@ (defvar ediff-temp-file-mode 384 ; u=rw only "*Mode for Ediff temporary files.") +(emerge-defvar-local ediff-temp-file-A nil + "Temporary file used for refining difference regions in buffer B.") +(emerge-defvar-local ediff-temp-file-B nil + "Temporary file used for refining difference regions in buffer B.") + (defvar ediff-last-dir-A nil "Last directory used by an Ediff command for file-A.") (defvar ediff-last-dir-B nil @@ -1094,6 +1450,64 @@ (defvar ediff-mode-map nil "Local keymap used in Ediff mode.") + +(if (and window-system ediff-want-default-menus (ediff-frame-has-menubar)) + (if (ediff-if-lucid) + (progn ;; Lucid menu bars + (defvar ediff-menu + '("" + ["Between Files ..." ediff-files t] + ["Between Buffers ..." ediff-buffers t] + ["With a Revision via VC ..." vc-ediff t] + ["With a Revision via RCS ..." rcs-ediff t])) + (defvar epatch-menu + '("" + ["To a File ..." ediff-patch-file t] + ["To a Buffer ..." ediff-patch-buffer t])) + (add-menu '("File") "Find Differences" + ediff-menu + "Delete Screen") + (add-menu '("File") "Apply Patch" + epatch-menu + "Delete Screen") + ;; Displays as a solid horizontal line + (add-menu-item '("File") "---" nil nil "Delete Screen") + ) + ;; FSF menu bars +;;;###autoload + (defvar menu-bar-epatch-menu (make-sparse-keymap "menu-bar-epatch-map")) +;;;###autoload + (fset 'menu-bar-epatch-menu (symbol-value 'menu-bar-epatch-menu)) +;;;###autoload + (defvar menu-bar-ediff-menu (make-sparse-keymap "menu-bar-ediff-map")) +;;;###autoload + (fset 'menu-bar-ediff-menu (symbol-value 'menu-bar-ediff-menu)) + +;;;###autoload + (define-key menu-bar-ediff-menu [rcs-ediff] + '("With a Revision via RCS ..." . rcs-ediff)) +;;;###autoload + (define-key menu-bar-ediff-menu [vc-ediff] + '("With a Revision via VC ..." . vc-ediff)) +;;;###autoload + (define-key menu-bar-ediff-menu [ediff-buffers] + '("Between Buffers ..." . ediff-buffers)) +;;;###autoload + (define-key menu-bar-ediff-menu [ediff-files] + '("Between Files ..." . ediff-files)) + +;;;###autoload + (define-key menu-bar-epatch-menu [ediff-patch-buffer] + '("To a Buffer ..." . ediff-patch-buffer)) +;;;###autoload + (define-key menu-bar-epatch-menu [ediff-patch-file] + '("To a File ..." . ediff-patch-file)) + + (define-key menu-bar-file-menu [epatch] + '("Apply Patch" . menu-bar-epatch-menu)) + (define-key menu-bar-file-menu [ediff] + '("Find Differences" . menu-bar-ediff-menu)) + )) (defun ediff-setup-keymap () @@ -1103,7 +1517,7 @@ (define-key ediff-mode-map "p" 'ediff-previous-difference) (define-key ediff-mode-map "\C-?" 'ediff-previous-difference) - (define-key ediff-mode-map "\C-h" (if ediff-nix-help-in-control-buffer + (define-key ediff-mode-map "\C-h" (if ediff-no-help-in-control-buffer 'ediff-previous-difference nil)) (define-key ediff-mode-map "n" 'ediff-next-difference) (define-key ediff-mode-map " " 'ediff-next-difference) @@ -1116,6 +1530,7 @@ (define-key ediff-mode-map "c" 'ediff-recenter) (define-key ediff-mode-map "s" 'ediff-toggle-split) (define-key ediff-mode-map "h" 'ediff-toggle-hilit) + (define-key ediff-mode-map "@" 'ediff-toggle-autorefine) (define-key ediff-mode-map "v" 'ediff-scroll-up) (define-key ediff-mode-map "\C-v" 'ediff-scroll-up) (define-key ediff-mode-map "^" 'ediff-scroll-down) @@ -1126,6 +1541,8 @@ (define-key ediff-mode-map "f" 'ediff-file-names) (define-key ediff-mode-map "l" 'ediff-line-numbers) (define-key ediff-mode-map "?" 'ediff-toggle-help) + (define-key ediff-mode-map "!" 'ediff-recompute-diffs) + (define-key ediff-mode-map "*" 'ediff-make-fine-diffs) (define-key ediff-mode-map "a" nil) (define-key ediff-mode-map "ab" 'ediff-diff-to-diff) (define-key ediff-mode-map "b" nil) @@ -1178,9 +1595,9 @@ (defun ediff-files-internal (file-A file-B &optional startup-hooks) (let (buffer-A buffer-B) - (message "Ediff: Reading file %s ... " file-A)(sit-for .5) + (message "Reading file %s ... " file-A)(sit-for .5) (ediff-find-file file-A 'buffer-A 'ediff-last-dir-A) - (message "Ediff: Reading file %s ... " file-B)(sit-for .5) + (message "Reading file %s ... " file-B)(sit-for .5) (ediff-find-file file-B 'buffer-B 'ediff-last-dir-B) (ediff-setup buffer-A file-A buffer-B file-B startup-hooks))) @@ -1218,15 +1635,17 @@ (setq ediff-A-buffer buffer-A) (setq ediff-B-buffer buffer-B) (setq ediff-control-buffer control-buffer) - (setq ediff-control-buffer-suffix - (if (string-match "<[0-9]*>" control-buffer-name) - (substring control-buffer-name - (match-beginning 0) (match-end 0)) - "<1>")) +; (setq ediff-control-buffer-suffix +; (if (string-match "<[0-9]*>" control-buffer-name) +; (substring control-buffer-name +; (match-beginning 0) (match-end 0)) +; "<1>")) + (setq ediff-error-buffer (get-buffer-create (emerge-unique-buffer-name + "*ediff-errors" "*"))) (ediff-remember-buffer-characteristics t) ;; remember at setup (ediff-set-keys) - (setq ediff-difference-vector (ediff-make-diff-list file-A file-B)) + (setq ediff-difference-vector (ediff-setup-diff-regions file-A file-B)) (setq ediff-number-of-differences (length ediff-difference-vector)) (setq ediff-current-difference -1) (ediff-make-current-diff-overlay 'A) @@ -1264,10 +1683,21 @@ (run-hooks 'startup-hooks 'ediff-startup-hooks) (setq buffer-read-only t))))) -;; Generate the Ediff difference list between two files -(defun ediff-make-diff-list (file-A file-B) - (setq ediff-diff-buffer - (get-buffer-create (emerge-unique-buffer-name "*ediff-diff" "*"))) +;; Generate the difference vector and overlays for the two files +;; With optional arg `refine', create refining difference regions +(defun ediff-setup-diff-regions (file-A file-B + &optional use-old refine-region + diff-program diff-options + diff-ok-lines-regexp) + + (setq diff-program (or diff-program ediff-diff-program) + diff-options (or diff-options ediff-diff-options) + diff-ok-lines-regexp + (or diff-ok-lines-regexp ediff-diff-ok-lines-regexp)) + + (or use-old (setq ediff-diff-buffer + (get-buffer-create + (emerge-unique-buffer-name "*ediff-diff" "*")))) (emerge-eval-in-buffer ediff-diff-buffer (erase-buffer) @@ -1275,27 +1705,35 @@ ;; puts output in another buffer---probably an Emacs bug. (ediff-kill-buffer-carefully "*Shell Command Output*") (let ((shell-file-name ediff-shell)) - (message "Ediff: Computing differences ...")(sit-for .5) + (if refine-region + (message "Refining difference region %d ..." (1+ refine-region)) + (message "Computing differences ...")(sit-for .5)) (shell-command (format "%s %s %s %s" - ediff-diff-program ediff-diff-options - (emerge-protect-metachars file-A) - (emerge-protect-metachars file-B)) + diff-program diff-options + (ediff-protect-metachars file-A) + (ediff-protect-metachars file-B)) t) )) - (ediff-prepare-error-list ediff-diff-ok-lines-regexp) - (message "Ediff: Computing differences ... Done.")(sit-for .5) - (ediff-convert-diffs-to-overlays - ediff-A-buffer ediff-B-buffer - (ediff-extract-diffs ediff-diff-buffer ediff-A-buffer ediff-B-buffer))) + (ediff-prepare-error-list diff-ok-lines-regexp) + (if refine-region + (message "Refining difference region %d ... Done." (1+ refine-region)) + (message "Computing differences ... Done.")(sit-for .5)) + (if refine-region + (ediff-convert-diffs-to-overlays-refine + ediff-A-buffer ediff-B-buffer + (ediff-extract-diffs ediff-diff-buffer) + refine-region) + (ediff-convert-diffs-to-overlays + ediff-A-buffer ediff-B-buffer + (ediff-extract-diffs ediff-diff-buffer ediff-A-buffer ediff-B-buffer))) + ) + (defun ediff-prepare-error-list (ok-regexp) (let ((diff-buff ediff-diff-buffer)) - (setq ediff-diff-error-buffer - (get-buffer-create (emerge-unique-buffer-name - "*ediff-diff-errors" "*"))) (emerge-eval-in-buffer - ediff-diff-error-buffer + ediff-error-buffer (erase-buffer) (insert-buffer diff-buff) (delete-matching-lines ok-regexp)))) @@ -1304,7 +1742,7 @@ ;;;###autoload (defun ediff-patch-file (file-to-patch &optional startup-hooks) - "Run Ediff by patching FILE-TO-PATCH." + "Run Ediff by patching FILE-TP-PATCH." (interactive "fFile to patch: ") (ediff-get-patch-buffer (file-name-directory file-to-patch)) @@ -1324,26 +1762,31 @@ (emerge-eval-in-buffer ediff-patch-diagnostics (let ((shell-file-name ediff-shell)) - (message "Ediff: Applying patch ... ")(sit-for .5) + (message "Applying patch ... ")(sit-for .5) + ;; always pass patch the -f option, so it won't ask any questions (shell-command-on-region (point-min) (point-max) (format "%s %s %s" - ediff-patch-program ediff-patch-options + ediff-patch-program (concat "-f " ediff-patch-options) (expand-file-name file-to-patch)) t) - (message "Ediff: Applying patch ... Done.")(sit-for .5) + (message "Applying patch ... Done.")(sit-for .5) )) (switch-to-buffer ediff-patch-diagnostics) (sit-for 0) ;; synchronize (setq startup-hooks (cons 'ediff-toggle-read-only-A startup-hooks)) - (ediff-files (format "%s.orig" file-to-patch) file-to-patch startup-hooks) + (if (file-exists-p (format "%s.orig" file-to-patch)) + (ediff-files + (format "%s.orig" file-to-patch) file-to-patch startup-hooks) + (error "Patch failed or didn't modify the original file.")) (bury-buffer ediff-patch-diagnostics) (message "Patch diagnostics available in buffer %s." (buffer-name ediff-patch-diagnostics))) (defalias 'epatch 'ediff-patch-file) +(defalias 'epatch-buffer 'ediff-patch-buffer) ;;; Function to start Ediff on files @@ -1362,7 +1805,12 @@ ediff-last-dir-B nil) f f) ))) - (ediff-files-internal file-A file-B 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) + startup-hooks)) (defalias 'ediff 'ediff-files) @@ -1374,28 +1822,22 @@ (defun ediff-buffers (buffer-A buffer-B &optional startup-hooks) "Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B." (interactive "bBuffer A to compare: \nbBuffer B to compare: ") - (let (ediff-file-A ediff-file-B) + (let (file-A file-B) (emerge-eval-in-buffer buffer-A - (setq ediff-file-A - (ediff-make-temp-file - (format ".%s." (file-name-nondirectory (buffer-name))))) - (write-region (point-min) (point-max) ediff-file-A nil 'no-message)) + (setq file-A (ediff-make-temp-file))) (emerge-eval-in-buffer buffer-B - (setq ediff-file-B - (ediff-make-temp-file - (format ".%s." (file-name-nondirectory (buffer-name))))) - (write-region (point-min) (point-max) ediff-file-B nil 'no-message)) - (ediff-setup (get-buffer buffer-A) ediff-file-A - (get-buffer buffer-B) ediff-file-B + (setq file-B (ediff-make-temp-file))) + (ediff-setup (get-buffer buffer-A) file-A + (get-buffer buffer-B) file-B (cons (` (lambda () - (delete-file (, ediff-file-A)) - (delete-file (, ediff-file-B)))) + (delete-file (, file-A)) + (delete-file (, file-B)))) startup-hooks) ))) -;;;###autoload +;;;;###autoload (defun ediff-patch-buffer (buffer-name &optional startup-hooks) "Run Ediff by patching BUFFER-NAME." (interactive "bBuffer to patch: ") @@ -1413,6 +1855,7 @@ ;;;###autoload (defun vc-ediff (rev) +;; Note: this function will work only with Emacs 19.22 and higher. "Run ediff on version REV of the current buffer in another window. 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." @@ -1425,11 +1868,13 @@ (error "The VC package is apparently not installed."))) (let ((newvers (current-buffer)) (oldvers (vc-version-other-window rev))) - (ediff-buffers newvers oldvers) + ;; current-buffer is supposed to contain the old version in another + ;; window + (ediff-buffers newvers (current-buffer)) )) (defun rcs-ediff-view-revision (&optional rev) - "View previous RCS revison of current file. + "View previous RCS revision of current file. With prefix argument, prompts for a revision name." (interactive (list (if current-prefix-arg (read-string "Revision: ")))) @@ -1441,7 +1886,7 @@ (setq filename (expand-file-name filename)) (with-output-to-temp-buffer buff - (let ((output-buffer (rcs-get-output-buffer filename buff))) + (let ((output-buffer (ediff-rcs-get-output-buffer filename buff))) (delete-windows-on output-buffer) (save-excursion (set-buffer output-buffer) @@ -1451,10 +1896,24 @@ (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 mofified 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)) ;;;###autoload (defun rcs-ediff (&optional rev) - "Run Ediff on the current buffer, comparing it with previous RCS revison. + "Run Ediff on the current buffer, comparing it with previous RCS revision. With prefix argument, prompts for revision name." (interactive (list (if current-prefix-arg (read-string "Revision: ")))) @@ -1516,23 +1975,25 @@ ;; all other windows. (if (eq (selected-window) (minibuffer-window)) (other-window 1)) - (delete-other-windows) - (switch-to-buffer control-buffer) - (ediff-refresh-mode-line) + (or (ediff-leave-window-config control-buffer) + (progn + (delete-other-windows) + (switch-to-buffer control-buffer) + (ediff-refresh-mode-line) - (ediff-arrange-buffer buffer-A buffer-B (current-buffer) pos) - (ediff-arrange-buffer buffer-B buffer-A (current-buffer) pos) - ;; ediff-arrange-buffer always leaves in ctl buffer - ;; setup ctl wind if it is not set. - (ediff-setup-control-window) + (ediff-arrange-buffer buffer-A buffer-B (current-buffer) pos) + (ediff-arrange-buffer buffer-B buffer-A (current-buffer) pos) + ;; ediff-arrange-buffer always leaves in ctl buffer + ;; setup ctl wind if it is not set. + (ediff-setup-control-window) - ;; If diff reports errors, display them rather than then compare buffers. - (if (/= 0 (emerge-eval-in-buffer ediff-diff-error-buffer (buffer-size))) - (let ((diff-output-buf ediff-diff-buffer)) - (switch-to-buffer ediff-diff-error-buffer) - (ediff-kill-buffer-carefully control-buffer) - (error "Errors found in diff output. Diff output buffer is %s" - diff-output-buf)))) + ;; If diff reports errors, show them then quit. + (if (/= 0 (emerge-eval-in-buffer ediff-error-buffer (buffer-size))) + (let ((diff-output-buf ediff-diff-buffer)) + (switch-to-buffer ediff-error-buffer) + (ediff-kill-buffer-carefully control-buffer) + (error "Errors found in diff output. Diff output buffer is %s" + diff-output-buf)))))) ;; Arranges goal-buf on the screen. @@ -1592,8 +2053,26 @@ (insert ediff-help-message) (shrink-window-if-larger-than-buffer) (setq ediff-control-window (selected-window)) + (setq ediff-window-config-saved + (format "%S%S%S%S" + ediff-control-window + (get-buffer-window ediff-A-buffer t) + (get-buffer-window ediff-B-buffer t) + ediff-split-window-function)) (goto-char (point-min)) - (skip-chars-forward " \t\n")) + (skip-chars-forward ediff-whitespace)) + +(defun ediff-leave-window-config (control-buf) + (and (eq control-buf (current-buffer)) + (/= (buffer-size) 0) + (emerge-eval-in-buffer + control-buf + (string= ediff-window-config-saved + (format "%S%S%S%S" + (get-buffer-window ediff-control-buffer t) + (get-buffer-window ediff-A-buffer t) + (get-buffer-window ediff-B-buffer t) + ediff-split-window-function))))) ;; Set up the keymap in the control buffer @@ -1613,7 +2092,7 @@ "If buffer is highlighted with ASCII flags, remove highlighting. Arguments, START and END are not used, but are provided because this is required by `before-change-function'." - (let (notify) + (let (rehighlight-key) (save-window-excursion (mapcar (function @@ -1626,13 +2105,48 @@ (ediff-unselect-and-select-difference ediff-current-difference 'unselect-only 'no-recenter) - (setq notify t) + (setq rehighlight-key + (substitute-command-keys "\\[ediff-recenter]")) )))))) ediff-this-buffer-control-sessions) - (if notify - (error "ASCII flags removed. You can edit now. Hit 'c' to rehighlight.")) + (if rehighlight-key + (error + "ASCII flags removed. You can edit now. Hit %S to rehighlight." + rehighlight-key)) ))) - + +(defun ediff-recompute-diffs () + "Recompute difference regions in buffers A and B." + (interactive) + (let ((curr-diff ediff-current-difference) + (point-A (emerge-eval-in-buffer ediff-A-buffer (point))) + (point-B (emerge-eval-in-buffer ediff-B-buffer (point))) + file-A file-B) + (ediff-unselect-and-select-difference -1) + (emerge-eval-in-buffer + ediff-A-buffer + (setq file-A (ediff-make-temp-file))) + (emerge-eval-in-buffer + ediff-B-buffer + (setq file-B (ediff-make-temp-file))) + (ediff-clear-diff-vector ediff-difference-vector 'fine-diffs-also) + (setq ediff-killed-diffs-alist nil) ; saved kills will no longer be valid + ; after recompute + (setq ediff-difference-vector + (ediff-setup-diff-regions file-A file-B 'use-old)) + (setq ediff-number-of-differences (length ediff-difference-vector)) + (delete-file file-A) + (delete-file file-B) + (emerge-eval-in-buffer ediff-A-buffer (goto-char point-A)) + (ediff-jump-to-difference (ediff-diff-at-point 'A)) + (beep 1) + (if (y-or-n-p + "Ediff is around last posn in buff A. Stay (or goto last posn in B)? ") + () + (emerge-eval-in-buffer ediff-B-buffer (goto-char point-B)) + (ediff-jump-to-difference (ediff-diff-at-point 'B))) + (message "") + )) (defun ediff-remember-buffer-characteristics (&optional arg) "Record certain properties of the buffers being compared. @@ -1669,16 +2183,22 @@ B-values)))) -(defun ediff-extract-diffs (diff-buffer A-buffer B-buffer) +;; if optional A-buffer and B-buffer are given, then construct a vector of +;; diff using point values. Otherwise, use line offsets. +(defun ediff-extract-diffs (diff-buffer &optional A-buffer B-buffer) (let (diff-list (a-prev 1) ;; this is needed to set the first diff line correctly (b-prev 1)) - (emerge-eval-in-buffer - A-buffer - (goto-char (point-min))) - (emerge-eval-in-buffer - B-buffer - (goto-char (point-min))) + + (if (and A-buffer B-buffer) + (progn ;; reset point in buffers A and B + (emerge-eval-in-buffer + A-buffer + (goto-char (point-min))) + (emerge-eval-in-buffer + B-buffer + (goto-char (point-min))))) + (emerge-eval-in-buffer diff-buffer (goto-char (point-min)) @@ -1712,31 +2232,43 @@ ;; (string-equal diff-type "c") (setq a-end (1+ a-end) b-end (1+ b-end)))) - ;; convert to relative line numbers - (emerge-eval-in-buffer - A-buffer - (forward-line (- a-begin a-prev)) - (setq a-begin-pt (point)) - (forward-line (- a-end a-begin)) - (setq a-end-pt (point) - a-prev a-end)) - (emerge-eval-in-buffer - B-buffer - (forward-line (- b-begin b-prev)) - (setq b-begin-pt (point)) - (forward-line (- b-end b-begin)) - (setq b-end-pt (point) - b-prev b-end)) - (setq diff-list (nconc diff-list (list (vector a-begin-pt a-end-pt - b-begin-pt b-end-pt)))) - ))) + (if (and A-buffer B-buffer) + (progn ;; computing main diff vector + ;; convert to relative line numbers + (emerge-eval-in-buffer + A-buffer + (forward-line (- a-begin a-prev)) + (setq a-begin-pt (point)) + (forward-line (- a-end a-begin)) + (setq a-end-pt (point) + a-prev a-end)) + (emerge-eval-in-buffer + B-buffer + (forward-line (- b-begin b-prev)) + (setq b-begin-pt (point)) + (forward-line (- b-end b-begin)) + (setq b-end-pt (point) + b-prev b-end)) + (setq diff-list + (nconc diff-list (list (vector a-begin-pt a-end-pt + b-begin-pt b-end-pt))))) + ;; computing refinement vector + (setq diff-list + (nconc diff-list (list (vector (- a-begin a-prev) + (- a-end a-begin) + (- b-begin b-prev) + (- b-end b-begin)))) + a-prev a-end + b-prev b-end)) + + ))) ;; end emerge-eval-in-buffer diff-list )) (defun ediff-convert-diffs-to-overlays (A-buffer B-buffer diff-list) (let* ((current-diff -1) (total-diffs (length diff-list)) - (control-buffer-suffix ediff-control-buffer-suffix) +; (control-buffer-suffix ediff-control-buffer-suffix) diff-overlay-list list-element a-begin a-end b-begin b-end a-overlay b-overlay) @@ -1751,15 +2283,16 @@ ;; place overlays at the appropriate places in the buffers (setq a-overlay (ediff-make-overlay a-begin a-end A-buffer)) - ;; priority of a-overlay and b-overlay should be equal. otherwise it - ;; won't work due to Emacs bug---insert-in-front-hooks will be called + ;; priorities of overlays should be equal in all ediff-control + ;; buffers. otherwise it won't work due to Emacs + ;; bug---insert-in-front-hooks will be called ;; only on behalf of the buffer with higher priority. (ediff-overlay-put a-overlay 'priority ediff-shaded-overlay-priority) (ediff-overlay-put a-overlay 'ediff-diff-num current-diff) (ediff-overlay-put a-overlay 'insert-in-front-hooks '(ediff-insert-in-front)) - (ediff-overlay-put a-overlay - 'ediff-control-buffer control-buffer-suffix) +; (ediff-overlay-put a-overlay +; 'ediff-control-buffer control-buffer-suffix) (ediff-overlay-put a-overlay 'face (if (ediff-odd-p current-diff) ;; odd diff 'ediff-odd-diff-face-A-var @@ -1770,8 +2303,8 @@ (ediff-overlay-put b-overlay 'ediff-diff-num current-diff) (ediff-overlay-put b-overlay 'insert-in-front-hooks '(ediff-insert-in-front)) - (ediff-overlay-put b-overlay - 'ediff-control-buffer control-buffer-suffix) +; (ediff-overlay-put b-overlay +; 'ediff-control-buffer control-buffer-suffix) (ediff-overlay-put b-overlay 'face (if (ediff-odd-p current-diff) ;; odd diff 'ediff-odd-diff-face-B-var @@ -1790,18 +2323,17 @@ ;; record all overlays for this difference (setq diff-overlay-list - (nconc diff-overlay-list (list (vector a-overlay b-overlay))) + (nconc diff-overlay-list (list (vector a-overlay b-overlay nil))) diff-list (cdr diff-list)) - (message "Ediff: Processing diff region %d of %d" + (message "Processing diff region %d of %d" current-diff total-diffs) ) ;; while ;; this is just to avoid confusing the user with diff num < total-diffs - (message "Ediff: Processing diff region %d of %d" + (message "Processing diff region %d of %d" (1+ current-diff) total-diffs) ;; convert the list of difference information into a vector for ;; fast access - (setq ediff-difference-vector - (apply 'vector diff-overlay-list)))) + (apply 'vector diff-overlay-list))) @@ -1871,7 +2403,7 @@ (if (eq ediff-split-window-function 'split-window-vertically) 'split-window-horizontally 'split-window-vertically)) - (message "Buffers A and B are residing in different frames. Why split?")) + (message "No splitting: Buffers A and B are in different frames.")) (ediff-recenter 'no-rehighlight))) (defun ediff-toggle-hilit () @@ -1890,18 +2422,18 @@ (ediff-unselect-and-select-difference ediff-current-difference 'unselect-only) ;; cycle through highlighting - (cond ((and ediff-want-faces (null ediff-highlight-selected-only)) - (message "Ediff: Unhighlighted unselected difference regions.") - (setq ediff-highlight-selected-only t)) + (cond ((and ediff-want-faces ediff-highlight-all-diffs) + (message "Unhighlighting unselected difference regions.") + (setq ediff-highlight-all-diffs nil)) (ediff-want-faces - (message "Ediff: Now using ASCII flags only.") + (message "Highlighting with ASCII flags.") (setq ediff-want-faces nil)) (t - (message "Ediff: Re-highlighted all difference regions.") + (message "Re-highlighting all difference regions.") (setq ediff-want-faces t - ediff-highlight-selected-only nil))) + ediff-highlight-all-diffs t))) - (if (and ediff-want-faces (null ediff-highlight-selected-only)) + (if (and ediff-want-faces ediff-highlight-all-diffs) (if (not (face-differs-from-default-p 'ediff-odd-diff-face-A-var)) (progn (copy-face ediff-odd-diff-face-A 'ediff-odd-diff-face-A-var) @@ -1918,6 +2450,23 @@ (ediff-operate-on-flags 'insert) ) +(defun ediff-toggle-autorefine () + "Toggle auto-refine mode." + (interactive) + (if window-system + (cond ((eq ediff-auto-refine 'nix) + (setq ediff-auto-refine 'on) + (ediff-make-fine-diffs ediff-current-difference 'noforce) + (message "Auto-refining is ON.")) + ((eq ediff-auto-refine 'on) + (message "Auto-refining is OFF.") + (setq ediff-auto-refine 'off)) + (t + (ediff-set-fine-diff-properties ediff-current-difference 'default) + (message "Refinements are HIDDEN.") + (setq ediff-auto-refine 'nix)) + ))) + (defun ediff-toggle-help () "Toggle short/long help message." (interactive) @@ -1926,6 +2475,7 @@ (if (string= ediff-help-message ediff-help-message-long) (setq ediff-help-message ediff-help-message-short) (setq ediff-help-message ediff-help-message-long))) + (setq ediff-window-config-saved "") ;; force redisplay (ediff-recenter 'no-rehighlight)) @@ -1945,7 +2495,7 @@ ;; These operations are designed to scroll all three windows the same amount, ;; so as to keep the text in them aligned. -;; Perform some operation on two file windows (if they are showing). +;; Perform some operation on the two file windows (if they are showing). ;; Catches all errors on the operation in the A and B windows. ;; Usually, errors come from scrolling off the ;; beginning or end of the buffer, and this gives nice nice error messages. @@ -2077,7 +2627,7 @@ default-amount)))))) (defun ediff-position-region (beg end pos) - "This is a variation on `emerge-position-region'. + "This is a variation on `emerge-position-region'. The difference is that it always tries to align difference regions in buffer-A and buffer-B, so that it will be easier to compare them." (set-window-start (selected-window) beg) @@ -2099,7 +2649,7 @@ ) -(defun ediff-next-difference (arg) +(defun ediff-next-difference (&optional arg) "Advance to the next difference. With a prefix argument, go back that many differences." (interactive "P") @@ -2110,7 +2660,7 @@ (ediff-unselect-and-select-difference n)) (error "At end of the difference list."))) -(defun ediff-previous-difference (arg) +(defun ediff-previous-difference (&optional arg) "Go to the previous difference. With a prefix argument, go back that many differences." (interactive "P") @@ -2133,31 +2683,35 @@ (defun ediff-jump-to-difference-at-point () "Go to the difference closest to the point in buffer A or B. If this command is invoked via `ja' or `ga' then the point in buffer A is -used. Otherwise, buffer B is used." +used. Otherwise, buffer B is used." (interactive) (let ((buffer-read-only nil) - (buf-type (if (eq last-command-char ?a) 'A 'B))) - + (buf-type (ediff-char-to-buftype last-command-char))) (ediff-jump-to-difference (ediff-diff-at-point buf-type)))) ;; find region "most related to the current point position (defun ediff-diff-at-point (buf-type) - (let ((buffer (if (eq buf-type 'A) ediff-A-buffer ediff-B-buffer)) + (let ((buffer (ediff-get-buffer buf-type)) (ctl-buffer ediff-control-buffer) (diff-no -1) (prev-beg 0) - (beg 0)) + (prev-end 0) + (beg 0) + (end 0)) (emerge-eval-in-buffer buffer (while (or (< (point) prev-beg) (> (point) beg)) (setq diff-no (1+ diff-no)) - (setq prev-beg beg) - (setq beg (ediff-get-diff-posn buf-type 'beg diff-no ctl-buffer))) + (setq prev-beg beg + prev-end end) + (setq beg (ediff-get-diff-posn buf-type 'beg diff-no ctl-buffer) + end (ediff-get-diff-posn buf-type 'end diff-no ctl-buffer)) + ) - (if (< (abs (- (point) prev-beg)) + (if (< (abs (- (point) prev-end)) (abs (- (point) beg))) diff-no (1+ diff-no)) ;; jump-to-diff works with diff nums higher by 1 @@ -2173,34 +2727,32 @@ (if arg (ediff-jump-to-difference arg)) (ediff-copy-diff ediff-current-difference - (if (eq last-command-char ?a) 'B 'A)) + (ediff-char-to-buftype (aref (this-command-keys) 0)) + (ediff-char-to-buftype (aref (this-command-keys) 1))) (ediff-recenter 'no-rehighlight)) -(defun ediff-copy-diff (n buf-type) - "Copy diff N from BUF-TYPE \(given as `A' or `B'\)." - (let* ((other-buf (if (eq buf-type 'A) - ediff-B-buffer ediff-A-buffer)) - (buf (if (eq buf-type 'A) - ediff-A-buffer ediff-B-buffer)) - (other-buf-type (if (eq buf-type 'A) 'B 'A)) +(defun ediff-copy-diff (n from-buf-type to-buf-type) + "Copy diff N from FROM-BUF-TYPE \(given as 'A or 'B\) to TO-BUF-TYPE." + (let* ((to-buf (ediff-get-buffer to-buf-type)) + (from-buf (ediff-get-buffer from-buf-type)) (ctrl-buf ediff-control-buffer) reg-to-copy reg-to-delete reg-to-delete-beg reg-to-delete-end) (ediff-operate-on-flags 'remove) (setq reg-to-delete-beg - (ediff-get-diff-posn other-buf-type 'beg n ctrl-buf)) + (ediff-get-diff-posn to-buf-type 'beg n ctrl-buf)) (setq reg-to-delete-end - (ediff-get-diff-posn other-buf-type 'end n ctrl-buf)) + (ediff-get-diff-posn to-buf-type 'end n ctrl-buf)) (setq reg-to-copy (emerge-eval-in-buffer - buf + from-buf (buffer-substring (ediff-get-diff-posn - buf-type 'beg n ctrl-buf) + from-buf-type 'beg n ctrl-buf) (ediff-get-diff-posn - buf-type 'end n ctrl-buf)))) + from-buf-type 'end n ctrl-buf)))) (setq reg-to-delete (emerge-eval-in-buffer - other-buf + to-buf (buffer-substring reg-to-delete-beg reg-to-delete-end))) (setq ediff-disturbed-overlays nil) ;; clear before use @@ -2209,15 +2761,15 @@ (progn (ding) (message - "Diff regions %d are identical in buffers A and B. Nothing copied." - (1+ n))) + "Diff regions %d are identical in buffers %S and %S. Nothing copied." + (1+ n) from-buf-type to-buf-type)) ;; seems ok to copy - (if (ediff-test-save-region n other-buf-type) + (if (ediff-test-save-region n to-buf-type) (condition-case conds (let (inhibit-read-only) (emerge-eval-in-buffer - other-buf + to-buf ;; to prevent flags from interfering if buffer is writable (setq inhibit-read-only (null buffer-read-only)) (let ((before-change-function nil)) @@ -2237,7 +2789,7 @@ (kill-region reg-to-delete-beg reg-to-delete-end) (ediff-move-disturbed-overlays reg-to-delete-beg))) )) - (ediff-save-diff-region n other-buf-type reg-to-delete)) + (ediff-save-diff-region n to-buf-type reg-to-delete)) (error (message "%s %s" (car conds) (mapconcat 'prin1-to-string (cdr conds) " ")) @@ -2249,7 +2801,7 @@ (defun ediff-save-diff-region (n buf-type reg) "Save Nth diff of buffer BUF-TYPE \(`A' or `B'\). That is to say, the Nth diff on the `ediff-killed-diffs-alist'. REG -is the region to save. It is redundant here,but is passed anyway, for +is the region to save. It is redundant here, but is passed anyway, for convenience." (let* ((n-th-diff-saved (assoc n ediff-killed-diffs-alist)) @@ -2264,8 +2816,9 @@ (setq ediff-killed-diffs-alist ;; create record for n-th diff (cons (list n (cons buf-type reg)) ediff-killed-diffs-alist)))) - (message "Saved diff region #%d for buffer %S. To recover hit '%s'." - (1+ n) buf-type (if (eq buf-type 'A) "ra" "rb")))) + (message "Saved diff region #%d for buffer %S. To recover hit 'r%s'." + (1+ n) buf-type + (downcase (symbol-name buf-type))))) (defun ediff-test-save-region (n buf-type) "Test if saving Nth difference region of buffer BUF-TYPE is possible." @@ -2275,8 +2828,8 @@ (if this-buf-n-th-diff-saved (if (yes-or-no-p (format - "You've previously copied diff %d from %S to %S. Confirm. " - (1+ n) (if (eq buf-type 'A) 'B 'A) buf-type)) + "You've previously copied diff region %d to buffer %S. Confirm." + (1+ n) buf-type)) t (error "Quit.")) t))) @@ -2285,12 +2838,14 @@ "Pop last killed Nth diff region from buffer BUF-TYPE." (let* ((n-th-record (assoc n ediff-killed-diffs-alist)) (saved-rec (assoc buf-type (cdr n-th-record))) - (buf (if (eq buf-type 'A) ediff-A-buffer ediff-B-buffer)) + (buf (ediff-get-buffer buf-type)) saved-diff reg-beg reg-end recovered) (if (cdr saved-rec) (setq saved-diff (cdr saved-rec)) - (error "Nothing saved for diff %d in buffer %S." (1+ n) buf-type)) + (if (> ediff-number-of-differences 0) + (error "Nothing saved for diff %d in buffer %S." (1+ n) buf-type) + (error "No differences found."))) (ediff-operate-on-flags 'remove) @@ -2329,7 +2884,7 @@ (if recovered (progn (setq n-th-record (delq saved-rec n-th-record)) - (message "Diff region %d restored for buffer %S." (1+ n) buf-type))) + (message "Restored diff region %d in buffer %S." (1+ n) buf-type))) )) (defun ediff-restore-diff (arg) @@ -2339,7 +2894,7 @@ (if arg (ediff-jump-to-difference arg)) (ediff-pop-diff ediff-current-difference - (if (eq last-command-char ?a) 'A 'B)) + (ediff-char-to-buftype last-command-char)) (ediff-recenter 'no-rehighlight)) @@ -2355,21 +2910,15 @@ (message "")) (ediff-really-quit))) + ;; Perform the quit operations. (defun ediff-really-quit () - (setq buffer-read-only nil) - (ediff-unselect-and-select-difference -1) - ;; null out the difference overlays so they won't slow down future editing - ;; operations - (mapcar (function (lambda (d) - (ediff-delete-overlay (aref d 0)) - (ediff-delete-overlay (aref d 1)))) - ediff-difference-vector) - ;; allow them to be garbage collected - (setq ediff-difference-vector nil) (setq ediff-help-message ediff-help-message-long) (ediff-restore-buffer-characteristics t) ;; restore as they were at setup (ediff-unhighlight-diffs-totally) + (ediff-clear-diff-vector ediff-difference-vector 'fine-diffs-also) + (if ediff-temp-file-A (delete-file ediff-temp-file-A)) + (if ediff-temp-file-B (delete-file ediff-temp-file-B)) ;; restore buffer mode line id's in buffer-A/B (let ((control-buffer ediff-control-buffer)) @@ -2406,7 +2955,8 @@ (let ((buff-A ediff-A-buffer) (buff-B ediff-B-buffer)) (ediff-kill-buffer-carefully ediff-diff-buffer) - (ediff-kill-buffer-carefully ediff-diff-error-buffer) + (ediff-kill-buffer-carefully ediff-tmp-buffer) + (ediff-kill-buffer-carefully ediff-error-buffer) (ediff-kill-buffer-carefully ediff-control-buffer) (ediff-kill-buffer-carefully ediff-patch-diagnostics) (delete-other-windows) @@ -2421,7 +2971,7 @@ (buf-B ediff-B-buffer) (buf-patch ediff-patch-buf) (buf-patch-diag ediff-patch-diagnostics) - (buf-err ediff-diff-error-buffer) + (buf-err ediff-error-buffer) (buf-diff ediff-diff-buffer)) (bury-buffer) ;; ediff-control-buffer (delete-other-windows) @@ -2439,9 +2989,10 @@ buffer and then type \\[ediff-recenter]. Ediff will automatically set up an appropriate window config." (interactive) + (let ((key (substitute-command-keys "\\[ediff-recenter]"))) (run-hooks 'ediff-suspend-hooks) (message - "To resume, switch to *ediff-control* and hit 'c' (ediff-recenter).")) + "To resume Ediff, switch to *ediff-control* and hit '%S'" key))) (defun ediff-file-names () @@ -2451,22 +3002,16 @@ (with-output-to-temp-buffer "*Help*" (emerge-eval-in-buffer ediff-A-buffer (if buffer-file-name - (progn - (princ "File A is: ") - (princ buffer-file-name)) - (progn - (princ "Buffer A is: ") - (princ (buffer-name)))) - (princ "\n")) + (princ + (format "File A is: %s\n" buffer-file-name)) + (princ + (format "Buffer A is: %s\n" (buffer-name))))) (emerge-eval-in-buffer ediff-B-buffer (if buffer-file-name - (progn - (princ "File B is: ") - (princ buffer-file-name)) - (progn - (princ "Buffer B is: ") - (princ (buffer-name)))) - (princ "\n")) + (princ + (format "File B is: %s\n" buffer-file-name)) + (princ + (format "Buffer B is: %s\n" (buffer-name))))) )) @@ -2500,6 +3045,21 @@ (ediff-place-flags-in-buffer 'B ediff-B-buffer ediff-control-buffer n)) + (if window-system + (cond ((eq ediff-auto-refine 'on) + (if (and + (> ediff-auto-refine-limit + (- (ediff-get-diff-posn 'A 'end n) + (ediff-get-diff-posn 'A 'beg n))) + (> ediff-auto-refine-limit + (- (ediff-get-diff-posn 'B 'end n) + (ediff-get-diff-posn 'B 'beg n)))) + (ediff-make-fine-diffs n 'noforce) + (ediff-make-fine-diffs n 'skip))) + + ((eq ediff-auto-refine 'off) ; highlight iff fine diffs + (ediff-make-fine-diffs n 'skip)))) ; already exist + (ediff-restore-buffer-characteristics) (run-hooks 'ediff-select-hooks)))) @@ -2526,6 +3086,12 @@ (ediff-restore-buffer-characteristics) (setq ediff-highlighting-style nil) + + ;; unhighlight fine diffs + (if window-system + (ediff-set-fine-diff-properties + ediff-current-difference 'default)) + (run-hooks 'ediff-unselect-hooks)))) @@ -2543,66 +3109,79 @@ ;; flags. (defun ediff-unselect-and-select-difference (n &optional flag no-recenter) - (let ((wind (selected-window)) - ;; save buf modified info + (let (;; save buf modified info + (control-buf ediff-control-buffer) (buf-A-modified (buffer-modified-p ediff-A-buffer)) (buf-B-modified (buffer-modified-p ediff-B-buffer)) ;; temporarily disable undo so highlighting won't confuse the user buf-A-undo buf-B-undo) + (let ((ediff-current-difference n)) + (or no-recenter + (ediff-recenter 'no-rehighlight))) + + (emerge-eval-in-buffer + ediff-A-buffer + (setq buf-A-undo buffer-undo-list)) + (emerge-eval-in-buffer + ediff-B-buffer + (setq buf-B-undo buffer-undo-list)) + + (buffer-disable-undo ediff-A-buffer) + (buffer-disable-undo ediff-B-buffer) + + (unwind-protect ;; we don't want to lose undo info due to error + (progn + (or (eq flag 'select-only) + (ediff-unselect-difference ediff-current-difference)) + + ;; Auto-save buffers while Ediff flags are temporarily removed. + (emerge-eval-in-buffer + ediff-A-buffer + (if buf-A-modified + (do-auto-save))) + (emerge-eval-in-buffer + ediff-B-buffer + (if buf-B-modified + (do-auto-save))) + + (or (eq flag 'unselect-only) + (ediff-select-difference n)) + (setq ediff-current-difference n) + ) ;; end protected section + + (emerge-eval-in-buffer + control-buf + (ediff-refresh-mode-line) + + ;; restore undo and buffer-modified info (emerge-eval-in-buffer ediff-A-buffer - (setq buf-A-undo buffer-undo-list)) + (set-buffer-modified-p buf-A-modified) + (setq buffer-undo-list buf-A-undo))) + + (emerge-eval-in-buffer + control-buf (emerge-eval-in-buffer ediff-B-buffer - (setq buf-B-undo buffer-undo-list)) - - (buffer-disable-undo ediff-A-buffer) - (buffer-disable-undo ediff-B-buffer) - - (unwind-protect ;; we don't want to lose undo info due to error - (progn - (or (eq flag 'select-only) - (ediff-unselect-difference ediff-current-difference)) - - ;; Auto-save buffers while Ediff flags are temporarily removed. - (emerge-eval-in-buffer - ediff-A-buffer - (if buf-A-modified - (do-auto-save))) - (emerge-eval-in-buffer - ediff-B-buffer - (if buf-B-modified - (do-auto-save))) - - (or (eq flag 'unselect-only) - (ediff-select-difference n)) - (setq ediff-current-difference n) - ) ;; end protected section - - (select-window wind) ;; must be before recenter! - (ediff-refresh-mode-line) - (or no-recenter - (ediff-recenter 'no-rehighlight)) - - ;; restore undo and buffer-modified info - (emerge-eval-in-buffer - ediff-A-buffer - (set-buffer-modified-p buf-A-modified) - (setq buffer-undo-list buf-A-undo)) - (emerge-eval-in-buffer - ediff-B-buffer - (set-buffer-modified-p buf-B-modified) - (setq buffer-undo-list buf-B-undo)) - ))) + (set-buffer-modified-p buf-B-modified) + (setq buffer-undo-list buf-B-undo)) + )))) ;; Revise the mode line to display which difference we have selected (defun ediff-refresh-mode-line () (setq mode-line-buffer-identification - (list (format "Ediff: %%b diff %d of %d" - (1+ ediff-current-difference) - ediff-number-of-differences))) + (cond ((< ediff-current-difference 0) + (list (format "Ediff: %%b At start: %d diffs" + ediff-number-of-differences))) + ((>= ediff-current-difference ediff-number-of-differences) + (list (format "Ediff: %%b At end: %d diffs" + ediff-number-of-differences))) + (t + (list (format "Ediff: %%b diff %d of %d" + (1+ ediff-current-difference) + ediff-number-of-differences))))) ;; Force mode-line redisplay (set-buffer-modified-p (buffer-modified-p))) @@ -2614,9 +3193,6 @@ (< ediff-current-difference ediff-number-of-differences))) (error "No difference selected"))) -;; The following is added to take care of Lemacs. - - (defun ediff-read-file-name (prompt default-dir default-file A-file) ; This is a modified version of a similar function in `emerge.el'. ; PROMPT should not have trailing ': ', so that it can be modified @@ -2629,41 +3205,75 @@ ; If default-file is set, it should be used as the default value. ; If default-dir is non-nil, use it as the default directory. ; Otherwise, use the value in Emacs's var default-directory. - (cond - ((and A-file default-dir) - (read-file-name (format "%s (default %s%s): " - prompt - (abbreviate-file-name - (expand-file-name default-dir)) - (file-name-nondirectory A-file)) - (expand-file-name default-dir) - (concat (expand-file-name default-dir) - (file-name-nondirectory A-file)) - 'confirm (file-name-nondirectory A-file))) - (A-file - (read-file-name (format "%s (default %s): " - prompt (file-name-nondirectory A-file)) - (expand-file-name (file-name-directory A-file)) - A-file - 'confirm (file-name-nondirectory A-file))) - ;; If there is a default file, but no A-file, use it. - (default-file - (read-file-name (format "%s (default %s): " prompt default-file) - default-dir ;; if nil then default-directory. - nil 'confirm)) - (t - (read-file-name (concat prompt ": ") - default-dir ;; if nil then default-directory. - nil 'confirm)))) + (let (f) + (setq f + (cond + ((and A-file default-dir) + (read-file-name (format "%s (default %s%s): " + prompt + (abbreviate-file-name + (expand-file-name default-dir)) + (file-name-nondirectory A-file)) + (expand-file-name default-dir) + (concat (expand-file-name default-dir) + (file-name-nondirectory A-file)) + 'confirm (file-name-nondirectory A-file))) + (A-file + (read-file-name (format "%s (default %s): " + prompt (file-name-nondirectory A-file)) + (expand-file-name (file-name-directory A-file)) + A-file + 'confirm (file-name-nondirectory A-file))) + ;; If there is a default file, but no A-file, use it. + (default-file + (read-file-name (format "%s (default %s): " prompt default-file) + default-dir;; if nil then default-directory. + nil 'confirm)) + (t + (read-file-name (concat prompt ": ") + default-dir;; if nil then default-directory. + nil 'confirm)))) + ;; If user enters a directory name, expand the default file in that + ;; directory. This allows the user to enter a directory name for the + ;; B-file and diff against the A-file in that directory instead of a DIRED + ;; listing! + (if (and (file-directory-p f) + (or A-file default-file)) + (setq f (expand-file-name + (file-name-nondirectory (or A-file default-file)) f))) + f)) -(defun ediff-make-temp-file (prefix) - (let ((f (make-temp-name (concat ediff-temp-file-prefix prefix)))) +;; If `prefix' is given, then it is used as a prefix for the temp file +;; name. Otherwise, `.buffer-name' is used. If `file' is given, use this +;; file and don't create a new one. +(defun ediff-make-temp-file (&optional prefix given-file) + (let ((f (or given-file + (make-temp-name (concat + ediff-temp-file-prefix + (or prefix + (format + ".%s" + (file-name-nondirectory + (buffer-name))))))))) ;; create the file - (write-region (point-min) (point-min) f nil 'no-message) + (write-region (point-min) (point-max) f nil 'no-message) (set-file-modes f ediff-temp-file-mode) f)) - + +;; Quote metacharacters (using \) when executing diff in Unix, but not in +;; EMX OS/2 +(defun ediff-protect-metachars (str) + (or (eq system-type 'emx) + (let ((limit 0)) + (while (string-match emerge-metachars str limit) + (setq str (concat (substring str 0 (match-beginning 0)) + "\\" + (substring str (match-beginning 0)))) + (setq limit (1+ (match-end 0)))))) + str) + + (defun ediff-block-write-file () "Prevent writing files A and B directly." (if (ediff-check-for-ascii-flags) @@ -2848,7 +3458,7 @@ "Returns positions of difference sectors in the BUF-TYPE buffer. BUF-TYPE should be a symbol--either `A' or `B'. POS is either `beg' or `end'--it specifies whether you want the position at the -beginning of a difference of at the end. +beginning of a difference or at the end. The optional argument N says which difference \(default: `ediff-current-difference'\). The optional argument CONTROL-BUF says @@ -2862,11 +3472,12 @@ control-buf (or n (setq n ediff-current-difference)) (if (or (< n 0) (>= n ediff-number-of-differences)) - (error "There is no diff %d in this session. Valid diffs are 1 to %d." - (1+ n) ediff-number-of-differences)) - (setq diff-overlay (aref (aref ediff-difference-vector n) - (if (eq buf-type 'A) 0 1)))) - + (if (> ediff-number-of-differences 0) + (error "There is no diff %d. Valid diffs are 1 to %d." + (1+ n) ediff-number-of-differences) + (error "No differences found."))) + (setq diff-overlay (ediff-get-diff-overlay n buf-type))) + (if (ediff-overlay-get diff-overlay 'detached) (ediff-move-overlay diff-overlay (ediff-overlay-get diff-overlay 'ediff-marker) @@ -2914,8 +3525,8 @@ (ediff-overlay-put ediff-current-diff-overlay-B 'priority (ediff-highest-priority begin-B end-B-hilit ediff-B-buffer)) - (if (and (not (face-differs-from-default-p 'ediff-odd-diff-face-A-var)) - (null ediff-highlight-selected-only)) + (or (face-differs-from-default-p 'ediff-odd-diff-face-A-var) + (not ediff-highlight-all-diffs) (progn (copy-face ediff-odd-diff-face-A 'ediff-odd-diff-face-A-var) (copy-face ediff-odd-diff-face-B 'ediff-odd-diff-face-B-var) @@ -2924,8 +3535,8 @@ ;; unhighlight the background overlay for the diff n so they won't ;; interfere with the current diff overlay - (ediff-overlay-put (aref (aref ediff-difference-vector n) 0) 'face nil) - (ediff-overlay-put (aref (aref ediff-difference-vector n) 1) 'face nil) + (ediff-overlay-put (ediff-get-diff-overlay n 'A) 'face nil) + (ediff-overlay-put (ediff-get-diff-overlay n 'B) 'face nil) (sit-for 0) ;; needs to synch for some reason )) @@ -2939,22 +3550,22 @@ ;; rehighlight the overlay in the background of the ;; current difference region - (ediff-overlay-put (aref (aref ediff-difference-vector - ediff-current-difference) - 0) + (ediff-overlay-put (ediff-get-diff-overlay ediff-current-difference 'A) 'face (if (ediff-odd-p ediff-current-difference) 'ediff-odd-diff-face-A-var 'ediff-even-diff-face-A-var)) - (ediff-overlay-put (aref (aref ediff-difference-vector - ediff-current-difference) - 1) + (ediff-overlay-put (ediff-get-diff-overlay ediff-current-difference 'B) 'face (if (ediff-odd-p ediff-current-difference) 'ediff-odd-diff-face-B-var 'ediff-even-diff-face-B-var)) ) +;; delete highlighting overlays, restore faces to their original form (defun ediff-unhighlight-diffs-totally () + (setq buffer-read-only nil) + (ediff-unselect-and-select-difference -1) + (if (and window-system ediff-want-faces) (let ((inhibit-quit t)) (if (face-differs-from-default-p 'ediff-odd-diff-face-A-var) @@ -2968,8 +3579,23 @@ (setq ediff-current-diff-overlay-A nil) (if (ediff-overlayp ediff-current-diff-overlay-B) (ediff-delete-overlay ediff-current-diff-overlay-B)) - (setq ediff-current-diff-overlay-B nil)))) - + (setq ediff-current-diff-overlay-B nil))) + ) + +(defun ediff-clear-diff-vector (vec &optional fin-diffs-also) + ;; null out the difference overlays so they won't slow down future + ;; editing operations + (mapcar (function + (lambda (elt) + (ediff-delete-overlay (ediff-get-diff-overlay-from-vector elt 'A)) + (ediff-delete-overlay (ediff-get-diff-overlay-from-vector elt 'B)) + (if fin-diffs-also + (ediff-clear-diff-vector + (ediff-get-fine-diff-vector-from-vec elt))) + )) + vec) + ;; allow them to be garbage collected + (setq vec nil)) (defun ediff-operate-on-flags (action) "Re/unhighlights buffers A and B with all flags from all Ediff sessions. @@ -2985,17 +3611,209 @@ (flag (if (eq action 'remove) 'unselect-only 'select-only))) (mapcar (function (lambda (buf) - (emerge-eval-in-buffer - buf - (or (if (eq action 'insert) + (if (ediff-buffer-live-p buf) + (emerge-eval-in-buffer + buf + (or (if (eq action 'insert) (memq ediff-highlighting-style '(ascii off)) - (not (eq ediff-highlighting-style 'ascii))) - (ediff-unselect-and-select-difference - ediff-current-difference - flag 'no-recenter)) - ))) + (not (eq ediff-highlighting-style 'ascii))) + (ediff-unselect-and-select-difference + ediff-current-difference + flag 'no-recenter)) + )))) sessions))) + + + +;;; Refinement of current diff +;; Split region along word boundaries. Each word will be on its own line. +;; Output to buffer out-buffer. +(defun ediff-wordify (beg end in-buffer out-buffer) + (let (sv-point string) + (save-excursion + (set-buffer in-buffer) + (setq string (buffer-substring beg end)) + + (set-buffer out-buffer) + (erase-buffer) + (insert string) + (goto-char (point-min)) + (skip-chars-forward ediff-whitespace) + (delete-region (point-min) (point)) + (while (or (> (skip-chars-forward ediff-word-1) 0) + (> (skip-chars-forward ediff-word-2) 0)) + + (setq sv-point (point)) + (skip-chars-forward ediff-whitespace) + (delete-region sv-point (point)) + (insert "\n"))))) + + +;; `n' is the diff region to work on. +;; if `flag' is 'noforce then make fine-diffs only if this region's fine +;; diffs have not been computed before. +;; if `flag' is 'skip then don't compute fine diffs for this region. +(defun ediff-make-fine-diffs (&optional n flag) + (interactive) + (if (not window-system) + (error "Non-window system.")) + (or n (setq n ediff-current-difference)) + + (if (< ediff-number-of-differences 1) + (error "No differences found.")) + + (let ((file-A ediff-temp-file-A) + (file-B ediff-temp-file-B)) + + (cond ((and (eq flag 'noforce) (ediff-get-fine-diff-vector n)) + nil) + ((eq flag 'skip) + (or (ediff-get-fine-diff-vector n) + (eq ediff-auto-refine 'off) + (message "Region %d is larger than auto-refine limit. Hit %S to force-refine." + (1+ n) + (substitute-command-keys "\\[ediff-make-fine-diffs]") + ))) + (t + ;; delete old fine diffs + (ediff-clear-diff-vector (ediff-get-fine-diff-vector n)) + ;; recompute fine diffs + (setq ediff-tmp-buffer (get-buffer-create "*ediff-tmp*")) + + (funcall ediff-wordify-function + (ediff-get-diff-posn 'A 'beg n) + (ediff-get-diff-posn 'A 'end n) + ediff-A-buffer + ediff-tmp-buffer) + (emerge-eval-in-buffer + ediff-tmp-buffer + (setq file-A (ediff-make-temp-file ".fine-diffs-A" file-A))) + + (funcall ediff-wordify-function + (ediff-get-diff-posn 'B 'beg n) + (ediff-get-diff-posn 'B 'end n) + ediff-B-buffer + ediff-tmp-buffer) + (emerge-eval-in-buffer + ediff-tmp-buffer + (setq file-B (ediff-make-temp-file ".fine-diffs-B" file-B))) + + ;; save temp file names. + (setq ediff-temp-file-A file-A + ediff-temp-file-B file-B) + + ;; set the new vector of fine diffs, if none exists + (ediff-set-fine-diff-vector + n + (ediff-setup-diff-regions file-A file-B 'use-old-diff-buf n + ediff-fine-diff-program + ediff-fine-diff-options + ediff-fine-diff-ok-lines-regexp)) + (if (eq (length (ediff-get-fine-diff-vector n)) 0) + (message "No differences found in region %d, except for white space and line breaks." + (1+ n)))) + ) ;; end cond + (ediff-set-fine-diff-properties n) + )) + + +(defun ediff-set-fine-diff-properties (n &optional default) + (let ((fine-diff-vector (ediff-get-fine-diff-vector n)) + (face-A (if default 'default (face-name ediff-fine-diff-face-A))) + (face-B (if default 'default (face-name ediff-fine-diff-face-B))) + (priority-A (if default + 0 + (1+ (ediff-overlay-get ediff-current-diff-overlay-A + 'priority)))) + (priority-B (if default + 0 + (1+ (ediff-overlay-get ediff-current-diff-overlay-B + 'priority))))) + (mapcar + (function (lambda (vec) + (ediff-overlay-put + (ediff-get-diff-overlay-from-vector vec 'A) + 'face face-A) + (ediff-overlay-put + (ediff-get-diff-overlay-from-vector vec 'A) + 'priority priority-A) + + (ediff-overlay-put + (ediff-get-diff-overlay-from-vector vec 'B) + 'face face-B) + (ediff-overlay-put + (ediff-get-diff-overlay-from-vector vec 'B) + 'priority priority-B) + )) + fine-diff-vector) + )) + +(defun ediff-convert-diffs-to-overlays-refine (A-buffer B-buffer + diff-list refine-region) + (let* ((current-diff -1) + (reg-A-start (ediff-get-diff-posn 'A 'beg refine-region)) + (reg-B-start (ediff-get-diff-posn 'B 'beg refine-region)) + diff-overlay-list list-element + a-begin a-end b-begin b-end + a-overlay b-overlay) + + (emerge-eval-in-buffer A-buffer (goto-char reg-A-start)) + (emerge-eval-in-buffer B-buffer (goto-char reg-B-start)) + + (while diff-list + (setq current-diff (1+ current-diff) + list-element (car diff-list) + a-begin (aref list-element 0) + a-end (aref list-element 1) + b-begin (aref list-element 2) + b-end (aref list-element 3)) + + ;; place overlays at the appropriate places in the buffers + (setq a-overlay (ediff-make-overlay + (ediff-goto-word (1+ a-begin) A-buffer) + (ediff-goto-word a-end A-buffer 'end) + A-buffer)) + + (setq b-overlay (ediff-make-overlay + (ediff-goto-word (1+ b-begin) B-buffer) + (ediff-goto-word b-end B-buffer 'end) + B-buffer)) + + ;; record all overlays for this difference + (setq diff-overlay-list (nconc diff-overlay-list + (list (vector a-overlay b-overlay))) + diff-list (cdr diff-list)) + ) ;; while + ;; convert the list of difference information into a vector for + ;; fast access + (apply 'vector diff-overlay-list))) + +;; goto word #n starting at current position in buffer `buf' +;; For ediff, a word is either a string of a-z,A-Z, incl `-' and `_'; +;; or a string of other non-blanks. A blank is a \n\t\j +;; If `flag' is non-nil, goto the end of the n-th word. +(defun ediff-goto-word (n buf &optional flag) + (emerge-eval-in-buffer + buf + (skip-chars-forward ediff-whitespace) + (while (> n 1) + (or (> (skip-chars-forward ediff-word-1) 0) + (> (skip-chars-forward ediff-word-2) 0)) + (skip-chars-forward ediff-whitespace) + (setq n (1- n))) + ;(if flag + (if (and flag (> n 0)) + (or (> (skip-chars-forward ediff-word-1) 0) + (> (skip-chars-forward ediff-word-2) 0))) + (point))) + + + + + +;;; Misc + (defun ediff-union (list1 list2) "Combine LIST1 and LIST2 using a set-union operation. The result list contains all items that appear in either LIST1 or LIST2. @@ -3014,37 +3832,38 @@ (setq list2 (cdr list2))) list1))) -(defun ediff-debug () - (interactive) - (with-output-to-temp-buffer "*ediff-debug*" - (princ - (format "Ctl buffer: %S\n\nediff-difference-vector:\n" - ediff-control-buffer)) - (mapcar (function - (lambda (overl-vec) - (princ (format "Diff %d: %S %S %S\n\t %S %S %S\n" - (1+ (ediff-overlay-get (aref overl-vec 0) - 'ediff-diff-num)) - (ediff-overlay-get (aref overl-vec 0) - 'ediff-control-buffer) - (ediff-overlay-get (aref overl-vec 0) - 'insert-in-front-hooks) - (aref overl-vec 0) - (ediff-overlay-get (aref overl-vec 1) - 'ediff-control-buffer) - (ediff-overlay-get (aref overl-vec 0) - 'insert-in-front-hooks) - (aref overl-vec 1) - )))) - ediff-difference-vector) - (princ "\nediff-disturbed-overlays:\n") - (mapcar (function - (lambda (overl) - (princ (format "%S %S\n" - (ediff-overlay-get overl 'ediff-control-buffer) - overl - )))) - ediff-disturbed-overlays))) + +;(defun ediff-debug () +; (interactive) +; (with-output-to-temp-buffer "*ediff-debug*" +; (princ +; (format "Ctl buffer: %S\n\nediff-difference-vector:\n" +; ediff-control-buffer)) +; (mapcar (function +; (lambda (overl-vec) +; (princ (format "Diff %d: %S %S %S\n\t %S %S %S\n" +; (1+ (ediff-overlay-get (aref overl-vec 0) +; 'ediff-diff-num)) +; (ediff-overlay-get (aref overl-vec 0) +; 'ediff-control-buffer) +; (ediff-overlay-get (aref overl-vec 0) +; 'insert-in-front-hooks) +; (aref overl-vec 0) +; (ediff-overlay-get (aref overl-vec 1) +; 'ediff-control-buffer) +; (ediff-overlay-get (aref overl-vec 0) +; 'insert-in-front-hooks) +; (aref overl-vec 1) +; )))) +; ediff-difference-vector) +; (princ "\nediff-disturbed-overlays:\n") +; (mapcar (function +; (lambda (overl) +; (princ (format "%S %S\n" +; (ediff-overlay-get overl 'ediff-control-buffer) +; overl +; )))) +; ediff-disturbed-overlays))) (run-hooks 'ediff-load-hooks)